Zsh on macOS has a tremendous amount of useful keyboard shortcuts enabled by default. It’s a long list, which I wanted to display in the shell in a more compact, readable format than bindkey
provides.
bindkey # list all keybindings
Transforming bindkey output
Here are the steps I took to transform the bindkey
output.
Remove some keys from list
The special keys (up, home, end, etc), which I don’t want to list, are defined with certain character sequences. I’ll use grep -v
to remove lines that match the sequences I want to exclude.
The first sequence to remove—which, I’ll admit, I don’t even really understand—, is ^[[
:
bindkey | grep -v '\^\[\['
That removes six bindings I don’t even understand.
Other special key sequences I want to remove are "^[[OA"
, "^[[OB"
, etc, which can be matched with the regex pattern '\^\[O[A-H]'
, which I add to the first pattern:
bindkey | grep -v - e '\^\[\[' -e '\^\[O[A-H]"'
The -e
flag of grep
is used to specify multiple patterns.
That gets the list down to the bindings I want to include.
Replace some characters
To make it more readable, I want to remove the quotes around the key definitions. The first quote is removed with sed 's/^"//g'
and the second with sed 's/" / /g'
.
bindkey | grep -v -e '\^\[\[' -e '\^\[O[A-H]"' \
| sed -e 's/^"//g' -e 's/" / /g'
The -e
flag can also be used with sed
to specify multiple patterns.
Add one more subsitution, -e 's/\^\[/⌥/g'
, to replace the meta key (^[
) with the option symbol (⌥
):
bindkey | grep -v -e '\^\[\[' -e '\^\[O[A-H]"' \
| sed -e 's/^"//g' -e 's/" / /g' -e 's/\^\[/⌥/g'
Display in columns
The print
command, with the -c
flag, can output the result in columns that fit the terminal. But I need to change the IFS
characters so it doesn’t split spaces into a newlines:
IFS=$'\n'
print -c -- $(bindkey | grep -v -e '\^\[\[' -e '\^\[O[A-H]"' | sed -e 's/^"//g' -e 's/" / /g' -e 's/\^\[/⌥/g')
unset IFS
IFS
returns to its default value when it’s unset
in zsh.
Make into an alias
I wouldn’t have any idea how to quote the above multi-line command, but zsh does.
After running the above command, press the up arrow to place it on the command line again, then press opt' (apostrophe) to quote it. Then, without pressing enter yet, navigate to the beginning of the line ( ctrla) and insert alias bind=
in front. It will end up looking like this syntax nightmare:
alias binds='IFS=$'\''\n'\''
print -c -- $(bindkey | grep -v -e '\''\^\[\['\'' -e '\''\^\[O[A-H]"'\'' | sed -e '\''s/^"//g'\'' -e '\''s/" / /g'\'' -e '\''s/\^\[/⌥/g'\'')
unset IFS'
Then press return to define the alias, which outputs this on my machine:
I’ll assume you know how to save an alias to a config file or can find the answer yourself.
Update: bindlist function
I’ve rewritten the alias as a more much flexible function. Still sort of ugly, but it works.