Subject: Re: _history-complete-older problems with $(
From: Bart Schaefer <[email-masked]>
To: Zsh hackers list <[email-masked]>
Date: Mon, 11 Jan 2016 16:15:01 -0800
List-Id: Zsh Workers List <zsh-workers.zsh.org>

On Jan 11,  5:21pm, Sebastian Gniazdowski wrote:
} Subject: Re: _history-complete-older problems with $(
}
} on IRC it came up that $( is a start of a subshell and that it makes
} completion start over at this place. Seems that $(( works in the same
} way. Is there any possibility to change that? Even at level of C code?

The following produces the correct set of completion matches (pardon the
unimaginative name) but is a bit of a hack (it breaks _complete_debug
and _complete_help):

  _widen_for_history () {
    local -a left=( "${(z)LBUFFER}" )
    local right="${words[CURRENT]#${left[-1]}}"
    words=( "${(z)BUFFER}" )
    CURRENT=${#left}
    PREFIX="${left[-1]}"
    IPREFIX=''
    SUFFIX="${right}"
    ISUFFIX=''
    {
      compadd () {
	local -a found
	builtin compadd -O found "$@"
	builtin compadd -Q -U "${(@)${(@)found#$PREFIX}%$SUFFIX}"
      }
      _history
    } always {
      unfunction compadd
    }
  }
  zstyle ':completion:*' completer _widen_for_history _complete

This needs some work around the issue of empty words, i.e., when
completing in empty parens such as $(<TAB>) then $words[CURRENT] is
empty and the trailing paren must be copied from $RBUFFER to SUFFIX.
I haven't dived into that detail.

It could be further refined (with a lot of work) to widen only to the
next "outward" command, e.g., in

  foo $(bar $(<TAB>

to extend back only as far as "bar" rather than to "foo", which might
turn out to be important for some multi-line buffers, I'm not sure.

Another approach would be to create a custom key binding for a widget
which

- inserts an open quote before the current word
- invokes completion with completer style set to _history
- removes quoting again

but that has its own complications if the word on the line is already
quoted, etc.