I have written utilities for choosing what information, icons, and faces your eshell prompt presents.

Example eshell prompts:

Eshell prompt customization takes place in eshell-prompt-function and eshell-prompt-regexp . The former determines the content of your prompt while the latter distinguishes your commands.

I define a macro esh-section taking a name, an icon, a form or variable to be evaluated, and optionally face properties. They create anonymous functions which will be evaluated and concatenated at prompt-time.

( require 'dash ) ( require 's ) (defmacro with-face (STR &rest PROPS) "Return STR propertized with PROPS." ` (propertize , STR 'face ( list ,@ PROPS))) (defmacro esh-section (NAME ICON FORM &rest PROPS) "Build eshell section NAME with ICON prepended to evaled FORM with PROPS." ` ( setq , NAME (lambda () (when , FORM (-> , ICON (concat esh-section-delim , FORM) (with-face ,@ PROPS)))))) (defun esh-acc (acc x) "Accumulator for evaluating and concatenating esh-sections." (--if-let ( funcall x) ( if (s-blank? acc) it (concat acc esh-sep it)) acc)) (defun esh-prompt-func () "Build `eshell-prompt-function'" (concat esh-header (-reduce-from 'esh-acc "" eshell-funcs) "

" eshell-prompt-string))

Now lets define the needed configuration.

;; Separator between esh-sections ( setq esh-sep " " ) ; or " | " ;; Separator between an esh-section icon and form ( setq esh-section-delim " " ) ;; Eshell prompt header ( setq esh-header "

" ) ; or "

┌─" ;; Eshell prompt regexp and string. Unless you are varying the prompt by eg. ;; your login, these can be the same. ( setq eshell-prompt-regexp " " ) ; or "└─> " ( setq eshell-prompt-string " " ) ; or "└─> "

Now we are set to build some sections. A note, if a section's form returns nil, then it will be skipped, so the effect of eg. python virtual environments will only appear when you have an active venv.

(esh-section esh-dir "\xf07c" ;  (faicon folder) (abbreviate-file-name (eshell/pwd)) ' ( :foreground "gold" :bold ultra-bold :underline t )) (esh-section esh-git "\xe907" ;  (git icon) (magit-get-current-branch) ' ( :foreground "pink" )) (esh-section esh-python "\xe928" ;  (python icon) pyvenv-virtual-env-name) (esh-section esh-clock "\xf017" ;  (clock icon) (format-time-string "%H:%M" (current-time)) ' ( :foreground "forest green" )) ;; Below I implement a "prompt number" section ( setq esh-prompt-num 0 ) (add-hook 'eshell-exit-hook (lambda () ( setq esh-prompt-num 0 ))) (advice-add 'eshell-send-input :before (lambda ( &rest args) ( setq esh-prompt-num (incf esh-prompt-num)))) (esh-section esh-num "\xf0c9" ;  (list icon) (number-to-string esh-prompt-num) ' ( :foreground "brown" )) ;; Choose which eshell-funcs to enable ( setq eshell-funcs ( list esh-dir esh-git esh-python esh-clock esh-num)) ;; Enable the new eshell prompt ( setq eshell-prompt-function 'esh-prompt-func )

Further extensions to explore are predicate-based face application for eg. distinguishing master and other branches and modeline-like foreground separation.

I've hosted the code altogether at this gist.

display/shell in my config will host the most recent iteration and all my other emacs tweaks.