åØē»ē«Æč¾å „ęę¬ē«ē¶å¦ę¤å¤ę
Source: Julia Evans
The other day I asked what folks on Mastodon find confusing about working in the terminal, and one thing that stood out to me was āediting a command you already typed inā.
This really resonated with me: even though entering some text and editing it is
a very ābasicā task, it took me maybe 15 years of using the terminal every
single day to get used to using Ctrl+A to go to the beginning of the line (or
Ctrl+E for the end ā I think I used Home/End instead).
So letās talk about why entering text might be hard! Iāll also share a few tips that I wish Iād learned earlier.
itās very inconsistent between programs
A big part of what makes entering text in the terminal hard is the inconsistency between how different programs handle entering text. For example:
- some programs (
cat,nc,git commit --interactive, etc) donāt support using arrow keys at all: if you press arrow keys, youāll just see^[[D^[[D^[[C^[[C^ - many programs (like
irb,python3on a Linux machine and many many more) use thereadlinelibrary, which gives you a lot of basic functionality (history, arrow keys, etc) - some programs (like
/usr/bin/python3on my Mac) do support very basic features like arrow keys, but not other features likeCtrl+leftor reverse searching withCtrl+R - some programs (like the
fishshell oripython3ormicroorvim) have their own fancy system for accepting input which is totally custom
So thereās a lot of variation! Letās talk about each of those a little more.
mode 1: the baseline
First, thereās āthe baselineā ā what happens if a program just accepts text by
calling fgets() or whatever and doing absolutely nothing else to provide a
nicer experience. Hereās what using these tools typically looks for me ā If I
start the version of dash installed on
my machine (a pretty minimal shell) press the left arrow keys, it just prints
^[[D to the terminal.
$ ls l-^[[D^[[D^[[D
At first it doesnāt seem like all of these ābaselineā tools have much in common, but there are actually a few features that you get for free just from your terminal, without the program needing to do anything special at all.
The things you get for free are:
- typing in text, obviously
- backspace
Ctrl+W, to delete the previous wordCtrl+U, to delete the whole line- a few other things unrelated to text editing (like
Ctrl+Cto interrupt the process,Ctrl+Zto suspend, etc)
This is not great, but it means that if you want to delete a word you
generally can do it with Ctrl+W instead of pressing backspace 15 times, even
if youāre in an environment which is offering you absolutely zero features.
You can get a list of all the ctrl codes that your terminal supports with stty -a.
mode 2: tools that use readline
The next group is tools that use readline! Readline is a GNU library to make entering text more pleasant, and itās very widely used.
My favourite readline keyboard shortcuts are:
Ctrl+E(orEnd) to go to the end of the lineCtrl+A(orHome) to go to the beginning of the lineCtrl+left/right arrowto go back/forward 1 word- up arrow to go back to the previous command
Ctrl+Rto search your history
And you can use Ctrl+W / Ctrl+U from the ābaselineā list, though Ctrl+U
deletes from the cursor to the beginning of the line instead of deleting the
whole line. I think Ctrl+W might also have a slightly different definition of
what a āwordā is.
There are a lot more (hereās a full list), but those are the only ones that I personally use.
The bash shell is probably the most famous readline user (when you use
Ctrl+R to search your history in bash, that feature actually comes from
readline), but there are TONS of programs that use it ā for example psql,
irb, python3, etc.
tip: you can make ANYTHING use readline with rlwrap
One of my absolute favourite things is that if you have a program like nc
without readline support, you can just run rlwrap nc to turn it into a
program with readline support!
This is incredible and makes a lot of tools that are borderline unusable MUCH more pleasant to use. You can even apparently set up rlwrap to include your own custom autocompletions, though Iāve never tried that.
some reasons tools might not use readline
I think reasons tools might not use readline might include:
- the program is very simple (like
catornc) and maybe the maintainers donāt want to bring in a relatively large dependency - license reasons, if the programās license is not GPL-compatible ā readline is GPL-licensed, not LGPL
- only a very small part of the program is interactive, and maybe readline
support isnāt seen as important. For example
githas a few interactive features (likegit add -p), but not very many, and usually youāre just typing a single character likeyornā most of the time you need to really type something significant in git, itāll drop you into a text editor instead.
For example idris2 says they donāt use readline
to keep dependencies minimal and suggest using rlwrap to get better
interactive features.
how to know if youāre using readline
The simplest test I can think of is to press Ctrl+R, and if you see:
(reverse-i-search)`':
then youāre probably using readline. This obviously isnāt a guarantee (some
other library could use the term reverse-i-search too!), but I donāt know of
another system that uses that specific term to refer to searching history.
the readline keybindings come from Emacs
Because Iām a vim user, It took me a very long time to understand where these
keybindings come from (why Ctrl+A to go to the beginning of a line??? so
weird!)
My understanding is these keybindings actually come from Emacs ā Ctrl+A and
Ctrl+E do the same thing in Emacs as they do in Readline and I assume the
other keyboard shortcuts mostly do as well, though I tried out Ctrl+W and
Ctrl+U in Emacs and they donāt do the same thing as they do in the terminal
so I guess there are some differences.
Thereās some more history of the Readline project here.
mode 3: another input library (like libedit)
On my Mac laptop, /usr/bin/python3 is in a weird middle ground where it
supports some readline features (for example the arrow keys), but not the
other ones. For example when I press Ctrl+left arrow, it prints out ;5D,
like this:
$ python3
>>> importt subprocess;5D
Folks on Mastodon helped me figure out that this is because in the default
Python install on Mac OS, the Python readline module is actually backed by
libedit, which is a similar library which has fewer features, presumably
because Readline is GPL licensed.
Hereās how I was eventually able to figure out that Python was using libedit on my system:
$ python3 -c "import readline; print(readline.__doc__)"
Importing this module enables command line editing using libedit readline.
Generally Python uses readline though if you install it on Linux or through Homebrew. Itās just that the specific version that Apple includes on their systems doesnāt have readline. Also Python 3.13 is going to remove the readline dependency in favour of a custom library, so āPython uses readlineā wonāt be true in the future.
I assume that there are more programs on my Mac that use libedit but I havenāt looked into it.
mode 4: something custom
The last group of programs is programs that have their own custom (and sometimes much fancier!) system for editing text. This includes:
- most terminal text editors (nano, micro, vim, emacs, etc)
- some shells (like fish), for example it seems like fish supports
Ctrl+Zfor undo when typing in a command. Zshās line editor is called zle. - some REPLs (like
ipython), for example IPython uses the prompt_toolkit library instead of readline - lots of other programs (like
atuin)
Some features you might see are:
- better autocomplete which is more customized to the tool
- nicer history management (for example with syntax highlighting) than the default you get from readline
- more keyboard shortcuts
custom input systems are often readline-inspired
I went looking at how Atuin (a wonderful tool for searching your shell history that I started using recently) handles text input. Looking at the code and some of the discussion around it, their implementation is custom but itās inspired by readline, which makes sense to me ā a lot of users are used to those keybindings, and itās convenient for them to work even though atuin doesnāt use readline.
prompt_toolkit (the library IPython uses) is similar ā it actually supports a lot of options (including vi-like keybindings), but the default is to support the readline-style keybindings.
This is like how you see a lot of programs which support very basic vim
keybindings (like j for down and k for up). For example Fastmail supports
j and k even though most of its other keybindings donāt have much
relationship to vim.
I assume that most āreadline-inspiredā custom input systems have various subtle incompatibilities with readline, but this doesnāt really bother me at all personally because Iām extremely ignorant of most of readlineās features. I only use maybe 5 keyboard shortcuts, so as long as they support the 5 basic commands I know (which they always do!) I feel pretty comfortable. And usually these custom systems have much better autocomplete than youād get from just using readline, so generally I prefer them over readline.
lots of shells support vi keybindings
Bash, zsh, and fish all have a āvi modeā for entering text. In a very unscientific poll I ran on Mastodon, 12% of people said they use it, so it seems pretty popular.
Readline also has a āvi modeā (which is how Bashās support for it works), so by extension lots of other programs have it too.
Iāve always thought that vi mode seems really cool, but for some reason even though Iām a vim user itās never stuck for me.
understanding what situation youāre in really helps
Iāve spent a lot of my life being confused about why a command line application I was using wasnāt behaving the way I wanted, and it feels good to be able to more or less understand whatās going on.
I think this is roughly my mental flowchart when Iām entering text at a command line prompt:
- Do the arrow keys not work? Probably thereās no input system at all, but at
least I can use
Ctrl+WandCtrl+U, and I canrlwrapthe tool if I want more features. - Does
Ctrl+Rprintreverse-i-search? Probably itās readline, so I can use all of the readline shortcuts Iām used to, and I know I can get some basic history and press up arrow to get the previous command. - Does
Ctrl+Rdo something else? This is probably some custom input library: itāll probably act more or less like readline, and I can check the documentation if I really want to know how it works.
Being able to diagnose whatās going on like this makes the command line feel a more predictable and less chaotic.
some things this post left out
There are lots more complications related to entering text that we didnāt talk about at all here, like:
- issues related to ssh / tmux / etc
- the
TERMenvironment variable - how different terminals (gnome terminal, iTerm, xterm, etc) have different kinds of support for copying/pasting text
- unicode
- probably a lot more