Add $OUTPUT and $LAST eshell variables

These contain the output from the last eshell command. Cool how easily
I implemented this.
This commit is contained in:
Howard Abrams 2022-09-23 16:20:56 -07:00
parent bcb014a9ef
commit 2a6302c43d

View file

@ -210,6 +210,78 @@ This allows us to replace some of our aliases with functions:
(eshell-fn-on-files 'find-file-other-window 'find-file-other-window args))
#+end_src
Well leave the =e= alias to replace the =eshell= buffer window.
** Last Results
The [[https://github.com/mathiasdahl/shell-underscore][shell-underscore]] project looks pretty cool, where the =_= character represents a /filename/ with the contents of the previous command (you know, like if you were planning on it, youd =tee= at the end of every command). An interesting idea that I could duplicate.
While diving into the =eshell= source code, I noticed that the special variable, =$$= can be used /sometimes/ as the output of the last command. For instance:
#+begin_example
$ echo "hello world"
hello world
$ echo $$
hello world
#+end_example
However, what I would like is something like this to work:
#+begin_example
$ ls *.org(U)
a.org b.org f.org
$ rg "foobar" $$
#+end_example
The problem /may/ be between calling Emacs functions versus external commands, as the =echo= works, but the call to =ls= doesnt:
#+begin_example
$ ls *.org(U) b.txt
a.org b.org f.org b.txt
$ echo Nam $$
("Nam" nil)
#+end_example
However, we could add a hook that runs /after/ every command to copy the output to a variables of our choosing:
#+begin_src emacs-lisp
(defvar OUTPUT ""
"Contains the output from the last eshell command executed.")
(defvar LAST nil
"Contains a list of elements from the last eshell command executed.")
#+end_src
Why two variables? Well unlike the behavior of the original shell (and most of its descendents, like =bash=), =eshell= doesnt automatically split on whitespace. For instance, =echo= called this way:
#+begin_example
$ echo a b *.txt
("a" "b"
("b.txt" "date today.txt"))
#+end_example
Is given a list of /three elements/: =a=, =b=, and a list of all files in the current directory with an =.org= extension. An interesting side-effect is that spaces in filenames are /often okay/. So we want =$OUTPUT= to contain the commands output /as a string/, and we have, =$LAST= contains the same stuff, but separated by spaces, into a list. So, if we are passing the output from =ls= to =grep=, we would use =$LAST= to represent files.
The following function does the work of saving the output of the last command. We can get this because after every command, eshell updates two variables, [[elisp:(describe-variable 'eshell-last-input-end)][eshell-last-input-end]] (the start of the output), and [[elisp:(describe-variable 'eshell-last-output-start)][eshell-last-output-start]] (the end of the output):
#+begin_src emacs-lisp
(defun ha-eshell-store-last-output ()
"Store the output from the last eshell command.
Called after every command by connecting to the `eshell-post-command-hook'."
(setq OUTPUT
(s-trim
(buffer-substring-no-properties eshell-last-input-end eshell-last-output-start)))
(setq LAST
(split-string (rx (one-or-more space)) OUTPUT)))
#+end_src
Now we save this output after every command by adding it to the [[elisp:(describe-variable 'eshell-post-command-hook)][eshell-post-command-hook]]:
#+begin_src emacs-lisp
(add-hook 'eshell-post-command-hook 'ha-eshell-store-last-output)
#+end_src
Success:
#+begin_example
$ ls *.org(U) b.txt
a.org b.txt
$ rg Nam $LAST
a.org
8:Nam vestibulum accumsan nisl.
b.txt
1:Nam euismod tellus id erat.
#+end_example
* Special Prompt
Following [[http://blog.liangzan.net/blog/2012/12/12/customizing-your-emacs-eshell-prompt/][these instructions]], we build a better prompt with the Git branch in it (Of course, it matches my Bash prompt). First, we need a function that returns a string with the Git branch in it, e.g. ":master"
#+begin_src emacs-lisp :tangle no