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