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

Re: KEYBOARD_HACK breaks with escaped quotes



Linus Kardell wrote on Sun, Mar 07, 2021 at 11:23:40 +0100:
> So, zsh has the KEYBOARD_HACK option as an anti-annoyance feature, which
> removes a trailing quote character in case you accidentally hit it along
> with enter. However, this naively looks at whether there is an odd number of
> quotes at the command line, which causes it to invert when you have (and odd
> number of) escaped quotes, removing the trailing quote when it shouldn't and
> vice versa. For example, if you write 'test'\''test' or 'test'"'"'test''
> with this enabled, zsh will inapropriately remove the trailing quotes,
> whereas if you write echo 'test'\''test'' it will not remove the trailing
> quote. Instead, zsh needs to more smartly check whether the quoting is
> unbalanced and if removing the trailing quote would make it balanced.

In the general case, determining whether the end of the line is outside
quotes requires knowing the previous lines (because quoted strings can
contain literal newlines).

SUN_KEYBOARD_HACK is implemented in inputline(); it is not part of the
lexer but a black box the lexer uses.  Therefore, I suspect that
function can't easily answer the above question.

Even answering that question for a single line would essentially require
lexing the line — whether using lex.c, using get_comp_string()/addx(),
or using bufferwords().  That's not impossible, but it'll be a lot
easier to unset SUN_KEYBOARD_HACK and reimplement it as a zle widget,
perhaps using ${(z)} and the concept of addx():

accept-line() {
  BUFFER+=' x'
  {
    local buf=$PREBUFFER$BUFFER
    if [[ -o INTERACTIVE_COMMENTS ]]; then
      local -a split=( ${(zZ+C+)buf} )
    else
      local -a split=( ${(z)buf} )
    fi
  } always {
    BUFFER=${BUFFER% x}
  }
  if [[ ${split[-1]} == x ]]; then
    …
  fi
  zle .$WIDGET -- "$@"
}

You might want to use LBUFFER rather than BUFFER.

Incidentally, we might want to invent a syntax that applies Z+C+ iff
INTERACTIVE_COMMENTS is set — say, ${(zZ+CC+)} could mean that, to avoid
using up a fourth option letter in the Z+…+ context ;-)

Sorry for the late answer.

Daniel




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