dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

diff-hl-margin.el (5934B)


      1 ;;; diff-hl-margin.el --- Highlight buffer changes on margins -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2012-2017  Free Software Foundation, Inc.
      4 
      5 ;; This file is part of GNU Emacs.
      6 
      7 ;; GNU Emacs is free software: you can redistribute it and/or modify
      8 ;; it under the terms of the GNU General Public License as published by
      9 ;; the Free Software Foundation, either version 3 of the License, or
     10 ;; (at your option) any later version.
     11 
     12 ;; GNU Emacs is distributed in the hope that it will be useful,
     13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 ;; GNU General Public License for more details.
     16 
     17 ;; You should have received a copy of the GNU General Public License
     18 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     19 
     20 ;;; Commentary:
     21 
     22 ;; This is a global mode, it modifies `diff-hl-mode' to use the margin
     23 ;; instead of the fringe. To toggle, type `M-x diff-hl-margin-mode'.
     24 ;;
     25 ;; Compared to the default behavior, this makes `diff-hl-mode'
     26 ;; indicators show up even when Emacs is running in a terminal.
     27 ;;
     28 ;; On the flip side, the indicators look simpler, and they are
     29 ;; incompatible with `linum-mode' or any other mode that uses the
     30 ;; margin.
     31 ;;
     32 ;; You might want to enable it conditionally in your init file
     33 ;; depending on whether Emacs is running in graphical mode:
     34 ;;
     35 ;; (unless (window-system) (diff-hl-margin-mode))
     36 
     37 (require 'cl-lib)
     38 (require 'diff-hl)
     39 (require 'diff-hl-dired)
     40 
     41 (defvar diff-hl-margin-old-highlight-function nil)
     42 
     43 (defvar diff-hl-margin-old-width nil)
     44 
     45 (defgroup diff-hl-margin nil
     46   "Highlight buffer changes on margin"
     47   :group 'diff-hl)
     48 
     49 (defface diff-hl-margin-insert
     50   '((default :inherit diff-hl-insert))
     51   "Face used to highlight inserted lines on the margin.")
     52 
     53 (defface diff-hl-margin-delete
     54   '((default :inherit diff-hl-delete))
     55   "Face used to highlight deleted lines on the margin.")
     56 
     57 (defface diff-hl-margin-change
     58   '((default :inherit diff-hl-change))
     59   "Face used to highlight changed lines on the margin.")
     60 
     61 (defface diff-hl-margin-ignored
     62   '((default :inherit dired-ignored))
     63   "Face used to highlight changed lines on the margin.")
     64 
     65 (defface diff-hl-margin-unknown
     66   '((default :inherit dired-ignored))
     67   "Face used to highlight changed lines on the margin.")
     68 
     69 (defcustom diff-hl-margin-symbols-alist
     70   '((insert . "+") (delete . "-") (change . "!")
     71     (unknown . "?") (ignored . "i"))
     72   "Associative list from symbols to strings."
     73   :type '(alist :key-type symbol
     74                 :value-type string
     75                 :options (insert delete change unknown ignored))
     76   :set (lambda (symbol value)
     77          (defvar diff-hl-margin-spec-cache)
     78          (set-default symbol value)
     79          (setq diff-hl-margin-spec-cache nil)))
     80 
     81 ;;;###autoload
     82 (define-minor-mode diff-hl-margin-mode
     83   "Toggle displaying `diff-hl-mode' highlights on the margin."
     84   :lighter "" :global t
     85   (if diff-hl-margin-mode
     86       (progn
     87         (add-hook 'diff-hl-mode-on-hook 'diff-hl-margin-local-mode)
     88         (add-hook 'diff-hl-mode-off-hook 'diff-hl-margin-local-mode-off)
     89         (add-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-local-mode)
     90         (add-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-local-mode-off))
     91     (remove-hook 'diff-hl-mode-on-hook 'diff-hl-margin-local-mode)
     92     (remove-hook 'diff-hl-mode-off-hook 'diff-hl-margin-local-mode-off)
     93     (remove-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-local-mode)
     94     (remove-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-local-mode-off))
     95   (dolist (buf (buffer-list))
     96     (with-current-buffer buf
     97       (cond
     98        (diff-hl-mode
     99         (diff-hl-margin-local-mode (if diff-hl-margin-mode 1 -1))
    100         (diff-hl-update))
    101        (diff-hl-dired-mode
    102         (diff-hl-margin-local-mode (if diff-hl-margin-mode 1 -1))
    103         (diff-hl-dired-update))))))
    104 
    105 ;;;###autoload
    106 (define-minor-mode diff-hl-margin-local-mode
    107   "Toggle displaying `diff-hl-mode' highlights on the margin locally.
    108 You probably shouldn't use this function directly."
    109   :lighter ""
    110   (let ((width-var (intern (format "%s-margin-width" diff-hl-side))))
    111     (if diff-hl-margin-local-mode
    112         (progn
    113           (setq-local diff-hl-margin-old-highlight-function
    114                       diff-hl-highlight-function)
    115           (setq-local diff-hl-highlight-function
    116                       #'diff-hl-highlight-on-margin)
    117           (setq-local diff-hl-margin-old-width (symbol-value width-var))
    118           (set width-var 1))
    119       (when diff-hl-margin-old-highlight-function
    120         (setq diff-hl-highlight-function diff-hl-margin-old-highlight-function
    121               diff-hl-margin-old-highlight-function nil))
    122       (set width-var diff-hl-margin-old-width)
    123       (kill-local-variable 'diff-hl-margin-old-width)))
    124   (dolist (win (get-buffer-window-list))
    125     (set-window-buffer win (current-buffer))))
    126 
    127 (defun diff-hl-margin-local-mode-off ()
    128   (diff-hl-margin-local-mode -1))
    129 
    130 (defvar diff-hl-margin-spec-cache nil)
    131 
    132 (defun diff-hl-margin-spec-cache ()
    133   (or diff-hl-margin-spec-cache
    134       (setq diff-hl-margin-spec-cache
    135             (diff-hl-margin-build-spec-cache))))
    136 
    137 (defun diff-hl-margin-build-spec-cache ()
    138   (cl-loop for (type . char) in diff-hl-margin-symbols-alist
    139            nconc
    140            (cl-loop for side in '(left right)
    141                     collect
    142                     (cons
    143                      (cons type side)
    144                      (propertize
    145                       " " 'display
    146                       `((margin ,(intern (format "%s-margin" side)))
    147                         ,(propertize char 'face
    148                                      (intern (format "diff-hl-margin-%s" type)))))))))
    149 
    150 (defun diff-hl-highlight-on-margin (ovl type _shape)
    151   (let ((spec (cdr (assoc (cons type diff-hl-side)
    152                           (diff-hl-margin-spec-cache)))))
    153     (overlay-put ovl 'before-string spec)))
    154 
    155 (provide 'diff-hl-margin)
    156 
    157 ;;; diff-hl-margin.el ends here