feat(vc-gutter): add +diff-hl backend
This adds an alternative backend to the :ui vc-gutter module, enabled with the +diff-hl flag. In the future, I intend for diff-hl to replace git-gutter, as it is slightly faster and depends on more native functionality (vc.el), but it's still a little buggy. It will remain opt-in until those issues are sorted out.
This commit is contained in:
parent
cd9bc5a1fd
commit
27a448b04b
10 changed files with 137 additions and 89 deletions
|
@ -349,11 +349,11 @@
|
||||||
:desc "Kill link to remote" "y" #'+vc/browse-at-remote-kill
|
:desc "Kill link to remote" "y" #'+vc/browse-at-remote-kill
|
||||||
:desc "Kill link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
|
:desc "Kill link to homepage" "Y" #'+vc/browse-at-remote-kill-homepage
|
||||||
(:when (featurep! :ui vc-gutter)
|
(:when (featurep! :ui vc-gutter)
|
||||||
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
|
:desc "Git revert hunk" "r" #'+vc-gutter/revert-hunk
|
||||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
:desc "Git stage hunk" "s" #'+vc-gutter/stage-hunk
|
||||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||||
:desc "Jump to next hunk" "n" #'git-gutter:next-hunk
|
:desc "Jump to next hunk" "n" #'+vc-gutter/next-hunk
|
||||||
:desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
|
:desc "Jump to previous hunk" "p" #'+vc-gutter/previous-hunk)
|
||||||
(:when (featurep! :tools magit)
|
(:when (featurep! :tools magit)
|
||||||
:desc "Magit dispatch" "/" #'magit-dispatch
|
:desc "Magit dispatch" "/" #'magit-dispatch
|
||||||
:desc "Magit file dispatch" "." #'magit-file-dispatch
|
:desc "Magit file dispatch" "." #'magit-file-dispatch
|
||||||
|
|
|
@ -452,11 +452,11 @@
|
||||||
(:when (featurep! :ui vc-gutter)
|
(:when (featurep! :ui vc-gutter)
|
||||||
(:when (featurep! :ui hydra)
|
(:when (featurep! :ui hydra)
|
||||||
:desc "VCGutter" "." #'+vc/gutter-hydra/body)
|
:desc "VCGutter" "." #'+vc/gutter-hydra/body)
|
||||||
:desc "Revert hunk" "r" #'git-gutter:revert-hunk
|
:desc "Revert hunk at point" "r" #'+vc-gutter/revert-hunk
|
||||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
:desc "stage hunk at point" "s" #'+vc-gutter/stage-hunk
|
||||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||||
:desc "Jump to next hunk" "]" #'git-gutter:next-hunk
|
:desc "Jump to next hunk" "]" #'+vc-gutter/next-hunk
|
||||||
:desc "Jump to previous hunk" "[" #'git-gutter:previous-hunk)
|
:desc "Jump to previous hunk" "[" #'+vc-gutter/previous-hunk)
|
||||||
(:when (featurep! :tools magit)
|
(:when (featurep! :tools magit)
|
||||||
:desc "Magit dispatch" "/" #'magit-dispatch
|
:desc "Magit dispatch" "/" #'magit-dispatch
|
||||||
:desc "Magit file dispatch" "." #'magit-file-dispatch
|
:desc "Magit file dispatch" "." #'magit-file-dispatch
|
||||||
|
|
|
@ -445,8 +445,8 @@ directives. By default, this only recognizes C directives.")
|
||||||
:m "]x" #'+web:encode-html-entities
|
:m "]x" #'+web:encode-html-entities
|
||||||
:m "[x" #'+web:decode-html-entities)
|
:m "[x" #'+web:decode-html-entities)
|
||||||
(:when (featurep! :ui vc-gutter)
|
(:when (featurep! :ui vc-gutter)
|
||||||
:m "]d" #'git-gutter:next-hunk
|
:m "]d" #'+vc-gutter/next-hunk
|
||||||
:m "[d" #'git-gutter:previous-hunk)
|
:m "[d" #'+vc-gutter/previous-hunk)
|
||||||
(:when (featurep! :ui hl-todo)
|
(:when (featurep! :ui hl-todo)
|
||||||
:m "]t" #'hl-todo-next
|
:m "]t" #'hl-todo-next
|
||||||
:m "[t" #'hl-todo-previous)
|
:m "[t" #'hl-todo-previous)
|
||||||
|
|
|
@ -72,11 +72,12 @@ Fixes #3939: unsortable dired entries on Windows."
|
||||||
|
|
||||||
|
|
||||||
(use-package! diff-hl
|
(use-package! diff-hl
|
||||||
:hook (dired-mode . diff-hl-dired-mode-unless-remote)
|
:when (featurep! :ui vc-gutter)
|
||||||
:hook (magit-post-refresh . diff-hl-magit-post-refresh)
|
:hook (dired-mode-hook . diff-hl-margin-local-mode)
|
||||||
:config
|
:init
|
||||||
;; use margin instead of fringe
|
(unless (featurep! :ui vc-gutter +diff-hl)
|
||||||
(diff-hl-margin-mode))
|
(add-hook 'dired-mode-hook #'diff-hl-dired-mode-unless-remote)
|
||||||
|
(add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh)))
|
||||||
|
|
||||||
|
|
||||||
(use-package! ranger
|
(use-package! ranger
|
||||||
|
|
|
@ -13,6 +13,10 @@ Supports Git, Svn, Hg, and Bzr.
|
||||||
[[doom-contrib-maintainer:][Become a maintainer?]]
|
[[doom-contrib-maintainer:][Become a maintainer?]]
|
||||||
|
|
||||||
** Module flags
|
** Module flags
|
||||||
|
- +diff-hl ::
|
||||||
|
Use [[doom-package:][diff-hl]] instead of git-gutter to power the VC gutter. It is a little
|
||||||
|
faster, but is slightly more prone to visual glitching. [[doom-package:][diff-hl]] is intended to
|
||||||
|
replace git-gutter at some point in the future.
|
||||||
- +pretty ::
|
- +pretty ::
|
||||||
Apply some stylistic defaults to the fringe, enabling thin bars in the fringe.
|
Apply some stylistic defaults to the fringe, enabling thin bars in the fringe.
|
||||||
This look takes after the modern look of git-gutter in VSCode and Sublime
|
This look takes after the modern look of git-gutter in VSCode and Sublime
|
||||||
|
@ -22,7 +26,8 @@ Supports Git, Svn, Hg, and Bzr.
|
||||||
diff-hl's faces (like modus-themes does).
|
diff-hl's faces (like modus-themes does).
|
||||||
|
|
||||||
** Packages
|
** Packages
|
||||||
- [[doom-package:][git-gutter-fringe]]
|
- [[doom-package:][git-gutter-fringe]] unless [[doom-module:][+diff-hl]]
|
||||||
|
- [[doom-package:][diff-hl]] if [[doom-module:][+diff-hl]]
|
||||||
|
|
||||||
** TODO Hacks
|
** TODO Hacks
|
||||||
#+begin_quote
|
#+begin_quote
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
;;; ui/vc-gutter/autoload.el -*- lexical-binding: t; -*-
|
|
||||||
;;;###if (featurep! :ui hydra)
|
|
||||||
|
|
||||||
;;;###autoload (autoload '+vc/gutter-hydra/body "ui/vc-gutter/autoload" nil t)
|
|
||||||
(defhydra +vc/gutter-hydra
|
|
||||||
(:body-pre (git-gutter-mode 1) :hint nil)
|
|
||||||
"
|
|
||||||
[git gutter]
|
|
||||||
Movement Hunk Actions Misc. +%-4s(car (git-gutter:statistic))/ -%-4s(cdr (git-gutter:statistic))
|
|
||||||
╭──────────────────────────────────┴────────────────╯
|
|
||||||
^_g_^ [_s_] stage [_R_] set start Rev
|
|
||||||
^_k_^ [_r_] revert
|
|
||||||
^↑ ^ [_m_] mark
|
|
||||||
^↓ ^ [_p_] popup ╭─────────────────────
|
|
||||||
^_j_^ │[_q_] quit
|
|
||||||
^_G_^ │[_Q_] Quit and disable"
|
|
||||||
("j" (progn (git-gutter:next-hunk 1) (recenter)))
|
|
||||||
("k" (progn (git-gutter:previous-hunk 1) (recenter)))
|
|
||||||
("g" (progn (goto-char (point-min)) (git-gutter:next-hunk 1)))
|
|
||||||
("G" (progn (goto-char (point-min)) (git-gutter:previous-hunk 1)))
|
|
||||||
("s" git-gutter:stage-hunk)
|
|
||||||
("r" git-gutter:revert-hunk)
|
|
||||||
("m" git-gutter:mark-hunk)
|
|
||||||
("p" git-gutter:popup-hunk)
|
|
||||||
("R" git-gutter:set-start-revision)
|
|
||||||
("q"
|
|
||||||
(when (get-buffer git-gutter:popup-buffer)
|
|
||||||
(kill-buffer (get-buffer git-gutter:popup-buffer)))
|
|
||||||
:color blue)
|
|
||||||
("Q"
|
|
||||||
(progn (git-gutter-mode -1)
|
|
||||||
(when (get-buffer git-gutter:popup-buffer)
|
|
||||||
(kill-buffer (get-buffer git-gutter:popup-buffer))))
|
|
||||||
:color blue))
|
|
11
modules/ui/vc-gutter/autoload/diff-hl.el
Normal file
11
modules/ui/vc-gutter/autoload/diff-hl.el
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
;;; ui/vc-gutter/autoload/diff-hl.el -*- lexical-binding: t; -*-
|
||||||
|
;;;###if (featurep! +diff-hl)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/stage-hunk #'diff-hl-stage-current-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/revert-hunk #'diff-hl-revert-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/next-hunk #'diff-hl-next-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/previous-hunk #'diff-hl-previous-hunk)
|
11
modules/ui/vc-gutter/autoload/git-gutter.el
Normal file
11
modules/ui/vc-gutter/autoload/git-gutter.el
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
;;; ui/vc-gutter/autoload/vc-gutter.el -*- lexical-binding: t; -*-
|
||||||
|
;;;###if (not (featurep! +diff-hl))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/stage-hunk #'git-gutter:stage-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/revert-hunk #'git-gutter:revert-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/next-hunk #'git-gutter:next-hunk)
|
||||||
|
;;;###autoload
|
||||||
|
(defalias '+vc-gutter/previous-hunk #'git-gutter:previous-hunk)
|
|
@ -1,20 +1,12 @@
|
||||||
;;; ui/vc-gutter/config.el -*- lexical-binding: t; -*-
|
;;; ui/vc-gutter/config.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; TODO Implement me
|
||||||
(defvar +vc-gutter-in-margin nil
|
(defvar +vc-gutter-in-margin nil
|
||||||
"If non-nil, use the margin for diffs instead of the fringe.")
|
"If non-nil, use the margin for diffs instead of the fringe.")
|
||||||
|
|
||||||
(defvar +vc-gutter-in-remote-files nil
|
(defvar +vc-gutter-in-remote-files nil
|
||||||
"If non-nil, enable the vc gutter in remote files (e.g. open through TRAMP).")
|
"If non-nil, enable the vc gutter in remote files (e.g. open through TRAMP).")
|
||||||
|
|
||||||
(defvar +vc-gutter-diff-unsaved-buffer nil
|
|
||||||
"If non-nil, `diff-hl-flydiff-mode' will be activated. This allows on-the-fly
|
|
||||||
diffing, even for unsaved buffers.")
|
|
||||||
|
|
||||||
(defvar +vc-gutter-default-style t
|
|
||||||
"If non-nil, enable the default look of the vc gutter.
|
|
||||||
This means subtle thin bitmaps on the left, an arrow bitmap for flycheck, and
|
|
||||||
flycheck indicators moved to the right fringe.")
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Default styles
|
;;; Default styles
|
||||||
|
@ -31,6 +23,7 @@ flycheck indicators moved to the right fringe.")
|
||||||
;; to shrink the fringe and sacrifice precious space for other fringe
|
;; to shrink the fringe and sacrifice precious space for other fringe
|
||||||
;; indicators (like flycheck or flyspell).
|
;; indicators (like flycheck or flyspell).
|
||||||
;; TODO Extract these into a package with faces that themes can target.
|
;; TODO Extract these into a package with faces that themes can target.
|
||||||
|
(if (not (featurep! +diff-hl))
|
||||||
(after! git-gutter-fringe
|
(after! git-gutter-fringe
|
||||||
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
||||||
nil nil '(center repeated))
|
nil nil '(center repeated))
|
||||||
|
@ -38,6 +31,21 @@ flycheck indicators moved to the right fringe.")
|
||||||
nil nil '(center repeated))
|
nil nil '(center repeated))
|
||||||
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
||||||
nil nil 'bottom))
|
nil nil 'bottom))
|
||||||
|
(defadvice! +vc-gutter-define-thin-bitmaps-a (&rest args)
|
||||||
|
:override #'diff-hl-define-bitmaps
|
||||||
|
(set-face-background 'diff-hl-insert nil)
|
||||||
|
(set-face-background 'diff-hl-delete nil)
|
||||||
|
(set-face-background 'diff-hl-change nil)
|
||||||
|
(define-fringe-bitmap 'diff-hl-bmp-middle [224] nil nil '(center repeated))
|
||||||
|
(define-fringe-bitmap 'diff-hl-bmp-delete [240 224 192 128] nil nil 'top))
|
||||||
|
(defun +vc-gutter-type-face-fn (type _pos)
|
||||||
|
(intern (format "diff-hl-%s" type)))
|
||||||
|
(defun +vc-gutter-type-at-pos-fn (type _pos)
|
||||||
|
(if (eq type 'delete)
|
||||||
|
'diff-hl-bmp-delete
|
||||||
|
'diff-hl-bmp-middle))
|
||||||
|
(setq diff-hl-fringe-bmp-function #'+vc-gutter-type-at-pos-fn
|
||||||
|
diff-hl-draw-borders nil))
|
||||||
|
|
||||||
;; FIX: To minimize overlap between flycheck indicators and git-gutter/diff-hl
|
;; FIX: To minimize overlap between flycheck indicators and git-gutter/diff-hl
|
||||||
;; indicators in the left fringe.
|
;; indicators in the left fringe.
|
||||||
|
@ -50,9 +58,10 @@ flycheck indicators moved to the right fringe.")
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;;; Packages
|
;;; git-gutter
|
||||||
|
|
||||||
(use-package! git-gutter
|
(use-package! git-gutter
|
||||||
|
:unless (featurep! +diff-hl)
|
||||||
:commands git-gutter:revert-hunk git-gutter:stage-hunk
|
:commands git-gutter:revert-hunk git-gutter:stage-hunk
|
||||||
:init
|
:init
|
||||||
(add-hook! 'find-file-hook
|
(add-hook! 'find-file-hook
|
||||||
|
@ -129,26 +138,69 @@ is deferred until the file is saved. Respects `git-gutter:disabled-modes'."
|
||||||
:from-end is-reverse)))
|
:from-end is-reverse)))
|
||||||
|
|
||||||
|
|
||||||
;; subtle diff indicators in the fringe
|
;;
|
||||||
(after! git-gutter-fringe
|
;;; diff-hl
|
||||||
(when +vc-gutter-default-style
|
|
||||||
;; standardize default fringe width
|
|
||||||
(if (fboundp 'fringe-mode) (fringe-mode '4))
|
|
||||||
|
|
||||||
;; places the git gutter outside the margins.
|
(use-package! diff-hl
|
||||||
(setq-default fringes-outside-margins t)
|
:when (featurep! +diff-hl)
|
||||||
;; thin fringe bitmaps
|
:hook (doom-first-file . global-diff-hl-mode)
|
||||||
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
:hook (diff-hl-mode . diff-hl-flydiff-mode)
|
||||||
nil nil '(center repeated))
|
:config
|
||||||
(define-fringe-bitmap 'git-gutter-fr:modified [224]
|
(set-popup-rule! "^\\*diff-hl" :select nil :size '+popup-shrink-to-fit)
|
||||||
nil nil '(center repeated))
|
|
||||||
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
|
||||||
nil nil 'bottom)))
|
|
||||||
|
|
||||||
(after! flycheck
|
;; PERF: reduce load on remote
|
||||||
(when +vc-gutter-default-style
|
(defvaralias 'diff-hl-disable-on-remote '+vc-gutter-in-remote-files)
|
||||||
;; let diff have left fringe, flycheck can have right fringe
|
;; PERF: A slightly faster algorithm for diffing.
|
||||||
(setq flycheck-indication-mode 'right-fringe)
|
(setq vc-git-diff-switches '("--histogram"))
|
||||||
;; A non-descript, left-pointing arrow
|
;; PERF: Slightly more conservative delay before updating the diff
|
||||||
(define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
|
(setq diff-hl-flydiff-delay 0.5) ; default: 0.3
|
||||||
[16 48 112 240 112 48 16] nil nil 'center)))
|
|
||||||
|
;; UX: get realtime feedback in diffs after staging/unstaging hunks.
|
||||||
|
(setq diff-hl-show-staged-changes nil)
|
||||||
|
|
||||||
|
;; UX: Update diffs when it makes sense too, without being too slow
|
||||||
|
(when (featurep! :editor evil)
|
||||||
|
(map! :after diff-hl-show-hunk
|
||||||
|
:map diff-hl-show-hunk-map
|
||||||
|
:n "p" #'diff-hl-show-hunk-previous
|
||||||
|
:n "n" #'diff-hl-show-hunk-next
|
||||||
|
:n "c" #'diff-hl-show-hunk-copy-original-text
|
||||||
|
:n "r" #'diff-hl-show-hunk-revert-hunk
|
||||||
|
:n "[" #'diff-hl-show-hunk-previous
|
||||||
|
:n "]" #'diff-hl-show-hunk-next
|
||||||
|
:n "{" #'diff-hl-show-hunk-previous
|
||||||
|
:n "}" #'diff-hl-show-hunk-next
|
||||||
|
:n "S" #'diff-hl-show-hunk-stage-hunk))
|
||||||
|
;; UX: Refresh git-gutter on ESC or refocusing the Emacs frame.
|
||||||
|
(add-hook! '(doom-escape-hook doom-switch-window-hook) :append
|
||||||
|
(defun +vc-gutter-update-h (&rest _)
|
||||||
|
"Return nil to prevent shadowing other `doom-escape-hook' hooks."
|
||||||
|
(ignore (or inhibit-redisplay
|
||||||
|
(and (or (bound-and-true-p diff-hl-mode)
|
||||||
|
(bound-and-true-p diff-hl-dir-mode))
|
||||||
|
(diff-hl-update-once))))))
|
||||||
|
;; UX: Update diff-hl when magit alters git state.
|
||||||
|
(when (featurep! :tools magit)
|
||||||
|
(add-hook 'magit-pre-refresh-hook #'diff-hl-magit-pre-refresh)
|
||||||
|
(add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh)
|
||||||
|
(add-hook 'magit-post-stage-hook #'+vc-gutter-update-h)
|
||||||
|
(add-hook 'magit-post-unstage-hook #'+vc-gutter-update-h))
|
||||||
|
|
||||||
|
;; UX: Don't delete the current hunk's indicators while we're editing
|
||||||
|
(add-hook! 'diff-hl-flydiff-mode-hook
|
||||||
|
(defun +vc-gutter-init-flydiff-mode-h ()
|
||||||
|
(if diff-hl-flydiff-mode
|
||||||
|
(progn
|
||||||
|
(advice-remove #'diff-hl-overlay-modified #'ignore)
|
||||||
|
(when (featurep! :editor evil)
|
||||||
|
(add-hook 'evil-insert-state-exit-hook #'diff-hl-flydiff-update)))
|
||||||
|
(remove-hook 'evil-insert-state-exit-hook #'diff-hl-flydiff-update))))
|
||||||
|
|
||||||
|
;; FIX: Reverting a hunk causes the cursor to be moved to an unexpected place,
|
||||||
|
;; often far from the target hunk.
|
||||||
|
(defadvice! +vc-gutter--save-excursion-a (fn &rest args)
|
||||||
|
"Suppresses unexpected cursor movement by `diff-hl-revert-hunk'."
|
||||||
|
:around #'diff-hl-revert-hunk
|
||||||
|
(let ((pt (point)))
|
||||||
|
(prog1 (apply fn args)
|
||||||
|
(goto-char pt)))))
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
;; -*- no-byte-compile: t; -*-
|
;; -*- no-byte-compile: t; -*-
|
||||||
;;; ui/vc-gutter/packages.el
|
;;; ui/vc-gutter/packages.el
|
||||||
|
|
||||||
(package! git-gutter-fringe :pin "648cb5b57faec55711803cdc9434e55a733c3eba")
|
(if (featurep! +diff-hl)
|
||||||
|
(package! diff-hl :pin "dabb7be6283488abd8d232ea8ce590d502713ed8")
|
||||||
|
(package! git-gutter-fringe :pin "648cb5b57faec55711803cdc9434e55a733c3eba"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue