/ diff-hl-flydiff.el
diff-hl-flydiff.el
 1  ;; Copyright (C) 2015-2025 Free Software Foundation, Inc. -*- lexical-binding: t -*-
 2  
 3  ;; Author:   Jonathan Hayase <PythonNut@gmail.com>
 4  ;; URL:      https://github.com/dgutov/diff-hl
 5  
 6  ;; This file is part of GNU Emacs.
 7  
 8  ;; GNU Emacs is free software: you can redistribute it and/or modify
 9  ;; it under the terms of the GNU General Public License as published by
10  ;; the Free Software Foundation, either version 3 of the License, or
11  ;; (at your option) any later version.
12  
13  ;; GNU Emacs is distributed in the hope that it will be useful,
14  ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ;; GNU General Public License for more details.
17  
18  ;; You should have received a copy of the GNU General Public License
19  ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
20  
21  ;;; Commentary:
22  
23  ;; This mode enables diffing on-the-fly (i.e. without saving the buffer first)
24  ;; Toggle in all buffers with M-x diff-hl-flydiff-mode
25  
26  ;;; Code:
27  
28  (require 'diff-hl)
29  (require 'diff)
30  
31  (defgroup diff-hl-flydiff nil
32    "Highlight changes on the fly"
33    :group 'diff-hl)
34  
35  (defcustom diff-hl-flydiff-delay 0.3
36    "The idle delay in seconds before highlighting is updated."
37    :type 'number)
38  
39  (defvar diff-hl-flydiff-modified-tick nil)
40  (defvar diff-hl-flydiff-timer nil)
41  (make-variable-buffer-local 'diff-hl-flydiff-modified-tick)
42  
43  (defun diff-hl-flydiff-changes-buffer (file backend &optional new-rev buffer)
44    (setq buffer (or buffer " *diff-hl-diff*"))
45    (setq diff-hl-flydiff-modified-tick (buffer-chars-modified-tick))
46    (if new-rev
47        (diff-hl-with-diff-switches
48         (diff-hl-diff-against-reference file backend buffer new-rev))
49      (diff-hl-diff-buffer-with-reference file buffer backend)))
50  
51  (defun diff-hl-flydiff-update ()
52    (unless (or
53             (not diff-hl-mode)
54             (eq diff-hl-flydiff-modified-tick (buffer-chars-modified-tick))
55             (not buffer-file-name)
56             (file-remote-p default-directory)
57             (not (file-exists-p buffer-file-name)))
58      (diff-hl-update)))
59  
60  (defun diff-hl-flydiff/modified-p (_state)
61    (buffer-modified-p))
62  
63  ;;;###autoload
64  (define-minor-mode diff-hl-flydiff-mode
65    "Perform highlighting on-the-fly.
66  This is a global minor mode.  It alters how `diff-hl-mode' works."
67    :lighter "" :global t
68    (and diff-hl-flydiff-timer
69         (cancel-timer diff-hl-flydiff-timer))
70  
71    (if diff-hl-flydiff-mode
72        (progn
73          (advice-add 'diff-hl-overlay-modified :override #'ignore)
74  
75          (advice-add 'diff-hl-modified-p :before-until
76                      #'diff-hl-flydiff/modified-p)
77          (advice-add 'diff-hl-changes-buffer :override
78                      #'diff-hl-flydiff-changes-buffer)
79          (setq diff-hl-flydiff-timer
80                (run-with-idle-timer diff-hl-flydiff-delay t #'diff-hl-flydiff-update)))
81  
82      (advice-remove 'diff-hl-overlay-modified #'ignore)
83  
84      (advice-remove 'diff-hl-modified-p #'diff-hl-flydiff/modified-p)
85      (advice-remove 'diff-hl-changes-buffer #'diff-hl-flydiff-changes-buffer)))
86  
87  (provide 'diff-hl-flydiff)