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 homepage" "Y" #'+vc/browse-at-remote-kill-homepage
|
||||
(:when (featurep! :ui vc-gutter)
|
||||
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
|
||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
||||
:desc "Git revert hunk" "r" #'+vc-gutter/revert-hunk
|
||||
:desc "Git stage hunk" "s" #'+vc-gutter/stage-hunk
|
||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||
:desc "Jump to next hunk" "n" #'git-gutter:next-hunk
|
||||
:desc "Jump to previous hunk" "p" #'git-gutter:previous-hunk)
|
||||
:desc "Jump to next hunk" "n" #'+vc-gutter/next-hunk
|
||||
:desc "Jump to previous hunk" "p" #'+vc-gutter/previous-hunk)
|
||||
(:when (featurep! :tools magit)
|
||||
:desc "Magit dispatch" "/" #'magit-dispatch
|
||||
:desc "Magit file dispatch" "." #'magit-file-dispatch
|
||||
|
|
|
@ -452,11 +452,11 @@
|
|||
(:when (featurep! :ui vc-gutter)
|
||||
(:when (featurep! :ui hydra)
|
||||
:desc "VCGutter" "." #'+vc/gutter-hydra/body)
|
||||
:desc "Revert hunk" "r" #'git-gutter:revert-hunk
|
||||
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
|
||||
:desc "Revert hunk at point" "r" #'+vc-gutter/revert-hunk
|
||||
:desc "stage hunk at point" "s" #'+vc-gutter/stage-hunk
|
||||
:desc "Git time machine" "t" #'git-timemachine-toggle
|
||||
:desc "Jump to next hunk" "]" #'git-gutter:next-hunk
|
||||
:desc "Jump to previous hunk" "[" #'git-gutter:previous-hunk)
|
||||
:desc "Jump to next hunk" "]" #'+vc-gutter/next-hunk
|
||||
:desc "Jump to previous hunk" "[" #'+vc-gutter/previous-hunk)
|
||||
(:when (featurep! :tools magit)
|
||||
:desc "Magit dispatch" "/" #'magit-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:decode-html-entities)
|
||||
(:when (featurep! :ui vc-gutter)
|
||||
:m "]d" #'git-gutter:next-hunk
|
||||
:m "[d" #'git-gutter:previous-hunk)
|
||||
:m "]d" #'+vc-gutter/next-hunk
|
||||
:m "[d" #'+vc-gutter/previous-hunk)
|
||||
(:when (featurep! :ui hl-todo)
|
||||
:m "]t" #'hl-todo-next
|
||||
:m "[t" #'hl-todo-previous)
|
||||
|
|
|
@ -72,11 +72,12 @@ Fixes #3939: unsortable dired entries on Windows."
|
|||
|
||||
|
||||
(use-package! diff-hl
|
||||
:hook (dired-mode . diff-hl-dired-mode-unless-remote)
|
||||
:hook (magit-post-refresh . diff-hl-magit-post-refresh)
|
||||
:config
|
||||
;; use margin instead of fringe
|
||||
(diff-hl-margin-mode))
|
||||
:when (featurep! :ui vc-gutter)
|
||||
:hook (dired-mode-hook . diff-hl-margin-local-mode)
|
||||
:init
|
||||
(unless (featurep! :ui vc-gutter +diff-hl)
|
||||
(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
|
||||
|
|
|
@ -13,6 +13,10 @@ Supports Git, Svn, Hg, and Bzr.
|
|||
[[doom-contrib-maintainer:][Become a maintainer?]]
|
||||
|
||||
** 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 ::
|
||||
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
|
||||
|
@ -22,7 +26,8 @@ Supports Git, Svn, Hg, and Bzr.
|
|||
diff-hl's faces (like modus-themes does).
|
||||
|
||||
** 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
|
||||
#+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; -*-
|
||||
|
||||
;; TODO Implement me
|
||||
(defvar +vc-gutter-in-margin nil
|
||||
"If non-nil, use the margin for diffs instead of the fringe.")
|
||||
|
||||
(defvar +vc-gutter-in-remote-files nil
|
||||
"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
|
||||
|
@ -31,13 +23,29 @@ flycheck indicators moved to the right fringe.")
|
|||
;; to shrink the fringe and sacrifice precious space for other fringe
|
||||
;; indicators (like flycheck or flyspell).
|
||||
;; TODO Extract these into a package with faces that themes can target.
|
||||
(after! git-gutter-fringe
|
||||
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:modified [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
||||
nil nil 'bottom))
|
||||
(if (not (featurep! +diff-hl))
|
||||
(after! git-gutter-fringe
|
||||
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:modified [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
||||
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
|
||||
;; indicators in the left fringe.
|
||||
|
@ -50,9 +58,10 @@ flycheck indicators moved to the right fringe.")
|
|||
|
||||
|
||||
;;
|
||||
;;; Packages
|
||||
;;; git-gutter
|
||||
|
||||
(use-package! git-gutter
|
||||
:unless (featurep! +diff-hl)
|
||||
:commands git-gutter:revert-hunk git-gutter:stage-hunk
|
||||
:init
|
||||
(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)))
|
||||
|
||||
|
||||
;; subtle diff indicators in the fringe
|
||||
(after! git-gutter-fringe
|
||||
(when +vc-gutter-default-style
|
||||
;; standardize default fringe width
|
||||
(if (fboundp 'fringe-mode) (fringe-mode '4))
|
||||
;;
|
||||
;;; diff-hl
|
||||
|
||||
;; places the git gutter outside the margins.
|
||||
(setq-default fringes-outside-margins t)
|
||||
;; thin fringe bitmaps
|
||||
(define-fringe-bitmap 'git-gutter-fr:added [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:modified [224]
|
||||
nil nil '(center repeated))
|
||||
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
|
||||
nil nil 'bottom)))
|
||||
(use-package! diff-hl
|
||||
:when (featurep! +diff-hl)
|
||||
:hook (doom-first-file . global-diff-hl-mode)
|
||||
:hook (diff-hl-mode . diff-hl-flydiff-mode)
|
||||
:config
|
||||
(set-popup-rule! "^\\*diff-hl" :select nil :size '+popup-shrink-to-fit)
|
||||
|
||||
(after! flycheck
|
||||
(when +vc-gutter-default-style
|
||||
;; let diff have left fringe, flycheck can have right fringe
|
||||
(setq flycheck-indication-mode 'right-fringe)
|
||||
;; A non-descript, left-pointing arrow
|
||||
(define-fringe-bitmap 'flycheck-fringe-bitmap-double-arrow
|
||||
[16 48 112 240 112 48 16] nil nil 'center)))
|
||||
;; PERF: reduce load on remote
|
||||
(defvaralias 'diff-hl-disable-on-remote '+vc-gutter-in-remote-files)
|
||||
;; PERF: A slightly faster algorithm for diffing.
|
||||
(setq vc-git-diff-switches '("--histogram"))
|
||||
;; PERF: Slightly more conservative delay before updating the diff
|
||||
(setq diff-hl-flydiff-delay 0.5) ; default: 0.3
|
||||
|
||||
;; 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; -*-
|
||||
;;; 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