Emacs package: misTTY

There are a number of ways to run shells in Emacs. As is often the case, you can find an excellent overview of the various options over at Mastering Emacs. There is also a new entry in this space that is worth a look: misTTY.

I stumbled across misTTY the other day and have been trying it out. It’s under active development – so expect things to evolve – but the initial experience is quite smooth. I was able to load the package and get going right away. There is a manual on readthedocs that highlights some considerations for different shells (fish, bash, zsh).

(use-package mistty
  :bind ("C-c x m" . mistty))

I’ve bound a key to the primary command, mistty, which starts a terminal or switches to the buffer if already running. Without any customization I’m able to use my custom prompt themes, take advantage of shell history and auto-completion, run terminal applications, and so on.

The misTTY buffer is split into two “zones”:

  • the scrollback zone
  • the terminal zone

This approach allows for a fairly seamless Emacs integration experience. The scrollback zone has your past commands and output. Since this is Emacs, you can navigate/search/etc this text as you would in any other buffer.

The active prompt is the terminal zone, where certain keys need to get sent directly to the underlying terminal. This zone has its own key map (mistty-prompt-map), allowing you to configure keys for terminal interaction when point is at the prompt – but leave those keys working “normally” anywhere else in the misTTY buffer. The default configuration uses M- and C- modifiers in a way that lets you work with terminal applications without losing basic Emacs navigation keys. (Of course, you can customize this to meet your needs).

If you are interested in running a “full terminal” in Emacs, you may already be familiar with vterm. In vterm, terminal interaction takes precedence: you need to explicitly switch modes (vterm-copy-mode) to use your familiar Emacs bindings to search/copy/etc the scrollback text. I like misTTY’s zone approach, which makes working in terminal buffers more consistent with my Emacs workflow. But… vterm wins on performance. It’s use of a compiled C library means vterm is fast.

I would recommend giving misTTY a try. I’m keeping it in my configuration and am interested to see how it evolves over time. It may not compete with vterm on speed, but it takes an interesting approach that might fit your needs.

Update

The author of misTTY has updated the README to note:

MisTTY isn’t a terminal emulator, but rather a frontend to an existing terminal emulator, the built-in term.el. […] In theory, other terminal emulators than term.el might be used as engine for MisTTY, such as vterm and eat.

It would be quite interesting to run misTTY on top of vterm to take advantage of that performance boost.

Protecting Emacs Buffers

A recent thread on Mastadon1 lead me to look at the built-in emacs-lock-mode package. This was added back in Emacs 24.1, but I already had implemented something similar and missed it.2

If you are not familiar with it, emacs-lock-mode allows you to lock a buffer in a couple ways:

  • Prevent the buffer from accidentally being killed.
  • Prevent Emacs from exiting while the buffer is locked.

My old buffer-protect package was written for the first case only. I occasionally would go in to ibuffer to clean up, and might accidentally mark and delete the scratch buffer or some other temporary buffer that had some useful text in it.

The built-in mode lets me drop this custom code and replace it with a little bit of configuration:

