mirror of
https://gitlab.com/dwt1/dotfiles.git
synced 2026-04-22 11:00:27 +10:00
Moving to Doom Emacs!
This commit is contained in:
137
.emacs.d/modules/tools/magit/autoload.el
Normal file
137
.emacs.d/modules/tools/magit/autoload.el
Normal file
@@ -0,0 +1,137 @@
|
||||
;;; tools/magit/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; HACK Magit complains loudly when it can't determine its own version, which is
|
||||
;; the case when magit is built through straight. The warning is harmless,
|
||||
;; however, so we just need it to shut up.
|
||||
;;;###autoload
|
||||
(advice-add #'magit-version :override #'ignore)
|
||||
|
||||
;;;###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))))))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
||||
(defun +magit--refresh-vc-in-buffer (buffer)
|
||||
(with-current-buffer buffer
|
||||
(when (and vc-mode (fboundp 'vc-refresh-state))
|
||||
(vc-refresh-state))
|
||||
(when (and (bound-and-true-p git-gutter-mode)
|
||||
(fboundp '+version-control|update-git-gutter))
|
||||
(+version-control|update-git-gutter))
|
||||
(setq +magit--vc-is-stale-p nil)))
|
||||
|
||||
;;;###autoload
|
||||
(defvar-local +magit--vc-is-stale-p nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun +magit-refresh-vc-state-maybe-h ()
|
||||
"Update `vc' and `git-gutter' if out of date."
|
||||
(when +magit--vc-is-stale-p
|
||||
(+magit--refresh-vc-in-buffer (current-buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(add-hook 'doom-switch-buffer-hook #'+magit-refresh-vc-state-maybe-h)
|
||||
|
||||
;;;###autoload
|
||||
(defun +magit/quit (&optional kill-buffer)
|
||||
"Clean up magit buffers after quitting `magit-status' and refresh version
|
||||
control in buffers."
|
||||
(interactive "P")
|
||||
(funcall magit-bury-buffer-function kill-buffer)
|
||||
(unless (delq nil
|
||||
(mapcar (lambda (win)
|
||||
(with-selected-window win
|
||||
(eq major-mode 'magit-status-mode)))
|
||||
(window-list)))
|
||||
(mapc #'+magit--kill-buffer (magit-mode-get-buffers))
|
||||
(dolist (buffer (buffer-list))
|
||||
(when (buffer-live-p buffer)
|
||||
(if (get-buffer-window buffer)
|
||||
(+magit--refresh-vc-in-buffer buffer)
|
||||
(with-current-buffer buffer
|
||||
(setq +magit--vc-is-stale-p t)))))))
|
||||
|
||||
(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-github-review (arg)
|
||||
(interactive "P")
|
||||
(call-interactively
|
||||
(if (or arg (not (featurep 'forge)))
|
||||
#'github-review-start
|
||||
#'github-review-forge-pr-at-point)))
|
||||
|
||||
(defvar +magit-clone-history nil
|
||||
"History for `+magit/clone' prompt.")
|
||||
;;;###autoload
|
||||
(defun +magit/clone (url-or-repo dir)
|
||||
"Like `magit-clone', but supports additional formats on top of absolute URLs:
|
||||
|
||||
+ USER/REPO: assumes {`+magit-default-clone-url'}/USER/REPO
|
||||
+ REPO: assumes {`+magit-default-clone-url'}/{USER}/REPO, where {USER} is
|
||||
ascertained from your global gitconfig."
|
||||
(interactive
|
||||
(progn
|
||||
(require 'ghub)
|
||||
(let* ((user (ghub--username (ghub--host)))
|
||||
(repo (read-from-minibuffer
|
||||
"Clone repository (user/repo or url): "
|
||||
(if user (concat user "/"))
|
||||
nil nil '+magit-clone-history))
|
||||
(name (car (last (split-string repo "/" t)))))
|
||||
(list repo
|
||||
(read-directory-name
|
||||
"Destination: "
|
||||
magit-clone-default-directory
|
||||
name nil name)))))
|
||||
(magit-clone-regular
|
||||
(cond ((string-match-p "^[^/]+$" url-or-repo)
|
||||
(require 'ghub)
|
||||
(format +magit-default-clone-url (ghub--username (ghub--host)) url-or-repo))
|
||||
((string-match-p "^\\([^/]+\\)/\\([^/]+\\)/?$" url-or-repo)
|
||||
(apply #'format +magit-default-clone-url (split-string url-or-repo "/" t)))
|
||||
(url-or-repo))
|
||||
dir
|
||||
nil))
|
||||
167
.emacs.d/modules/tools/magit/config.el
Normal file
167
.emacs.d/modules/tools/magit/config.el
Normal file
@@ -0,0 +1,167 @@
|
||||
;;; tools/magit/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;
|
||||
;;; Packages
|
||||
|
||||
(use-package! magit
|
||||
:commands magit-file-delete
|
||||
:defer-incrementally (dash f s with-editor git-commit package eieio lv transient)
|
||||
:init
|
||||
(setq magit-auto-revert-mode nil) ; we do this ourselves
|
||||
;; Must be set early to prevent ~/.emacs.d/transient from being created
|
||||
(setq transient-levels-file (concat doom-etc-dir "transient/levels")
|
||||
transient-values-file (concat doom-etc-dir "transient/values")
|
||||
transient-history-file (concat doom-etc-dir "transient/history"))
|
||||
:config
|
||||
(setq transient-default-level 5
|
||||
magit-revision-show-gravatars '("^Author: " . "^Commit: ")
|
||||
magit-diff-refine-hunk t ; show granular diffs in selected hunk
|
||||
;; Don't autosave repo buffers. This is too magical, and saving can
|
||||
;; trigger a bunch of unwanted side-effects, like save hooks and
|
||||
;; formatters. Trust us to know what we're doing.
|
||||
magit-save-repository-buffers nil)
|
||||
|
||||
(defadvice! +magit-invalidate-projectile-cache-a (&rest _args)
|
||||
;; We ignore the args to `magit-checkout'.
|
||||
:after '(magit-checkout magit-branch-and-checkout)
|
||||
(projectile-invalidate-cache nil))
|
||||
|
||||
;; The default location for git-credential-cache is in
|
||||
;; ~/.cache/git/credential. However, if ~/.git-credential-cache/ exists, then
|
||||
;; it is used instead. Magit seems to be hardcoded to use the latter, so here
|
||||
;; we override it to have more correct behavior.
|
||||
(unless (file-exists-p "~/.git-credential-cache/")
|
||||
(setq magit-credential-cache-daemon-socket
|
||||
(doom-glob (or (getenv "XDG_CACHE_HOME")
|
||||
"~/.cache/")
|
||||
"git/credential/socket")))
|
||||
|
||||
;; Magit uses `magit-display-buffer-traditional' to display windows, by
|
||||
;; default, which is a little primitive. `+magit-display-buffer' marries
|
||||
;; `magit-display-buffer-fullcolumn-most-v1' with
|
||||
;; `magit-display-buffer-same-window-except-diff-v1', except:
|
||||
;;
|
||||
;; 1. Magit sub-buffers (like `magit-log') that aren't spawned from a status
|
||||
;; screen are opened as popups.
|
||||
;; 2. The status screen isn't buried when viewing diffs or logs from the
|
||||
;; status screen.
|
||||
(setq transient-display-buffer-action '(display-buffer-below-selected)
|
||||
magit-display-buffer-function #'+magit-display-buffer-fn)
|
||||
(set-popup-rule! "^\\(?:\\*magit\\|magit:\\| \\*transient\\*\\)" :ignore t)
|
||||
(add-hook 'magit-popup-mode-hook #'hide-mode-line-mode)
|
||||
|
||||
;; Add --tags switch
|
||||
(transient-append-suffix 'magit-fetch "-p"
|
||||
'("-t" "Fetch all tags" ("-t" "--tags")))
|
||||
(transient-append-suffix 'magit-pull "-r"
|
||||
'("-a" "Autostash" "--autostash"))
|
||||
|
||||
;; so magit buffers can be switched to (except for process buffers)
|
||||
(add-hook! 'doom-real-buffer-functions
|
||||
(defun +magit-buffer-p (buf)
|
||||
(with-current-buffer buf
|
||||
(and (derived-mode-p 'magit-mode)
|
||||
(not (eq major-mode 'magit-process-mode))))))
|
||||
|
||||
;; properly kill leftover magit buffers on quit
|
||||
(define-key magit-status-mode-map [remap magit-mode-bury-buffer] #'+magit/quit)
|
||||
|
||||
;; Close transient with ESC
|
||||
(define-key transient-map [escape] #'transient-quit-one))
|
||||
|
||||
|
||||
(use-package! forge
|
||||
;; We defer loading even further because forge's dependencies will try to
|
||||
;; compile emacsql, which is a slow and blocking operation.
|
||||
:after-call magit-status
|
||||
:init
|
||||
(setq forge-database-file (concat doom-etc-dir "forge/forge-database.sqlite"))
|
||||
:config
|
||||
;; All forge list modes are derived from `forge-topic-list-mode'
|
||||
(map! :map forge-topic-list-mode-map :n "q" #'kill-current-buffer)
|
||||
(set-popup-rule! "^\\*?[0-9]+:\\(?:new-\\|[0-9]+$\\)" :size 0.45 :modeline t :ttl 0 :quit nil)
|
||||
(set-popup-rule! "^\\*\\(?:[^/]+/[^ ]+ #[0-9]+\\*$\\|Issues\\|Pull-Requests\\|forge\\)" :ignore t)
|
||||
|
||||
(defadvice! +magit--forge-get-repository-lazily-a (&rest _)
|
||||
"Make `forge-get-repository' return nil if the binary isn't built yet.
|
||||
This prevents emacsql getting compiled, which appears to come out of the blue
|
||||
and blocks Emacs for a short while."
|
||||
:before-while #'forge-get-repository
|
||||
(file-executable-p emacsql-sqlite-executable))
|
||||
|
||||
(defadvice! +magit--forge-build-binary-lazily-a (&rest _)
|
||||
"Make `forge-dispatch' only build emacsql if necessary.
|
||||
Annoyingly, the binary gets built as soon as Forge is loaded. Since we've
|
||||
disabled that in `+magit--forge-get-repository-lazily-a', we must manually
|
||||
ensure it is built when we actually use Forge."
|
||||
:before #'forge-dispatch
|
||||
(unless (file-executable-p emacsql-sqlite-executable)
|
||||
(emacsql-sqlite-compile 2)
|
||||
(if (not (file-executable-p emacsql-sqlite-executable))
|
||||
(message (concat "Failed to build emacsql; forge may not work correctly.\n"
|
||||
"See *Compile-Log* buffer for details"))
|
||||
;; HACK Due to changes upstream, forge doesn't initialize completely if
|
||||
;; it doesn't find `emacsql-sqlite-executable', so we have to do it
|
||||
;; manually after installing it.
|
||||
(setq forge--sqlite-available-p t)
|
||||
(magit-add-section-hook 'magit-status-sections-hook 'forge-insert-pullreqs nil t)
|
||||
(magit-add-section-hook 'magit-status-sections-hook 'forge-insert-issues nil t)
|
||||
(after! forge-topic
|
||||
(dolist (hook forge-bug-reference-hooks)
|
||||
(add-hook hook #'forge-bug-reference-setup)))))))
|
||||
|
||||
|
||||
(use-package! github-review
|
||||
:after magit
|
||||
:config
|
||||
(transient-append-suffix 'magit-merge "i"
|
||||
'("y" "Review pull request" +magit/start-github-review))
|
||||
(after! forge
|
||||
(transient-append-suffix 'forge-dispatch "c u"
|
||||
'("c r" "Review pull request" +magit/start-github-review))))
|
||||
|
||||
|
||||
(use-package! magit-todos
|
||||
:after magit
|
||||
:config
|
||||
(setq magit-todos-keyword-suffix "\\(?:([^)]+)\\)?:?") ; make colon optional
|
||||
(define-key magit-todos-section-map "j" nil)
|
||||
;; Warns that jT isn't bound. Well, yeah, you don't need to tell me, that was
|
||||
;; on purpose ya goose.
|
||||
(advice-add #'magit-todos-mode :around #'doom-shut-up-a))
|
||||
|
||||
|
||||
(use-package! magit-gitflow
|
||||
:hook (magit-mode . turn-on-magit-gitflow))
|
||||
|
||||
|
||||
(use-package! evil-magit
|
||||
:when (featurep! :editor evil +everywhere)
|
||||
:after magit
|
||||
:init
|
||||
(setq evil-magit-state 'normal
|
||||
evil-magit-use-z-for-folds t)
|
||||
:config
|
||||
(unmap! magit-mode-map
|
||||
;; Replaced by z1, z2, z3, etc
|
||||
"M-1" "M-2" "M-3" "M-4"
|
||||
"1" "2" "3" "4"
|
||||
"0") ; moved to g=
|
||||
(evil-define-key* 'normal magit-status-mode-map [escape] nil) ; q is enough
|
||||
(evil-define-key* '(normal visual) magit-mode-map
|
||||
"%" #'magit-gitflow-popup
|
||||
"zz" #'evil-scroll-line-to-center
|
||||
"g=" #'magit-diff-default-context)
|
||||
(define-key! 'normal
|
||||
(magit-status-mode-map
|
||||
magit-stash-mode-map
|
||||
magit-revision-mode-map
|
||||
magit-diff-mode-map)
|
||||
[tab] #'magit-section-toggle)
|
||||
(after! git-rebase
|
||||
(dolist (key '(("M-k" . "gk") ("M-j" . "gj")))
|
||||
(when-let (desc (assoc (car key) evil-magit-rebase-commands-w-descriptions))
|
||||
(setcar desc (cdr key))))
|
||||
(evil-define-key* evil-magit-state git-rebase-mode-map
|
||||
"gj" #'git-rebase-move-line-down
|
||||
"gk" #'git-rebase-move-line-up)))
|
||||
10
.emacs.d/modules/tools/magit/packages.el
Normal file
10
.emacs.d/modules/tools/magit/packages.el
Normal file
@@ -0,0 +1,10 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; tools/magit/packages.el
|
||||
|
||||
(when (package! magit)
|
||||
(package! forge)
|
||||
(package! magit-gitflow)
|
||||
(package! magit-todos)
|
||||
(package! github-review)
|
||||
(when (featurep! :editor evil +everywhere)
|
||||
(package! evil-magit)))
|
||||
Reference in New Issue
Block a user