;;; diff-hl-margin.el --- Highlight buffer changes on margins -*- lexical-binding: t -*- ;; Copyright (C) 2012-2017 Free Software Foundation, Inc. ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; This is a global mode, it modifies `diff-hl-mode' to use the margin ;; instead of the fringe. To toggle, type `M-x diff-hl-margin-mode'. ;; ;; Compared to the default behavior, this makes `diff-hl-mode' ;; indicators show up even when Emacs is running in a terminal. ;; ;; On the flip side, the indicators look simpler, and they are ;; incompatible with `linum-mode' or any other mode that uses the ;; margin. ;; ;; You might want to enable it conditionally in your init file ;; depending on whether Emacs is running in graphical mode: ;; ;; (unless (window-system) (diff-hl-margin-mode)) (require 'cl-lib) (require 'diff-hl) (require 'diff-hl-dired) (defvar diff-hl-margin-old-highlight-function nil) (defgroup diff-hl-margin nil "Highlight buffer changes on margin" :group 'diff-hl) (defface diff-hl-margin-insert '((default :inherit diff-hl-insert)) "Face used to highlight inserted lines on the margin.") (defface diff-hl-margin-delete '((default :inherit diff-hl-delete)) "Face used to highlight deleted lines on the margin.") (defface diff-hl-margin-change '((default :inherit diff-hl-change)) "Face used to highlight changed lines on the margin.") (defface diff-hl-margin-ignored '((default :inherit dired-ignored)) "Face used to highlight changed lines on the margin.") (defface diff-hl-margin-unknown '((default :inherit dired-ignored)) "Face used to highlight changed lines on the margin.") (defcustom diff-hl-margin-symbols-alist '((insert . "+") (delete . "-") (change . "!") (unknown . "?") (ignored . "i")) "Associative list from symbols to strings." :type '(alist :key-type symbol :value-type string :options (insert delete change unknown ignored)) :set (lambda (symbol value) (defvar diff-hl-margin-spec-cache) (set-default symbol value) (setq diff-hl-margin-spec-cache nil))) ;;;###autoload (define-minor-mode diff-hl-margin-mode "Toggle displaying `diff-hl-mode' highlights on the margin." :lighter "" :global t (if diff-hl-margin-mode (progn (add-hook 'diff-hl-mode-on-hook 'diff-hl-margin-minor-mode) (add-hook 'diff-hl-mode-off-hook 'diff-hl-margin-minor-mode-off) (add-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-minor-mode) (add-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-minor-mode-off)) (remove-hook 'diff-hl-mode-on-hook 'diff-hl-margin-minor-mode) (remove-hook 'diff-hl-mode-off-hook 'diff-hl-margin-minor-mode-off) (remove-hook 'diff-hl-dired-mode-on-hook 'diff-hl-margin-minor-mode) (remove-hook 'diff-hl-dired-mode-off-hook 'diff-hl-margin-minor-mode-off)) (dolist (buf (buffer-list)) (with-current-buffer buf (cond (diff-hl-mode (diff-hl-margin-minor-mode (if diff-hl-margin-mode 1 -1)) (diff-hl-update)) (diff-hl-dired-mode (diff-hl-margin-minor-mode (if diff-hl-margin-mode 1 -1)) (diff-hl-dired-update)))))) (define-minor-mode diff-hl-margin-minor-mode "Toggle displaying `diff-hl-mode' highlights on the margin locally. You probably shouldn't use this function directly." :lighter "" (let ((width-var (intern (format "%s-margin-width" diff-hl-side)))) (if diff-hl-margin-minor-mode (progn (set (make-local-variable 'diff-hl-margin-old-highlight-function) diff-hl-highlight-function) (set (make-local-variable 'diff-hl-highlight-function) 'diff-hl-highlight-on-margin) (set width-var 1)) (when diff-hl-margin-old-highlight-function (setq diff-hl-highlight-function diff-hl-margin-old-highlight-function diff-hl-margin-old-highlight-function nil)) (set width-var 0))) (dolist (win (get-buffer-window-list)) (set-window-buffer win (current-buffer)))) (define-obsolete-variable-alias 'diff-hl-margin-side 'diff-hl-side "1.7.1") (defun diff-hl-margin-minor-mode-off () (diff-hl-margin-minor-mode -1)) (defvar diff-hl-margin-spec-cache nil) (defun diff-hl-margin-spec-cache () (or diff-hl-margin-spec-cache (setq diff-hl-margin-spec-cache (diff-hl-margin-build-spec-cache)))) (defun diff-hl-margin-build-spec-cache () (cl-loop for (type . char) in diff-hl-margin-symbols-alist nconc (cl-loop for side in '(left right) collect (cons (cons type side) (propertize " " 'display `((margin ,(intern (format "%s-margin" side))) ,(propertize char 'face (intern (format "diff-hl-margin-%s" type))))))))) (defun diff-hl-highlight-on-margin (ovl type _shape) (let ((spec (cdr (assoc (cons type diff-hl-side) (diff-hl-margin-spec-cache))))) (overlay-put ovl 'before-string spec))) (provide 'diff-hl-margin) ;;; diff-hl-margin.el ends here