(use-package emacs-lock
  :config
  (with-current-buffer "*scratch*"
    (emacs-lock-mode 'kill)))

This locks the scratch buffer to keep it from being killed, but won’t block me from exiting Emacs. You can toggle the lock on any buffer with the command emacs-lock-mode. Use a prefix argument to choose the lock behavior, or customize the variable emacs-lock-default-locking-mode.

This lock mode is also nicely integrated with ibuffer. In my own buffer-protect code I’d had to advise some ibuffer functions to prevent them complaining if a protected buffer happened to be marked for deletion. With the built-in lock mode no such tweaking is needed:

  • Locked buffers are shown in the *IBuffer* list with an L annotation.
  • You can easily toggle the lock state on one or several buffers with L
  • If you happen to mark a locked buffer and try to delete it, ibuffer silently ignores the delete.

I don’t need emacs-lock-mode frequently enough to bind it to a key, but it’s nice to know it is there. And it is always nice to remove custom code from my configuration, particularly when the built-in equivalent is more tightly integrated with other tools like ibuffer.


  1. Thanks to @xenodium. Check out their blog on Emacs and other stuff. ↩︎

  2. For the last few releases, Mickey Petersen over at Mastering Emacs has been publishing an annotated version of the NEWS file with his comments and observations on what has changed. This is an excellent resource, highlighting new features you might have overlooked or implications of a change you might not think of. Check out his recent post on Emacs 29.1↩︎

Emacs Key Binding Tweaks

Key bindings are one of first things a new Emacs user will experiment with. The default key bindings don’t follow recent OS conventions and may seem complicated and hard to remember; so when you discover how easy it is to change them, it may be hard to resist customizing everything. This is of course one of the great things about Emacs: you can and should configure it for your needs.

I’ve dabbled with key bindings over the years1 but have settled on using default bindings for most things. Here are some notable exceptions2.

Replacing defaults with DWIM commands

There are only so many keys available. If you can find one command that does the job of two or three others, based on context, it can free up some keys – and be one less thing to remember. In Emacs circles such commands are often referred to as DWIM (Do What I Mean) commands.

An easy place to start are the case commands. Emacs has separate commands for capitalize-word and capitalize-region, but it also provides capitalize-dwim that can do either depending on whether you have a region selected:

(bind-keys
 ([remap capitalize-word] . capitalize-dwim)
 ([remap upcase-word] . upcase-dwim)
 ([remap downcase-word] . downcase-dwim))

Another DWIM command (for me at least): when I hit C-x k to kill a buffer, I always mean the current one:

(bind-key [remap kill-buffer] 'kill-this-buffer)

There are also some DWIM commands that cycle through possible outcomes rather than trying to guess what you want. This can be very convenient – I usually want the first result, and when I want a variation I don’t have to remember what the other command is:

(bind-key [remap just-one-space] 'cycle-spacing)

Easier key combinations

Some of the default bindings are just hard to type. I use emacsclient to interact with Emacs running as a server, so the server-edit command comes up fairly often in my workflow. The default binding is C-x #, which is fairly straightforward but does require switching modifiers to get that #. A quick fix is to just replace Shift with Control:

(bind-key "C-x C-3" server-edit)

Avoiding prefix keys for common actions

There are some actions in Emacs that are so common that a binding with a prefix (such as C-x o) feels like overhead. In recent versions Emacs has introduced repeat-mode and provided a repeatable binding that simplifies this sort of thing: you can type C-x o o o to switch windows multiple times, without needing the C-x prefix every time. This is a great improvement; but in practice I’m usually just working with two windows and don’t need the repeat.

I’ve adopted M-o for other-window. It’s convenient and not bound by default. I’ve also adopted M-i for the related action of switching buffers in the current window. Emacs has a built-in function for what I want here, but it isn’t bound to anything. (M-i defaults to tab-to-tab-stop, which is something I have never used.) This pair of bindings makes getting to the window and buffer I want fast and easy:

(bind-keys*
 :filter (not (minibufferp))
 ("M-o" . other-window)
 ("M-i" . mode-line-other-buffer))

A couple of notes on this one:

  • I’m using bind-keys* to makes these global bindings that override any mode-specific bindings. Your mileage may vary, but so far I’ve found having these globally consistent more useful then any mode-specific behavior (which I can always rebind anyway).

  • The one exception to the previous point is the minibuffer. Switching buffers makes no sense in the minibuffer; and I don’t often use other-window to switch in and out of the minibuffer, so I can always fall back to C-x o in that situation. There are packages that provide useful minibuffer behavior on these keys by default, so I’ve added a filter here.

One more other-window tweak

I like the ace-link package, which lets you quickly jump to links in a buffer by highlighting available links with a jump target. By default ace-link binds o for this.

The new Emacs repeat behavior can get in the way of that. Let’s say you open a help buffer, e.g. C-h f to get help for some command. You see a useful link so you want to switch windows and then jump to the link:

  • C-x o (or M-o with my bindings) gets you to the help window.

  • o should trigger ace-link to jump to the link… but instead it takes you back to the window you just left.

There are various ways to address this, but I’ve built the habit of using M-o o to do this sort of thing. It’s a very simple key sequence that gets me where I want quickly.

With M-o for other-window I don’t really benefit from its repeat behavior, so let’s drop that as part of configuring ace-link. Easy enough:

(use-package ace-link
  :init
  (ace-link-setup-default)
  ;; Allow for `M-o o' to switch window and jump to link
  (unbind-key "o" other-window-repeat-map))

  1. One customization I stuck with for a long time was binding M-1, M-2, etc. to the window split commands that default to C-x 1, C-x 2, and so on. Having digit-argument bound to both M- and C- prefixes seemed like a waste! I eventually realized the convenience of passing a numeric argument to a command without having to switch modifiers. It’s much faster to type C-3 C-k to delete three lines and M-3 M-f to go forward three words than to mix modifiers.. ↩︎

  2. I am using the bind-key package in these examples, which is built in to Emacs 29.1 and available as an optional package for earlier versions. For a definitive explanation of key bindings, check out the excellent article Mastering Key Bindings in Emacs↩︎

Command-line Tools: Yank

If you spend any time working in a terminal, you’ll find yourself wanting to extract some bit of data from the output of a command. There are lots of ways to accomplish this: you might use cut, or craft a sed or awk expression that pulls out just the part you need.

But sometimes you just want to grab the relevant output and move on to doing something useful with it – without having to stop and think about a regex or count fields. You might reach for the mouse, but for some folks that is a last resort…

I’ve recently come across the terminal utility yank, which is perfect in this situation. Yank provides an interactive selection interface to copy a field from stdin.

What does that mean? You can run something like:

docker ps | yank

and then use your arrow keys (or hjkl) to select the thing you want, such as a container ID. Hit Enter to copy it to the clipboard and go about your work. You can of course pipe your selection to another command:

docker ps | yank | xargs docker kill

And you can specify a delimiter or a pattern if you need to:

env | yank -d =

Check out the project README for more examples. Yank is easy to install on a variety of platforms – give it a try.

Emacs Package: s3ed

The s3ed package provides a convenient way to work directly with S3 files from Emacs. It uses the AWS CLI under the hood to provide a couple of commands to browse S3 buckets and edit files as if they were local.

Here’s an example configuration:

(use-package s3ed 
    :if (executable-find "aws") 
    :bind
    ("C-c s f" . s3ed-find-file) 
    ("C-c s s" . s3ed-save-file))

Update: Handling quit signals

After using this package for a bit, I noticed that sometimes I would get into a state where <backspace> in the minibuffer would raise an error. Checking the key binding, I determined this was caused by s3ed and had to do a little digging.

It turns out the s3ed commands bind their own behavior to <backspace> in the minibuffer-local-map. That binding is removed when the command is done… but not if you change your mind and use C-g (keyboard-quit) to quit the minibuffer without completing the command. In that situation the key binding remains, waiting to cause problems the next time you use the minibuffer.

One way to work around the issue is to handle the quit signal to ensure the key binding is removed. I’ve added this to the use-package example above:

:config
(defun my/s3ed-quit-handler (orig &rest args)
  (condition-case nil
      (apply orig args)
    (quit (define-key minibuffer-local-map (kbd "<backspace>") nil))))
(advice-add #'s3ed-find-file :around #'my/s3ed-quit-handler)
(advice-add #'s3ed-save-file :around #'my/s3ed-quit-handler)

With that everything is working well, and s3ed remains a great utility in my Emacs toolbox.

;; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with \\[find-file] and enter text in its buffer.
@glucas on Mastodon