aboutsummaryrefslogtreecommitdiff
path: root/Emacs/.config/emacs/elisp/eshell-prompt.el
diff options
context:
space:
mode:
Diffstat (limited to 'Emacs/.config/emacs/elisp/eshell-prompt.el')
-rw-r--r--Emacs/.config/emacs/elisp/eshell-prompt.el240
1 files changed, 171 insertions, 69 deletions
diff --git a/Emacs/.config/emacs/elisp/eshell-prompt.el b/Emacs/.config/emacs/elisp/eshell-prompt.el
index d0a4e91..9267469 100644
--- a/Emacs/.config/emacs/elisp/eshell-prompt.el
+++ b/Emacs/.config/emacs/elisp/eshell-prompt.el
@@ -19,25 +19,86 @@
;;; Commentary:
-;; We provide a function +eshell-prompt which generates a prompt on
+;; We provide a function ep which generates a prompt on
;; demand.
;;; Code:
-(defvar +eshell-prompt/user-prompt "𝜆> "
+(defvar ep/user-prompt " λ "
"Prompt for user to input.")
-(defvar +eshell-prompt/dir-colour "deepskyblue")
-(defvar +eshell-prompt/success-colour "forestgreen")
-(defvar +eshell-prompt/failure-colour "red")
-
-(defun +eshell-prompt/--colour-on-last-command ()
+(defvar ep/pwd-max-len 30)
+(defvar ep/git-branch-max-len 5)
+
+(defvar ep/dir-colour "deepskyblue")
+(defvar ep/success-colour "green2")
+(defvar ep/failure-colour "red")
+(defvar ep/branch-name-colour "LightSalmon")
+(defvar ep/pipe-colour "green4")
+(defvar ep/ahead-colour "dodger blue")
+(defvar ep/remote-colour "DarkGoldenrod")
+
+(defun ep/make-prompt ()
+ (let ((git (ep/--git-status)))
+ (thread-last
+ `(("┌──" :foreground ,ep/pipe-colour)
+ "["
+ (,(ep/--user-and-remote) :foreground ,ep/remote-colour)
+ (,(ep/--pwd)
+ :foreground ,ep/dir-colour)
+ ,(if (string= git "")
+ ""
+ (concat "]─[" git))
+ "]"
+ "\n"
+ ("└─>" :foreground ,ep/pipe-colour)
+ (,ep/user-prompt :foreground ,(ep/--colour-on-last-command)))
+ (mapconcat
+ #'(lambda (item)
+ (thread-last
+ (propertize (car item)
+ 'font-lock-face (cdr item)
+ 'front-sticky '(font-lock-face read-only)
+ 'rear-nonsticky '(font-lock-face read-only))
+ (if (not (listp item))
+ item)))))))
+
+(defun ep/--colour-on-last-command ()
"Returns an Emacs colour based on ESHELL-LAST-COMMAND-STATUS."
(if (zerop eshell-last-command-status)
- +eshell-prompt/success-colour
- +eshell-prompt/failure-colour))
+ ep/success-colour
+ ep/failure-colour))
+
+(defun ep/--with-fg-colour (s colour)
+ "Helper which propertises a string `s' with foreground colour `colour'"
+ (propertize s 'font-lock-face `(:foreground ,colour)))
+
+(defun ep/--user-and-remote ()
+ "If in a remote directory, return a string representing that host,
+otherwise empty string."
+ (if (file-remote-p default-directory)
+ (let ((user (file-remote-p default-directory 'user))
+ (host (file-remote-p default-directory 'host)))
+ (thread-first
+ (if user
+ (format "%s@%s" user host)
+ host)
+ (concat ":")))
+ ""))
+
+(defun ep/--git-status ()
+ "Returns a completely formatted string of form
+BRANCH-NAME(REMOTE-STATUS)(CHANGES)."
+ (let ((git-branch (ep/--git-branch-name)))
+ (if (null git-branch)
+ ""
+ (format
+ "%s(%s)(%s)"
+ (ep/--with-fg-colour git-branch ep/branch-name-colour)
+ (ep/--git-remote-status)
+ (ep/--git-change-status)))))
-(defun +eshell-prompt/--git-remote-status ()
+(defun ep/--git-remote-status ()
"Returns a propertized string for the status of a repository
in comparison to its remote. 3 differing strings are returned
dependent on:
@@ -53,67 +114,108 @@ behind or ahead the local repository is."
(status (nth 3 branch-status))
(diff (cl-position "by" branch-status :test #'string=)))
(if (null diff)
- (propertize "=" 'font-lock-face `(:foreground ,+eshell-prompt/success-colour))
- (let ((n (nth (+ 1 diff) branch-status)))
- (concat
- (cond
- ((string= status "ahead")
- (propertize "→" 'font-lock-face '(:foreground "dodger blue")))
- ((string= status "behind")
- (propertize "←" 'font-lock-face '(:foreground "red"))))
- n)))))
-
-(defun +eshell-prompt/--git-change-status ()
+ (ep/--with-fg-colour "=" ep/success-colour)
+ (concat
+ (cond
+ ((string= status "ahead")
+ (ep/--with-fg-colour "→" ep/ahead-colour))
+ ((string= status "behind")
+ (ep/--with-fg-colour "←" ep/failure-colour)))
+ (nth (1+ diff) branch-status)))))
+
+(defun ep/--git-change-status ()
"Returns a propertized string for the condition of the worktree in
-a repository. If there are no changes i.e. the worktree is clean
-then a green tick is returned, but if there are changes then the
-number of files affected are returned in red."
- (let* ((git-cmd "git status -s")
- (command-output (split-string (shell-command-to-string git-cmd) "\n"))
- (changed-files (- (length command-output) 1)))
- (if (= changed-files 0)
- (propertize "✓"
- 'font-lock-face
- `(:foreground ,+eshell-prompt/success-colour))
- (propertize (number-to-string changed-files)
- 'font-lock-face
- `(:foreground ,+eshell-prompt/failure-colour)))))
-
-(defun +eshell-prompt/--git-status ()
- "Returns a completely formatted string of
-form (BRANCH-NAME<CHANGES>[REMOTE-STATUS])."
- (let ((git-branch (thread-last
- (split-string (shell-command-to-string "git branch") "\n")
- (cl-remove-if (lambda (s) (= (length s) 0)))
- (cl-find-if (lambda (s) (string= "*" (substring s 0 1)))))))
- (if (null git-branch)
- ""
- (format
- "(%s<%s>[%s])"
- (nth 2 (split-string git-branch "\n\\|\\*\\| "))
- (+eshell-prompt/--git-change-status)
- (+eshell-prompt/--git-remote-status)))))
-
-(defun +eshell-prompt/make-prompt ()
- (let ((git (+eshell-prompt/--git-status)))
- (mapconcat
- (lambda (item)
- (if (listp item)
- (propertize (car item)
- 'font-lock-face (cdr item)
- 'front-sticky '(font-lock-face read-only)
- 'rear-nonsticky '(font-lock-face read-only))
- item))
- (list
- "["
- `(,(abbreviate-file-name (eshell/pwd)) :foreground ,+eshell-prompt/dir-colour)
- "]"
- (if (string= git "")
- ""
- (concat " " git))
- "\n"
- (list "𝜆> " ':foreground (+eshell-prompt/--colour-on-last-command))))))
+a repository.
+If there are no changes i.e. the worktree is clean then a green tick is
+returned.
+
+If there are changes then we characterise it by the following parameters:
+- staged changes in green
+- unstaged but tracked changes in blue
+- untracked files in red
+"
+ (let* ((git-cmd "git status -s")
+ (command-output (thread-first
+ (shell-command-to-string git-cmd)
+ (split-string "\n")
+ butlast))
+ (status-codes (mapcar #'(lambda (s) (cons (substring s 0 1) (substring s 1 2)))
+ command-output))
+ (count-f (lambda (coll) (thread-first
+ (lambda (x) (not (or (string= x "?") (string= x " "))))
+ (cl-count-if
+ coll))))
+ (total (length status-codes))
+ (staged (funcall count-f (mapcar #'car status-codes)))
+ (modified (funcall count-f (mapcar #'cdr status-codes)))
+ (not-tracked (cl-count-if (lambda (x) (string= (cdr x) "?")) status-codes)))
+ (if (= total 0)
+ (ep/--with-fg-colour "✓" ep/success-colour)
+ (thread-last
+ (list
+ (ep/--with-fg-colour (number-to-string staged) ep/success-colour)
+ (ep/--with-fg-colour (number-to-string modified) ep/ahead-colour)
+ (ep/--with-fg-colour (number-to-string not-tracked) ep/failure-colour))
+ (cl-remove-if #'(lambda (s) (string= s "0")))
+ (mapconcat #'(lambda (s) (concat s "/")))))))
+
+(defun ep/--git-branch-name ()
+ "Get the branch name of the current working directory.
+
+If a deteached head, return the SHA."
+ (let* ((branch-name (thread-last
+ (split-string (shell-command-to-string "git branch") "\n")
+ (cl-remove-if #'(lambda (s) (thread-last (length s) (= 0))))
+ (cl-find-if #'(lambda (s) (thread-last (substring s 0 1) (string= "*"))))))
+ (branch-name (thread-last
+ (substring branch-name 2)
+ (if (null branch-name) nil))))
+ (if branch-name
+ (ep/--abbreviate-str
+ (cond
+ ((string= "(" (substring branch-name 0 1))
+ (replace-regexp-in-string
+ "\n$" ""
+ (shell-command-to-string "git rev-parse --short HEAD")))
+ (t branch-name))
+ "-"
+ ep/git-branch-max-len))))
+
+(defun ep/--pwd ()
+ (let ((pwd (thread-last (eshell/pwd)
+ tramp-file-local-name
+ abbreviate-file-name)))
+ (ep/--abbreviate-str pwd "/" ep/pwd-max-len)))
+
+(defun ep/--abbreviate-str (to-abbrev sep max-len)
+ (if (<= (length to-abbrev) max-len)
+ to-abbrev
+ (let ((str "")
+ (len (length to-abbrev))
+ (components (split-string to-abbrev sep)))
+ (while (and (> len max-len)
+ (cdr components))
+ (let* ((comp (car components))
+ (ab-comp (cond
+ ((= 0 (length comp)) "")
+ ((= 1 (length comp)) comp)
+ ((char-equal (elt comp 0) ?.)
+ (substring comp 0 3))
+ (t
+ (substring comp 0 2)))))
+ (setq str (concat str ab-comp sep)
+ len (- len (length ab-comp))
+ components (cdr components))))
+ (thread-last
+ components
+ (cl-reduce #'(lambda (a b) (concat a sep b)))
+ (if (null components) "")
+ (concat str)))))
(provide 'eshell-prompt)
;;; eshell-prompt.el ends here
+
+;; Local Variables:
+;; read-symbol-shorthands: (("ep" . "eshell-prompt"))
+;; End: