zshoh-my-zshzsh-zle

zle backward-char not working as expected


I'm writing a simple ZLE widget to quickly create subshells with <C-j>. Here's what I have:

function zle_subshell {
  zle -U '$()'
  zle .backward-char
}

# register as widget
zle -N zle_subshell

# create kbd
bindkey '^j' zle_subshell

However, it appears that zle .backward-char isn't working. What makes matters more confusing is that if I modify the script to be:

function zle_subshell {
  zle -U '$('
  zle -U ')'
  zle .backward-char
}

I get output like )$(...

It appears that zle_subshell function is being evaluated in reverse. Are there some obvious gotchas with ZLE widgets that I'm unaware of?


Solution

  • The zle -U usage is the pecial case. It seems that the behavior is intended:

    zle -U string
    ...
    This pushes the characters in the string onto the input stack of ZLE. After the widget currently executed finishes ZLE will behave as if the characters in the string were typed by the user.

    As ZLE uses a stack, if this option is used repeatedly the last string pushed onto the stack will be processed first. However, the characters in each string will be processed in the order in which they appear in the string.

    -- zshzle(1), ZLE BUILTINS, zle -U

    So, zsh will behave as if ) and $( were typed after the zle_subshell finishes.

    We could modify the (R)BUFFER to change the editor buffer directly like this:

    function zle_subshell {
      RBUFFER='$()'"$RBUFFER"
      repeat 2 do zle .forward-char; done
      # ((CURSOR=CURSOR+2)) # We could do this instead.
    }