Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH and Re: simulation of dabbrev-expand
- X-seq: zsh-workers 8028
- From: Adam Spiers <adam@xxxxxxxxxxxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxx
- Subject: PATCH and Re: simulation of dabbrev-expand
- Date: Thu, 23 Sep 1999 14:44:53 +0100
- In-reply-to: <199909230838.KAA23316@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
- Mail-followup-to: zsh-workers@xxxxxxxxxxxxxx
- Mailing-list: contact zsh-workers-help@xxxxxxxxxxxxxx; run by ezmlm
- References: <199909230838.KAA23316@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
- Reply-to: Adam Spiers <adam@xxxxxxxxxx>
Sven Wischnowsky (wischnow@xxxxxxxxxxxxxxxxxxxxxxx) wrote:
>
> First: there was a buglet in `_history_complete_word' which made it
> pretty useless if `history_stop' wasn't set. I hope the patch below
> doesn't interfere with your work...
Nope -- I ended up rewriting the whole damn thing :-)
> Adam Spiers wrote:
> > The current situation is that _history_complete_word crawls through
> > matching history words, oldest first.
>
> Now I'm confused. For me it works from the bottom up.
Of course I was talking rubbish again here ... but I'm sure you had
realised that and were just being polite :-)
> *But* words
> from the same line are inserted left-to-right. Since the C-code walks
> up maybe we should add the words from the end of the line to the
> beginning.
>
> We should then use the hunk for `zle_tricky.c' below.
Nice touch. Reminds me of another feature I've wanted in
_history_complete_word for ages - would it be possible to modify
compgen -H to include words from the currently edited line?
> > However, I got stuck when handling the history_stop feature.
> > When in verbose mode, history_stop uses _message to indicate that the
> > beginning/end of the history has been reached. However, unless I've
> > got things really wrong, _message seems to destroy any old list of matches
> > which you might want to keep. I can't understand why, as it's only
> > essentially a compadd -X ... -n ''.
>
> That's right. To be able to display the message we have to add a dummy
> completion (that empty string) and throw away the old list.
Hmm. I'm still puzzled why compadd -X ... -n '' throws away the old
list though, since compwidget == lastcompwidget and
compstate[old_list] is set to keep.
> > so that if you hit the oldest match and press M-/ again, it displays
> > this message but keeps the oldest match (should I need a
> > compstate[insert]=1 again, or is it enough to have done that the first
> > time the oldest match was displayed?), and if you switch to M-, it
> > will keep this old_list again and start moving in the opposite
> > direction.
>
> If I were to implement that, I would use two (global) parameters set
> when the end is reached with `verbose' (or always when the end is
> reached). Any of the two ends, that is. The first parameter just says
> that the end was reached (and could say which end if that is
> needed). The other one would contain the value of `BUFFER' at the time
> the end was reached. Now if you invoke the widget for the other
> direction when an end was reached (the first parameter sayeth so), you
> compare the second parameter with the current value of `BUFFER'. If
> they are equal, the thing was just invoked (hm, maybe we shouldn't
> compare `BUFFER', maybe we should check `LASTWIDGET'; or both; and if
> you use the numeric argument thing, the latter may also need to have
> to take that into its calculation). Anyway, the test would say that we
> just reached one of the ends by the history_complete function for the
> other direction and if we find that out, we just call completion again
> (that `compgen') and then use `compstate[insert]=-1' (or `...=1' for
> the other direction). Getting words to complete from the history
> should be fast enough so that the user doesn't really notice that a
> new list was created. For this we would also have to keep the original
> values of `PREFIX' and `SUFFIX' -- and set them anew in the right
> place.
Yep, a similar approach had occurred to me after my last post on the
subject.
> Anyway, I think it can be done...
It can and it has :-) Here's a full replacement for
Completion/Commands/_history_complete_word.
-------- 8< -------- 8< --------
#compdef -k complete-word \e/ \e,
#
# Complete words from the history
#
# by Adam Spiers, with help gratefully received from
# Sven Wischnowsky and Bart Schaefer
#
# Available configuration keys:
#
# history_list -- display lists of available matches
# history_stop -- prevent looping at beginning and end of matches
# during menu-completion
# history_sort -- sort matches lexically (default is to sort by age)
# history_remove_all_dups --
# remove /all/ duplicate matches rather than just
# consecutives
#
_history_complete_word () {
local expl direction
case "$KEYS" in
',') direction='newer'
;;
'/') direction='older'
;;
*) print <<EOF
The keypress \`$KEYS\' was not understood by _history_complete_word.
You must alter _history_complete_word if you want to bind it to keys
other than the defaults, so that it knows which direction the key
should move in the history.
EOF
return 1
esac
[[ -z "$compconfig[history_list]" ]] && compstate[list]=''
if [[ -n "$compstate[old_list]" && -n "$compconfig[history_stop]" ]]; then
# array of matches is newest -> oldest (reverse of history order)
if [[ "$direction" == 'older' ]]; then
if [[ compstate[old_insert] -eq $_hist_menu_length ||
"$_hist_stop" == 'oldest' ]]; then
_hist_stop='oldest'
[[ "$compconfig[history_stop]" = verbose ]] &&
_message 'beginning of history reached'
elif [[ "$_hist_stop" == 'newest' ]]; then
zle -Rc
_history_complete_word_gen_matches
else
compstate[old_list]=keep
(( compstate[insert] = compstate[old_insert] + 1 ))
fi
elif [[ "$direction" == 'newer' ]]; then
if [[ compstate[old_insert] -eq 1 || "$_hist_stop" == 'newest' ]]; then
_hist_stop='newest'
[[ "$compconfig[history_stop]" = verbose ]] &&
_message 'end of history reached'
elif [[ "$_hist_stop" == 'oldest' ]]; then
zle -Rc
_history_complete_word_gen_matches
else
compstate[old_list]=keep
(( compstate[insert] = compstate[old_insert] - 1 ))
fi
fi
else
_hist_stop=''
_hist_old_prefix="$PREFIX"
_history_complete_word_gen_matches
fi
[[ -n "$compstate[nmatches]" ]]
}
_history_complete_word_gen_matches () {
if [[ -n "$compconfig[history_list]" ]]; then
if [[ -n "$compconfig[history_sort]" ]]; then
_description expl 'history word'
else
_description -V expl 'history word'
fi
else
if [[ -n "$compconfig[history_sort]" ]]; then
expl=()
else
expl=('-V' '')
fi
fi
[[ -n "$_hist_stop" ]] && PREFIX="$_hist_old_prefix"
local rem_dups
if [[ -n "$compconfig[history_remove_all_dups]" ]]; then
rem_dups=''
else
rem_dups='-1'
fi
compgen "$expl[@]" $rem_dups -Q -H 0 ''
_hist_menu_length="$compstate[nmatches]"
case "$direction" in
newer) compstate[insert]=$_hist_menu_length
[[ -n "$_hist_stop" ]] && (( compstate[insert]-- ))
;;
older) compstate[insert]=1
[[ -n "$_hist_stop" ]] && (( compstate[insert]++ ))
;;
esac
[[ -n "$_hist_stop" ]] && _hist_stop=''
}
_history_complete_word "$@"
-------- 8< -------- 8< --------
Please have a play with the different options and see how robust it is
(not very, probably!) Known problems:
- Doesn't cope with numeric arguments yet.
- Whenever duplicates get removed, it breaks. It looks like
compstate[nmatches] corresponds with the number of matches
/including/ duplicates, even if some/all duplicates have been
removed.
- The error message given when unknown keys are bound to the
widget doesn't work. Should I be using zle -R here?
> I hope it helped.
It did. Thanks!
Messages sorted by:
Reverse Date,
Date,
Thread,
Author