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
|
@ -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)))))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue