No debug on errors in Eshell

And while we are at it, let's leave more notes for myself.
This is why I like literate programming for my Emacs Configuration
files.
This commit is contained in:
Howard Abrams 2023-12-03 16:25:42 -08:00
parent 2d9725290b
commit 1022f21d29

View file

@ -31,17 +31,28 @@ Tell straight to use the built-in =eshell=:
#+begin_src emacs-lisp
(use-package eshell
:straight (:type built-in)
:hook (eshell-mode . (lambda () (setq mode-line-format nil))))
:hook (eshell-mode . 'ha-eshell-setup))
#+end_src
After reading [[https://xenodium.com/my-emacs-eye-candy/][this essay]], I decided to try hiding the mode line in eshell windows … at least, until I get the mode line to display more important information. Note that hiding the mode line is fairly straight-forward, but others might want to use the [[https://github.com/hlissner/emacs-hide-mode-line][hide-mode-line]] package that turns that /mode-line definition/ into a minor mode that can be toggled.
I like =debug-on-error=, but not in Eshell, so I set this up when entering Eshell:
#+begin_src emacs-lisp
(defun ha-eshell-setup ()
(make-local-variable 'debug-on-error)
(setq mode-line-format nil
debug-on-error nil))
#+end_src
** Navigation and Keys
Along with the regular Emacs keybindings, Eshell comes with some interesting features:
- ~M-RET~ gives you a prompt, even when you are running another command. Since =eshell= passes all input to subprocesses, there is no automatic input queueing as there is with other shells.
- ~C-c C-p~ / ~C-c C-n~ jumps between command inputs using Eat.
- ~C-c C-t~ truncates the buffer if it grows too large.
- ~C-c C-r~ will move point to the beginning of the output of the last command. With a prefix argument, =eshell= narrows to view its output.
- ~C-c C-o~ will delete the output from the last command.
- ~C-c C-f~ will move forward a complete shell argument.
- ~C-c C-f~ will move forward a complete shell argument, but I usually either type ~Escape~ to enter Evil mode, or just issue ~M-f~ / ~M-b~.
- ~C-c C-b~ will move backward a complete shell argument.
- ~M-S-r~ shows/selects a better history of commands (see below). Yes, the up/down arrows keys (as well as ~M-p~ / ~M-n~) scroll through this, but that is /slow/.
** Control-D Double Duty
Used to ~C-d~ exiting from a shell? Want it to keep working, but still allow deleting a character? We can have it both (thanks to [[https://github.com/wasamasa/dotemacs/blob/master/init.org#eshell][wasamasa]]):
#+begin_src emacs-lisp
@ -77,9 +88,31 @@ On [[http://www.reddit.com/r/emacs/comments/1zkj2d/advanced_usage_of_eshell/][th
(ring-elements eshell-history-ring)))))
#+END_SRC
* Predicate Filters and Modifiers
The =T= predicate filter allows me to limit file results that have internal =org-mode= tags. For instance, =eshell= will send files that have a =#+TAGS:= header with a =mac= label to the =grep= function:
This is a cool and under-rated feature of Eshell. Type the following commands into an Eshell buffer for the details:
- ~eshell-display-modifier-help~
- ~eshell-display-predicate-help~
In short, use parens to limit the files, for instance:
#+begin_src sh
$ grep brew *.org(T'mac')
ls *.sh(*) # List shell scripts that are executable
ls *(/) # List directories (recursively)
#+end_src
And parens with a colon character transform the filename, useful with =for=:
#+begin_src sh
for F in *.org(:r) { mv $F.org $F.el }
#+end_src
The =T= predicate filter allows me to limit file results that have internal =org-mode= tags.
#+begin_src sh
$ ls *.org(T'org')
ha-agendas.org ha-org-journaling.org ha-org.org
ha-capturing-notes.org ha-org-publishing.org
ha-org-clipboard.org ha-org-word-processor.org
#+end_src
For instance, =eshell= will send files that have a =#+TAGS:= header with a =macos= label to the =grep= function:
#+begin_src sh
$ grep brew *.org(T'macos')
#+end_src
As described in [[http://www.howardism.org/Technical/Emacs/eshell-fun.html][this essay]], to extend Eshell, we need a two-part function:
@ -112,7 +145,8 @@ For the first step, we have our function /called/ as it helps parse the text. Ba
(insert-file-contents file)
(re-search-forward ,reg nil t 1))))
(error "The `T' predicate takes an org-mode tag value in single quotes.")))
#+END_src
#+end_src
Then we need add that function to the =eshell-predicate-alist= as the =T= tag:
#+begin_src emacs-lisp
(defun ha-eshell-add-predicates ()
@ -125,6 +159,7 @@ Gotta have some [[http://www.emacswiki.org/emacs/EshellAlias][shell aliases]], r
#+begin_src sh
alias ll 'ls -AlohG --color=always'
#+end_src
Note that you need single quotes (not double quotes). Also note that more than one parameter doesnt work with aliases (to resolve that, we need to write [[Eshell Functions][a function]]).
Second, you can create/populate the alias file, [[file:~/.emacs.d/eshell/alias][~/.emacs.d/eshell/alias]] … as long as you dont use those single quotes:
@ -134,6 +169,7 @@ Second, you can create/populate the alias file, [[file:~/.emacs.d/eshell/alias][
alias d dired $1
alias find echo 'Please use fd <pattern> <paths> instead.'
#+end_src
Yeah, the variable =$*= doesnt work as youd expect, so use =$1= when calling Emacs functions that take one parameter).
For instance, while I would like to have the following, the real solution is to make functions (see [[Less and More][below for details]]).
#+begin_src sh
@ -141,6 +177,7 @@ For instance, while I would like to have the following, the real solution is to
#+end_src
Third, you want more /control/, you can use the help:eshell/alias function, but it doesnt honor =$1= and other parameters, so we could create conditionally create function that we add to the [[help:eshell-mode-hook][eshell-mode-hook]], for instance:
#+begin_src emacs-lisp :tangle no
(defun ha-eshell-add-aliases ()
"Call `eshell/alias' to define my aliases."
@ -158,7 +195,19 @@ I have also had a lot of trouble getting aliases to work, for instance =dired= w
#+end_src
To work around this, I create functions instead.
* Eshell Functions
Any function that begins with =eshell/= is available as a command (with the remaining letters) Once I had a function =eshell/f= as a replacement for =find=, but the [[https://github.com/sharkdp/fd][fd]] project is better.
Any function that begins with =eshell/= is available as a command (with the remaining letters). For instance:
#+begin_src emacs-lisp
(defun eshell/greet (&rest params)
(let ((greeting (seq-random-elt
'(Hello Greeting Howdy "How's it going"))))
(if params
(format "%s, %s!" greeting
(propertize (car params) 'face
'(:weight bold :foreground "lightblue")))
"Hello World.")))
#+end_src
Not everything /has/ to be an Emacs function, as the normal executables are available. Once I had a function =eshell/f= as a replacement for =find=, but the [[https://github.com/sharkdp/fd][fd]] project is better.
Since =eshell= is an /Emacs/ shell, I try to think how to use Emacs buffers in a shell-focused workflow. For instance, use =view-file= instead of =less=, as it will show a file with syntax coloring, and typing ~q~ returns to your shell session.
@ -1196,17 +1245,17 @@ And finally, add our new functions to [[elisp(describe-variable 'eshell-virtual-
(add-to-list 'eshell-virtual-targets '("/dev/c" ha-eshell-target-engineering-notebook nil)))
#+end_src
* EAT and Eshell
The [[https://codeberg.org/akib/emacs-eat][Emulate a Terminal]] project provides flicker-free, perfect display, of visual commands in Eshell, eliminating one of my primary issue with using Eshell all the time.
The [[https://codeberg.org/akib/emacs-eat][Emulate a Terminal]] project provides flicker-free, perfect display, of visual commands in Eshell, eliminating one of my primary issue with using Eshell all the time. (Check out Akib Azmain Turjas [[https://emacsconf.org/2023/talks/eat/][talk at EmacsConf2023]]).
#+begin_src emacs-lisp
(use-package eat
:after eshell
:straight (:repo "https://codeberg.org/akib/emacs-eat")
:hook (eshell-load . #'eat-eshell-visual-command-mode))
#+end_src
Note: Bash integration?
#+begin_src sh
[ -n "$EAT_SHELL_INTEGRATION_DIR" ] && source "$EAT_SHELL_INTEGRATION_DIR/bash"
#+end_src
Note that the =eat-eshell-visual-command-mode= also kicks off the global minor mode, =eat-eshell-mode=. The big advantage of Eat is the /three input modes/, however, in Eshell with Evil, I can just type ~Escape~ to go into Emacs Mode, and ~G A~ to return to typing Terminal commands.
* 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