doomemacs/modules/tools/magit/autoload.el
Henrik Lissner b405225b90
refactor!(vc-gutter): drop git-gutter for diff-hl
BREAKING CHANGE: This removes git-gutter as an implementation for the
`:ui vc-gutter` module, leaving only the diff-hl implementation. There
are no longer any +git-gutter or +diff-hl flags for this module. Users
don't have to do anything to keep the vc gutter, unless they prefer
git-gutter for any reason (in which case they'll need to install and set
it up themselves).

This has been planned for some time, because of a roadmap goal for Doom
to lean into native/built-in functionality where it's equal or better
than the third party alternatives. diff-hl relies on the built-in vc.el
library instead of talking to git directly (thus expanding support to
whatever VCS's vc.el supports, and not git alone), which also means it
can take advantage of its caching and other user configuration for
vc.el. Overall, it is faster and lighter.

What I've also been waiting for was a stage-hunk command, similar to
git-gutter:stage-hunk, which arrived in dgutov/diff-hl@a0560551cd and
dgutov/diff-hl@133538973b, and have evolved since.

Ref: dgutov/diff-hl@a0560551cd
Ref: dgutov/diff-hl@133538973b
Ref: https://github.com/orgs/doomemacs/projects/5/views/1?pane=issue&itemId=58747789
2024-06-22 18:14:04 -04:00

161 lines
6 KiB
EmacsLisp

;;; tools/magit/autoload.el -*- lexical-binding: t; -*-
;; HACK Magit complains loudly (but harmlessly) when it can't determine its own
;; version in a sparse clone. Since I'd rather not compromise on shallow
;; clones, I've gimped `magit-version' so it doesn't complain (unless
;; called interactively).
;;;###autoload
(defadvice! +magit--ignore-version-a (fn &rest args)
:around #'magit-version
(let ((inhibit-message (not (called-interactively-p 'any))))
(apply fn args)))
;;;###autoload
(defun +magit-display-buffer-fn (buffer)
"Same as `magit-display-buffer-traditional', except...
- If opened from a commit window, it will open below it.
- Magit process windows are always opened in small windows below the current.
- Everything else will reuse the same window."
(let ((buffer-mode (buffer-local-value 'major-mode buffer)))
(display-buffer
buffer (cond
((and (eq buffer-mode 'magit-status-mode)
(get-buffer-window buffer))
'(display-buffer-reuse-window))
;; Any magit buffers opened from a commit window should open below
;; it. Also open magit process windows below.
((or (bound-and-true-p git-commit-mode)
(eq buffer-mode 'magit-process-mode))
(let ((size (if (eq buffer-mode 'magit-process-mode)
0.35
0.7)))
`(display-buffer-below-selected
. ((window-height . ,(truncate (* (window-height) size)))))))
;; Everything else should reuse the current window.
((or (not (derived-mode-p 'magit-mode))
(not (memq (with-current-buffer buffer major-mode)
'(magit-process-mode
magit-revision-mode
magit-diff-mode
magit-stash-mode
magit-status-mode))))
'(display-buffer-same-window))
('(+magit--display-buffer-in-direction))))))
(defun +magit--display-buffer-in-direction (buffer alist)
"`display-buffer-alist' handler that opens BUFFER in a direction.
This differs from `display-buffer-in-direction' in one way: it will try to use a
window that already exists in that direction. It will split otherwise."
(let ((direction (or (alist-get 'direction alist)
+magit-open-windows-in-direction))
(origin-window (selected-window)))
(if-let (window (window-in-direction direction))
(unless magit-display-buffer-noselect
(select-window window))
(if-let (window (and (not (one-window-p))
(window-in-direction
(pcase direction
(`right 'left)
(`left 'right)
((or `up `above) 'down)
((or `down `below) 'up)))))
(unless magit-display-buffer-noselect
(select-window window))
(let ((window (split-window nil nil direction)))
(when (and (not magit-display-buffer-noselect)
(memq direction '(right down below)))
(select-window window))
(display-buffer-record-window 'reuse window buffer)
(set-window-buffer window buffer)
(set-window-parameter window 'quit-restore (list 'window 'window origin-window buffer))
(set-window-prev-buffers window nil))))
(unless magit-display-buffer-noselect
(switch-to-buffer buffer t t)
(selected-window))))
;;
;;; Auto-revert
(defvar +magit--stale-p nil)
(defun +magit--revert-buffer (buffer)
(with-current-buffer buffer
(kill-local-variable '+magit--stale-p)
(when (and buffer-file-name (file-exists-p buffer-file-name))
(if (buffer-modified-p (current-buffer))
(when (bound-and-true-p vc-mode)
(vc-refresh-state)
(force-mode-line-update))
(revert-buffer t t t)))))
;;;###autoload
(defun +magit-mark-stale-buffers-h ()
"Revert all visible buffers and mark buried buffers as stale.
Stale buffers are reverted when they are switched to, assuming they haven't been
modified."
(dolist (buffer (buffer-list))
(when (buffer-live-p buffer)
(if (get-buffer-window buffer)
(+magit--revert-buffer buffer)
(with-current-buffer buffer
(setq-local +magit--stale-p t))))))
;;;###autoload
(defun +magit-revert-buffer-maybe-h ()
"Update `vc' and `diff-hl' if out of date."
(when +magit--stale-p
(+magit--revert-buffer (current-buffer))))
;;
;;; Commands
;;;###autoload
(defun +magit/quit (&optional kill-buffer)
"Bury the current magit buffer.
If KILL-BUFFER, kill this buffer instead of burying it.
If the buried/killed magit buffer was the last magit buffer open for this repo,
kill all magit buffers for this repo."
(interactive "P")
(let ((topdir (magit-toplevel)))
(funcall magit-bury-buffer-function kill-buffer)
(or (cl-find-if (lambda (win)
(with-selected-window win
(and (derived-mode-p 'magit-mode)
(equal magit--default-directory topdir))))
(window-list))
(+magit/quit-all))))
;;;###autoload
(defun +magit/quit-all ()
"Kill all magit buffers for the current repository."
(interactive)
(mapc #'+magit--kill-buffer (magit-mode-get-buffers))
(+magit-mark-stale-buffers-h))
(defun +magit--kill-buffer (buf)
"TODO"
(when (and (bufferp buf) (buffer-live-p buf))
(let ((process (get-buffer-process buf)))
(if (not (processp process))
(kill-buffer buf)
(with-current-buffer buf
(if (process-live-p process)
(run-with-timer 5 nil #'+magit--kill-buffer buf)
(kill-process process)
(kill-buffer buf)))))))
;;;###autoload
(defun +magit/start-code-review (arg)
(interactive "P")
(call-interactively
(if (or arg (not (featurep 'forge)))
#'code-review-start
#'code-review-forge-pr-at-point)))