[Emacs] Rework Eshell prompt
continuous-integration/drone/push Build is passing Details

The Eshell prompt is now git-aware with some powerline associated to it.
This commit is contained in:
Lucien Cartier-Tilet 2020-10-21 23:03:43 +02:00
parent 31eb64c2ba
commit 5211c24410
Signed by: phundrak
GPG Key ID: BD7789E705CB8DCA
1 changed files with 176 additions and 61 deletions

View File

@ -1330,7 +1330,7 @@
:header-args:emacs-lisp: :mkdirp yes :tangle ~/.config/emacs/private/user-config.el :exports code :results silent
:CUSTOM_ID: User_Configuration-4a937fe5
:END:
** Custom functions
** Custom functions, macros, and variables
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-ceb4bc42
:END:
@ -1341,37 +1341,42 @@
Almost all of my code snippets will be prefixed by either my name or the name
of the package or layer they are part of, unless they are an explicit
overwrite of a function that already exists.
*** ~phundrak/yas-rust-new-assignments~
*** Nord theming variables
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-phundrakyas-rust-new-assignments-10f73456
:CUSTOM_ID: User_Configuration-Custom_functions_and_variables-Some_theming_variables-9b853a99
:END:
The following function is a function that will allow me to easily create
~new~ functions for Rust structs. Inspired from [[https://github.com/jorgenschaefer/elpy][elpy]]s
~elpy-snippet-init-assignments~ function, it will automatically write
assignments to my new struct as I write new parameters in the ~new~
function. It also comes with a helper function that parses the arguments
given to the ~new~ function.
Yes, I do use a preconfigured theme, as mentioned above, but for some
elements such as Eshell, I need to define some variables for color, and Ill
do it here.
#+BEGIN_SRC emacs-lisp
(defun phundrak//yas-snippet-split-rust-args ($arg-string)
"Split a Rust argument string into ((name, default)...) tuples"
(mapcar (lambda ($elem)
(split-string $elem "[[:blank:]]*:[[:blank:]]*" t))
(split-string $arg-string "[[:blank:]]*,[[:blank:]]*" t)))
(setq phundrak/nord0 "#2e3440"
phundrak/nord1 "#3b4252"
phundrak/nord2 "#434c5e"
phundrak/nord3 "#4c566a"
phundrak/nord4 "#d8dee9"
phundrak/nord5 "#e5e9f0"
phundrak/nord6 "#eceff4"
phundrak/nord7 "#8fbcbb"
phundrak/nord8 "#88c0d0"
phundrak/nord9 "#81a1c1"
phundrak/nord10 "#5e81ac"
phundrak/nord11 "#bf616a"
phundrak/nord12 "#d08770"
phundrak/nord13 "#ebcb8b"
phundrak/nord14 "#a3be8c"
phundrak/nord15 "#b48ead")
#+END_SRC
(defun phundrak/yas-rust-new-assignments ($arg-string)
"Return a typical new assignment for arguments.
Inspired from elpys functions https://github.com/jorgenschaefer/elpy"
(let ((indentation (make-string (save-excursion
(goto-char start-point)
(current-indentation))
?\s)))
(mapconcat (lambda ($elem)
(if (string-match "^\\*" (car $elem))
""
(format "%s,\n%s" (car $elem) indentation)))
(phundrak//yas-snippet-split-rust-args $arg-string)
"")))
*** ~with-face~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions,_macros,_and_variables-with-face-60298b14
:END:
~with-face~ is a simple yet very useful macro that allows me to easily
create strings with faces defined as properties to the string passed as the
first argument. Here is how it is implemented:
#+BEGIN_SRC emacs-lisp
(defmacro with-face (str &rest properties)
`(propertize ,str 'face (list ,@properties)))
#+END_SRC
*** ~phundrak/add-all-to-list~
@ -1389,6 +1394,84 @@
$list)
#+END_SRC
*** ~phundrak/eshell-git-status~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions_and_variables-phundrakeshell-git-status-7f487b84
:END:
This function is used in my Eshell prompt which you can consult [[#User_Configuration-Eshell-Eshell_theme-a06715a9][here]]. This
function basically executes two git calls to get some information about a
git repo, which path we provide as an argument. Based on the result of these
git calls, the function will know what it needs to know about the repo to
build a git prompt that will be inserted in my Eshell prompt. And just for
shit and giggles, Ive made it so it is a powerline prompt.
#+BEGIN_SRC emacs-lisp
(defun phundrak/eshell-git-status ($path)
"Returns a string indicating the status of the current
repository if it exists. It should also append the name of the
current branch if it is not `master' or `main'. The theme is
inspired by the bobthefish theme for the fish shell which you can
find here: https://github.com/oh-my-fish/theme-bobthefish
Color code:
- green:
- orange: tracked stuff is staged but not commited
- red: tracked stuff is modified and not commited
Symbols:
- `*': dirty working dir, RED
- `~': staged changes, ORANGE
- `…': untracked files, GREEN
- `$': stashed changes
- `-': unpulled commits
- `-': unpushed commits
- `±': unpulled and unpushed commits"
(if (magit-toplevel $path)
(let* ((git-status-command (concat "cd " $path "; git status"))
(git-stash-status-command (concat "cd " $path "; git stash list"))
(status (eshell-command-result git-status-command))
(stashstat (eshell-command-result git-stash-status-command))
(detached (s-contains? "HEAD detached" status))
(dirty (s-contains? "Changes not staged for commit" status))
(staged (s-contains? "Changes to be committed" status))
(untracked (s-contains? "Untracked files" status))
(stash (not (null stashstat)))
(pull (s-contains? "git pull" status))
(push (s-contains? "git push" status))
(branch (replace-regexp-in-string "On Branch \\(.*\\)\n\\(.\\|\n\\)*" "\\1" status))
(branch (if (or (string= "master" branch)
(string= "main" branch))
nil
(if (s-contains? " " branch)
nil
branch))))
(let ((prompt (concat " "
(if detached ">" "")
(if branch (concat " " branch " "))
(if dirty "*")
(if staged "~")
(if untracked "…")
(if (and pull push) "±"
(if pull "-"
(if push "+")))
(if stash "$")
" "))
(accent (cond
(dirty nord11)
(staged nord13)
(t nord14)))
(background nord0))
(concat " "
(with-face ""
:background accent
:foreground background)
(with-face prompt
:background accent
:foreground (if dirty nord6 background))
(with-face ""
:background background
:foreground accent))))))
#+END_SRC
*** ~phundrak/fill-paragraph~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-~phundrak-fill-paragraph~-ab4ef600
@ -1403,20 +1486,6 @@
(call-interactively 'fill-paragraph)))
#+END_SRC
*** ~terminal-here-default-terminal-command~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-~terminal-here-default-terminal-command~-1916a912
:END:
This function is actually an overwrite of the default one which apparently
does not work on my machine. This function is called by
~terminal-here-launch~ and spawns an external terminal emulator in the
directory emacs was in when the terminal was invoked. I simply point out to
this function the name of my terminal emulator. Here is the code:
#+BEGIN_SRC emacs-lisp
(defun terminal-here-default-terminal-command (_dir)
'("st"))
#+END_SRC
*** ~phundrak/find-org-file~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-phundrakfind-org-file-029040a5
@ -1453,6 +1522,53 @@
:buffer "*org files*")))
#+END_SRC
*** ~phundrak/yas-rust-new-assignments~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-phundrakyas-rust-new-assignments-10f73456
:END:
The following function is a function that will allow me to easily create
~new~ functions for Rust structs. Inspired from [[https://github.com/jorgenschaefer/elpy][elpy]]s
~elpy-snippet-init-assignments~ function, it will automatically write
assignments to my new struct as I write new parameters in the ~new~
function. It also comes with a helper function that parses the arguments
given to the ~new~ function.
#+BEGIN_SRC emacs-lisp
(defun phundrak//yas-snippet-split-rust-args ($arg-string)
"Split a Rust argument string into ((name, default)...) tuples"
(mapcar (lambda ($elem)
(split-string $elem "[[:blank:]]*:[[:blank:]]*" t))
(split-string $arg-string "[[:blank:]]*,[[:blank:]]*" t)))
(defun phundrak/yas-rust-new-assignments ($arg-string)
"Return a typical new assignment for arguments.
Inspired from elpys functions https://github.com/jorgenschaefer/elpy"
(let ((indentation (make-string (save-excursion
(goto-char start-point)
(current-indentation))
?\s)))
(mapconcat (lambda ($elem)
(if (string-match "^\\*" (car $elem))
""
(format "%s,\n%s" (car $elem) indentation)))
(phundrak//yas-snippet-split-rust-args $arg-string)
"")))
#+END_SRC
*** ~terminal-here-default-terminal-command~
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Custom_functions-~terminal-here-default-terminal-command~-1916a912
:END:
This function is actually an overwrite of the default one which apparently
does not work on my machine. This function is called by
~terminal-here-launch~ and spawns an external terminal emulator in the
directory emacs was in when the terminal was invoked. I simply point out to
this function the name of my terminal emulator. Here is the code:
#+BEGIN_SRC emacs-lisp
(defun terminal-here-default-terminal-command (_dir)
'("st"))
#+END_SRC
** Emacs builtins
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Emacs_builtins-7822b8dd
@ -1763,16 +1879,10 @@
:PROPERTIES:
:CUSTOM_ID: User_Configuration-Eshell-Eshell_theme-a06715a9
:END:
As with most shells, again, it is possible to customize the appearance of
the Eshell prompt. First, we need to declare a macro so we can set a face
with properties:
#+BEGIN_SRC emacs-lisp
(defmacro with-face (str &rest properties)
`(propertize ,str 'face (list ,@properties)))
#+END_SRC
Now, lets declare a function that will abbreviate the current ~pwd~
fish-shell style.
As with most shells, again, it is possible to customize the appearance of
the Eshell prompt. Lets declare a function that will abbreviate the
current ~pwd~, that is, if we are in a directory inside our home directory,
~/home/<username>~ will be abbreviated to an =~=.
#+BEGIN_SRC emacs-lisp
(defun eshell/abbr-pwd ()
(let (($home (getenv "HOME"))
@ -1783,17 +1893,22 @@
($path))))
#+END_SRC
Now, lets declare our prompt:
Now, lets declare our prompt, with some Nord colors
#+BEGIN_SRC emacs-lisp
(defun eshell/my-prompt ()
(let ((header-bg "#161616"))
(concat
(with-face (eshell/abbr-pwd) :foreground "#008700")
"\n"
(if (= (user-uid) 0)
(with-face "➜" :foreground "red")
(with-face "➜" :foreground "#2345ba"))
" ")))
(let* ((header-bg phundrak/nord0)
(path (eshell/abbr-pwd)))
(concat (with-face (eshell/abbr-pwd)
:foreground phundrak/nord14)
;; add git status if it exists
(let (($path (eshell/pwd)))
(if (magit-toplevel $path)
(phundrak/eshell-git-status $path)))
" "
(if (zerop eshell-last-command-status)
(with-face "λ" :foreground phundrak/nord10)
(with-face "λ" :foreground phundrak/nord11))
" ")))
#+END_SRC
Now, lets declare our prompt regexp and our prompt functions: