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:

screenshot -  output of alias: binds
screenshot - output of alias: binds

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.

Categories:

Published:    |    Updated: