diff options
-rw-r--r-- | .emacs.d/lisp/init-git.el | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/.emacs.d/lisp/init-git.el b/.emacs.d/lisp/init-git.el index 43e88c7..bfcfc22 100644 --- a/.emacs.d/lisp/init-git.el +++ b/.emacs.d/lisp/init-git.el @@ -113,13 +113,109 @@ (magit-shell-command-topdir command))) (message "Not a git repository"))) + ;; difftastic code copied from https://tsdh.org/posts/2022-08-01-difftastic-diffing-with-magit.html + (defun my/magit--with-difftastic (buffer command) + "Run COMMAND with GIT_EXTERNAL_DIFF=difft then show result in BUFFER." + (let ((process-environment + (cons (concat "GIT_EXTERNAL_DIFF=difft --width=" + (number-to-string (frame-width))) + process-environment))) + ;; Clear the result buffer (we might regenerate a diff, e.g., for + ;; the current changes in our working directory). + (with-current-buffer buffer + (setq buffer-read-only nil) + (erase-buffer)) + ;; Now spawn a process calling the git COMMAND. + (make-process + :name (buffer-name buffer) + :buffer buffer + :command command + ;; Don't query for running processes when emacs is quit. + :noquery t + ;; Show the result buffer once the process has finished. + :sentinel (lambda (proc event) + (when (eq (process-status proc) 'exit) + (with-current-buffer (process-buffer proc) + (goto-char (point-min)) + (ansi-color-apply-on-region (point-min) (point-max)) + (setq buffer-read-only t) + (view-mode) + (end-of-line) + ;; difftastic diffs are usually 2-column side-by-side, + ;; so ensure our window is wide enough. + (let ((width (current-column))) + (while (zerop (forward-line 1)) + (end-of-line) + (setq width (max (current-column) width))) + ;; Add column size of fringes + (setq width (+ width + (fringe-columns 'left) + (fringe-columns 'right))) + (goto-char (point-min)) + (pop-to-buffer + (current-buffer) + `(;; If the buffer is that wide that splitting the frame in + ;; two side-by-side windows would result in less than + ;; 80 columns left, ensure it's shown at the bottom. + ,(when (> 80 (- (frame-width) width)) + #'display-buffer-at-bottom) + (window-width + . ,(min width (frame-width)))))))))))) + + (defun my/magit-show-with-difftastic (rev) + "Show the result of \"git show REV\" with GIT_EXTERNAL_DIFF=difft." + (interactive + (list (or + ;; If REV is given, just use it. + (when (boundp 'rev) rev) + ;; If not invoked with prefix arg, try to guess the REV from + ;; point's position. + (and (not current-prefix-arg) + (or (magit-thing-at-point 'git-revision t) + (magit-branch-or-commit-at-point))) + ;; Otherwise, query the user. + (magit-read-branch-or-commit "Revision")))) + (if (not rev) + (error "No revision specified") + (my/magit--with-difftastic + (get-buffer-create (concat "*git show difftastic " rev "*")) + (list "git" "--no-pager" "show" "--ext-diff" rev)))) + + (defun my/magit-diff-with-difftastic (arg) + "Show the result of \"git diff ARG\" with GIT_EXTERNAL_DIFF=difft." + (interactive + (list (or + ;; If RANGE is given, just use it. + (when (boundp 'range) range) + ;; If prefix arg is given, query the user. + (and current-prefix-arg + (magit-diff-read-range-or-commit "Range")) + ;; Otherwise, auto-guess based on position of point, e.g., based on + ;; if we are in the Staged or Unstaged section. + (pcase (magit-diff--dwim) + ('unmerged (error "unmerged is not yet implemented")) + ('unstaged nil) + ('staged "--cached") + (`(stash . ,value) (error "stash is not yet implemented")) + (`(commit . ,value) (format "%s^..%s" value value)) + ((and range (pred stringp)) range) + (_ (magit-diff-read-range-or-commit "Range/Commit")))))) + (let ((name (concat "*git diff difftastic" + (if arg (concat " " arg) "") + "*"))) + (my/magit--with-difftastic + (get-buffer-create name) + `("git" "--no-pager" "diff" "--ext-diff" ,@(when arg (list arg)))))) + ;; Based on https://tsdh.org/posts/2022-08-01-difftastic-diffing-with-magit.html (transient-define-prefix my/magit-extra-commands () "Extra magit commands." ["Extra commands" ("u" "Set upstream" my/magit-set-upstream) ("r" "Refresh state (update modeline)" my/magit-refresh-state) - ("m" "Update master/main" my/magit-update-master)]) + ("m" "Update master/main" my/magit-update-master) + ("d" "Difftastic Diff (dwim)" my/magit-diff-with-difftastic) + ("s" "Difftastic Show" my/magit-show-with-difftastic)]) (transient-append-suffix 'magit-dispatch "!" '("#" "Extra Magit Cmds" my/magit-extra-commands)) (define-key magit-status-mode-map (kbd "#") #'my/magit-extra-commands) |