zsh-workers
 help / color / mirror / code / Atom feed
From: Daniel Shahaf <d.s@daniel.shahaf.name>
To: Linus Kardell <linus.kardell@gmail.com>
Cc: zsh-workers@zsh.org
Subject: Re: KEYBOARD_HACK breaks with escaped quotes
Date: Mon, 29 Mar 2021 12:30:57 +0000	[thread overview]
Message-ID: <20210329123057.GQ18178@tarpaulin.shahaf.local2> (raw)
In-Reply-To: <1fef65c9-6680-b17a-98e8-c67572778f7f@gmail.com>

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


      reply	other threads:[~2021-03-29 12:31 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-07 10:23 Linus Kardell
2021-03-29 12:30 ` Daniel Shahaf [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210329123057.GQ18178@tarpaulin.shahaf.local2 \
    --to=d.s@daniel.shahaf.name \
    --cc=linus.kardell@gmail.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).