I like the Ys theme from oh my zsh to work in the terminal, which allows me to use the whole line for enter commands, show me the current directory git status and the colours are good in dark themes.
In the other side, I love the Emacs shell, eshell. So, why not have the same functions in the one true editor?
Here the code:
(defun pedro-eprompt--is-a-git-dir ()
"RETURN A STRING IF TRUE AND A NUMBER IF FALSE.
If is a git dir returns a string with the branch name, in other way a number with the status output of git command"
(let* ((output-buffer "*git-eshell-prompt")
(output-status (call-process "git" nil output-buffer nil "rev-parse" "--abbrev-ref" "HEAD"))
(current-branch (car (split-string (with-current-buffer output-buffer
(buffer-substring (point-min) (point-max)))
"\n"))))
(kill-buffer output-buffer)
(if (= output-status 0)
current-branch
output-status)))
(defun pedro-eprompt--git-status-verbose()
"RETURN 0 IF WORKING TREE CLEAN, OTHERWISE RETURN A STRING LIST WITH STAGGED/UNTRACKED..."
(let* ((output-buffer "*git-eshell-prompt")
(output-status (call-process "git" nil output-buffer nil "status" "--porcelain"))
(git-status (with-current-buffer output-buffer
(buffer-substring (point-min) (point-max))))
(status-list (mapcar #'(lambda(s)
(if (not (string-empty-p s))
(substring s 0 2)))
(split-string git-status "\n")))
(status-keys (delq nil (seq-uniq status-list)))
(verbose-list (mapcar #'(lambda(k)
(cons (seq-count #'(lambda(e)
(string= e k))
status-list)
k))
status-keys)))
(kill-buffer output-buffer)
(mapconcat #'(lambda (e)
(concat
(propertize (number-to-string (car e)) 'face `(:foreground "#ffffff"))
(propertize (cdr e) 'face `(:foreground "#8b3e2f" :weight bold :underline t))))
verbose-list
"")))
(defun pedro-eprompt--shorten-path ()
"SHORT THE PATH WHEN PATH LENGTH GREATER THAN `WINDOW-MAX-CHARS-PER-LINE' / 2"
(let ((path (abbreviate-file-name (eshell/pwd))))
(if (> (length path) (/ (window-max-chars-per-line) 2 )) ;; TODO max-size-path (?)
(let* ((max-size-path (/ (window-max-chars-per-line) 2))
(path-split (split-string (abbreviate-file-name (eshell/pwd)) "/"))
(shorten-list (mapcar (lambda (dir)
(if (string-empty-p dir )
"/"
(substring dir 0 1)))
(butlast path-split))))
(mapconcat (lambda (p)
(if (string= p "/") "" p))
(append shorten-list (last path-split))
"/"))
path)))
(defun pedro-eprompt--git-status()
"RETURN 0 IF WORKING TREE CLEAN, OTHERWISE 1."
(let* ((output-buffer "*git-eshell-prompt")
(output-status (call-process "git" nil output-buffer nil "status" "-s"))
(git-status (with-current-buffer output-buffer
(buffer-substring (point-min) (point-max)))))
(kill-buffer output-buffer)
(if (string-empty-p git-status)
0
1)))
(defun pedro-eprompt-prompt-function ()
(setq eshell-prompt-regexp "^$ ")
(concat
"\n"
"# " ;TODO
(propertize user-login-name 'face `(:foreground "#1f5582"))
"@"
(propertize system-name 'face `(:foreground "#9acd32" ))
": "
(propertize (pedro-eprompt--shorten-path) 'face `(:foreground "#cd8500" :weight bold))
(let ((output (pedro-eprompt--is-a-git-dir))
(git-status (pedro-eprompt--git-status)))
(if (numberp output)
""
(concat (propertize " on git:" 'face `(:foreground "#ffffff"))
(propertize output 'face `(:foreground "#1f5582")) " "
(if (= git-status 0)
(propertize "o" 'face `(:foreground "#9acd32"))
;;(propertize "x" 'face `(:foreground "#ff6347"))))))
(pedro-eprompt--git-status-verbose)))))
" "
(let ((output eshell-last-command-status)
(current-time (propertize (format-time-string "[%-H:%M:%S]") 'face `(:foreground "#ffffff" ))))
(if (= output 0)
current-time
(concat current-time " C:" (propertize (number-to-string output) 'face `(:foreground "#ff6347")))))
"\n"
(propertize "$" 'face `(:foreground "#ff6347"))
" "))
(setq eshell-prompt-function #'pedro-eprompt-prompt-function)