Add git stash support and make branch status more efficient

This commit is contained in:
Alexander Rosenberg 2024-01-17 21:12:42 -08:00
parent 7b9cc70e7c
commit 47039d4bfe
Signed by: Zander671
GPG Key ID: 5FD0394ADBD72730

View File

@ -5,6 +5,7 @@
(require 'vc)
(require 'vc-git)
(require 'eshell)
(require 'cl-lib)
(defun eshell-starship--git-process-lines (&rest flags)
"Run `vc-git-program' and return an array of its output lines.
@ -43,68 +44,56 @@ Example:
(if-let ((worktree (vc-root-dir))
(parent (file-name-parent-directory worktree)))
(file-relative-name default-directory parent)
(eshell-starship--replace-home-with-tilda default-directory))))
(eshell-starship--replace-home-with-tilda
default-directory))))
(defun eshell-starship--prompt-status-char-for-branch (branch remote)
"Get the status char representing the relation between BRANCH and REMOTE."
(let ((lines (eshell-starship--git-process-lines
"rev-list"
"--left-right"
(concat branch "..." remote)))
(to-remote nil)
(to-local nil))
(dolist (line lines)
(if-let (((not (string-empty-p line)))
(dir-char (aref line 0)))
(if (= dir-char ?<)
(setq to-remote t)
(setq to-local t))))
(cond
((and to-remote to-local) ?󰹺)
(to-remote ?󰜷)
(to-local ?󰜮))))
(defun eshell-starship--prompt-current-branch-status (status-line)
"Get the status char for the current branch and its remote.
STATUS-LINE is the first line of output from \"git status --porcelain=v1 -b\"."
(when (string-match
"\\[\\(?:ahead \\([0-9]+\\)\\)?,? ?\\(?:behind \\([0-9]+\\)\\)?\\]$"
status-line)
(let ((ahead (match-string 1 status-line))
(behind (match-string 2 status-line)))
(cond
((and ahead behind) ?󰹺)
(ahead ?󰜷)
(behind ?󰜮)))))
(defun eshell-starship--prompt-current-branch-status ()
"Get the status char for the current branch and its remote."
(let ((refs (eshell-starship--git-process-lines
"for-each-ref"
"--format=%(HEAD)%00%(refname:short)%00%(upstream:short)"
"refs/heads")))
(catch 'break
(dolist (ref refs)
(if-let ((split-ref (split-string ref "\0" nil nil))
((equal (car split-ref) "*")))
(throw 'break (eshell-starship--prompt-status-char-for-branch
(cadr split-ref)
(caddr split-ref))))))))
(defun eshell-starship--prompt-git-has-stash ()
"Return t if the current git directory has a stash, nil otherwise."
(= (process-file vc-git-program nil nil nil
"rev-parse" "--verify" "refs/stash") 0))
(defun eshell-starship--prompt-git-state-chars ()
"Get chars, like + and ✘ for `eshell-starship--prompt-function'."
(let ((lines (eshell-starship--git-process-lines "status" "--porcelain=v1"))
(branch-status (eshell-starship--prompt-current-branch-status))
(status-arr))
(dolist (line lines)
(let* ((lines (eshell-starship--git-process-lines "status" "--porcelain=v1" "-b"))
(branch-status (eshell-starship--prompt-current-branch-status
(car lines)))
(status-arr))
(dolist (line (cdr lines))
(cl-loop with fields = (string-split line " " t " *")
with status-str = (car-safe fields)
for status-char across status-str
do
(cond ((or (= status-char ?M) (= status-char ?T))
(add-to-list 'status-arr ?!))
(push ?! status-arr))
((= status-char ??)
(add-to-list 'status-arr ??))
(push ?? status-arr))
((or (= status-char ?A) (= status-char ?C))
(add-to-list 'status-arr ?+))
(push ?+ status-arr))
((= status-char ?D)
(add-to-list 'status-arr ?))
(push ? status-arr))
((= status-char ?R)
(add-to-list 'status-arr ))
(push status-arr))
((= status-char ?U)
(add-to-list 'status-arr ?=)))))
(push ?= status-arr)))))
(when (eshell-starship--prompt-git-has-stash)
(push ?$ status-arr))
(sort status-arr #'<)
(when branch-status
(push branch-status status-arr))
(apply 'string status-arr)))
(apply 'string (seq-uniq status-arr))))
(defun eshell-starship--prompt-git-get-operation ()
"Return the current git operation. For example, a revert."
@ -198,7 +187,7 @@ END-TIME is the time when the command finished executing."
;;;###autoload
(define-minor-mode eshell-starship-prompt-mode
"Minor mode to make eshell prompts look like starship (https://starship.rs)"
"Minor mode to make eshell prompts look like starship (https://starship.rs)."
:global nil
:init-value nil
:interactive (eshell-mode)