Opening any CLI in Emacs
Reddit pointed out that there is a much easier way to accomplish what is
described in this article: C-u M-x comint-run
, then type the executable name
in the first prompt, and arguments in the second prompt.
This can also be used from Emacs Lisp:
(comint-run "perl" '("-de" "0")')
I’m keeping the rest of the article anyway because I enjoy public embarassment.
If you want to do it the complicated way, open a new scratch buffer and evaluate
(with-current-buffer (current-buffer) (make-comint-in-buffer "perl" (current-buffer) "perl" nil "-de" "0"))
But why?
Some clis are not built on readline, and they are a pain to use. There’s no support for editing the input, and every keypress inserts characters – even backspace and arrow keys. Interaction with these clis might end up looking something like
[user@host ~]$ perl -de 0 Loading DB routines from perl5db.pl version 1.77 ... DB<1> printf^Ax ^E"d^H2d"^C^C^C^D[user@host ~]$
When faced with a cli like this, people often resort to writing commands in a text editor and then copy–pasting them into the cli. But there’s a better way.
Emacs has something called comint-mode which automatically turns any cli, however bare, into a powerful one. You will find existing support for many common programs, but even if there’s not – as with the Perl debugger – we can improvise it in two steps:
- First open a junk buffer. I do this by pressing
C-x b
and then slamming my forehead onto the keyboard to generate a unique buffer name. - Press
M-:
to evaluate an Emacs Lisp expression, and paste the Emacs Lisp expression in the code block at the top of this article.
This runs the desired command (in this case perl -de 0
) as an inferior
interpreter. Any output of the command will be pasted into the Emacs buffer,
and if we press return at any point it will send the current line to the cli
as input. With this, we can
- Use the full Emacs complement of text editing to compose input.
- Navigate the history of inputs with
M-p
andM-n
. - Move the cursor to a any previous line (input or output), edit it if we want, and then press return to send it as new input.
Much nicer than the cli we are wrapping.
If we find ourselves doing this often with different clis, we could wrap the expression at the top into a convenient Emacs command that prompts for the program to run, and executes it with comint in a new buffer. Me, I have mainly encountered this with Perl so far, so I created a Perl-specific function for it instead.