Eshell as gymnasium

Did you note how underpowered is Eshell out of the box? There are almost no premade commands above and beyond what we'd expect from any comint mode, even in em-extras or the ELPAs… we have to write the features we want ourselves!

As it is, Eshell (and shell-mode and other comint modes) has been special only to the minority of the Emacs community who hold a lot of skill in Elisp. For the rest, it's just a weird sort of alternative to their terminal emulator, with some ups and some downs.

Yet… it has the potential to do a lot for the newbie. If you approach it a certain way, it works as a stepping stone to general Emacs-fu. Terminal emulators have ruined our mindsets, and continuing to rely on the likes of ansi-term (or using shell-mode as if it was no different from a terminal)1 hinders developing effective ways to control your system, and as a consequence, hinders developing Emacs-fu too.

Priorities in our approach:

  • generalize skills
    • Why can I manipulate text in Eshell with grep, sort, uniq etc, but not outside Eshell? Unix tools like these live in silos.
      • Even with the lovely command objed-ipipe, I'm just carrying the Unix silo with me, which has to be set up akin to a trebuchet instead of integrating naturally with my work.
  • get out of the shell
    • Always try to find a way to do something that would work outside the shell too.
  • avoid memorizing redundant ways to do similar things

Consider the coreutils mostly obsolete (Never learn Bash):

  • We shouldn't need ls when we have dired
  • We shouldn't need cd when we have find-file
  • We shouldn't need grep when we have keep-lines/flush-lines
  • We shouldn't need find when we have multi-occur
  • and so on

Pretend you never learned the coreutils. How do you solve your next problem? There's usually a way, and it'll be a trick you can reuse!

My learning loop has been to solve a specific problem, then generalize it.

  • First I wrote a command my-copy-region-into-variable. Then I implemented automatic backreferences: the outputs of every shell command is automatically saved into an Emacs-global variable with no effort on my part.
  • First I wrote a command my-replace-path-at-point-with-truename. Then I wrote the more general my-cycle-path-at-point.
  • First I wrote a command my-replace-var-at-point-with-value which only looked up envvars like $DOOMDIR, extended it to fall back on Lisp vars if available, then realized that this is just crux-eval-and-replace plus envvars, so I instead extended that to also "eval-and-replace" envvars.
    • Then it turned out there's no reason to bind my custom version of crux-eval-and-replace to a key: instead, you can make it so that after every vanilla eval-last-sexp or eval-defun, the evalled thing is marked (without moving point) and its result copied into your kill ring, so you can simply call yank if you wished to replace. You can additionally ensure that any motion pops the mark and restores point and any active region, so there's no interference with the mark workflow you may have had going.
      • An alternative to activating the region is to keep the distinction between eval and eval-print, make the result print after point (i don't see the rationale for the default behavior of printing before point, it doesn't seem to have any workflow in mind), and use C-w optionally to remove the original sexp (it works without an active region).
  • First I wrote a command my-insert-other-buffer-file-name. It's useful many times, but sometimes doesn't insert the buffer I had in mind. Enter my-insert-other-buffer-file-name-and-cycle-repeat.

What links here

Created (3 years ago)