Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Official plugin manager?

On Sat, Jan 4, 2020 at 1:40 AM dana <dana@xxxxxxx> wrote:
> Actually, if key bindings don't always work well out of the box, and
> especially if we can fix that by simply checking terminfo, shouldn't we do
> that with the default bindings in the shell itself?

If keys such as arrows, home, end and delete just worked, this would be perfect!

My comment presupposed the existing zsh, which requires a few bindkey
commands to make these keys work. The use of terminfo here results in
brittle code. Let me show what I mean.

${terminfo[khome]} expands to the escape sequence for the home key.
Let's try using it:

    autoload -Uz terminfo
    bindkey ${terminfo[khome]} beginning-of-line

Doesn't work. Zsh puts terminal in raw mode (rmkx) when it starts but
${terminfo[khome]} is the escape key for application mode (smkx).
Let's manually switch terminal to application mode.

    echoti smkx

This works. Until we run an application that switches terminal back to
raw mode. To solve this problem we can hook zle-line-init and switch
to application mode from there.

    function zle-line-init () { echoti smkx; }
    zle -N zle-line-init

It's what Debian does. And Oh My Zsh. And Prezto. This works. Until we
source a plugin before setting up bindings and the plugin happens to
hook zle-line-init. Our zle-line-init overrides the plugin's, breaking
it in the process. Let's fix it by calling the plugin's hook from

    zle -A zle-line-init orig-zle-line-init

    function my-zle-line-init () {
      zle orig-zle-line-init
      echoti smkx

    zle -N zle-line-init my-zle-line-init

This works. Until we source a plugin after setting up bindings and the
plugin happens to hook zle-line-init without calling our hook. This
time it's the plugin breaking our code rather than vise versa.

The alternative to this rather complex and brittle approach is to bind
beginning-of-line to several escape sequences.

    bindkey '^[[H' beginning-of-line  # home in raw mode
    bindkey '^[OH' beginning-of-line  # home in app mode

To avoid having to specify bindings several times, we can translate
escape sequences from application mode to their counterparts in raw
mode, and bind all keys as if the terminal was always in raw mode.

    # Translate application mode (smkx) key escape codes,
    # to raw mode (rmkx).
    bindkey -s '^[OH' '^[[H'  # home
    bindkey -s '^[OF' '^[[F'  # end
    # etc

    bindkey '^[[H' beginning-of-line  # home
    bindkey '^[[F' end-of-line  # end
    # etc

The same approach works with terminals of different type:

    # TTY sends different key codes. Translate them to regular.
    bindkey -s '^[[1~' '^[[H'  # home
    bindkey -s '^[[4~' '^[[F'  # end

And NumLock:

    # If NumLock is off, translate keys to make them appear
    # the same as with NumLock on.
    bindkey -s '^[OM' '^M'  # enter
    bindkey -s '^[Ok' '+'
    bindkey -s '^[Om' '-'
    bindkey -s '^[Oj' '*'
    bindkey -s '^[Oo' '/'
    bindkey -s '^[OX' '='

This makes keys such as `/` and `+` on the numpad work in zsh the same
way they work everywhere else.

The downside of such shotgun-type translation is the possibility of
clashes. It's possible in theory that one terminal's escape code for
the home key is another terminal's code for the end key. This can be
dealt with with some conditionals. I don't have any in my own zshrc as
none of the terminals I use produce clashes on any key sequences. I
imagine not everyone is so lucky.

> Obviously we shouldn't go crazy with it, but i don't see any reason to
> specifically limit the use of styles. The style system is an important aspect
> of configuring zsh. There are very useful settings that can only be changed
> that way, and it's important for users to know about it if they want to make
> their own changes.

Oh yeah, I've nothing against styles. I wanted (but failed) to make a
point that the basic config shouldn't attempt to provide the best
possible shell experience at the expense of config complexity. If 12
completion style lines give you only slightly better completion that 2
lines, it may be preferable to go with 2 lines. When the user's
complexity threshold is exceeded by the config, the whole thing
becomes opaque. A slightly worse but simpler config may result in
better long term user experience as the user will be able to customize


Messages sorted by: Reverse Date, Date, Thread, Author