Let cancel after an unambiguous completion was accepted undo it

In some cases the completion we come up with may be unexpected, e.g.
if you have files like

/etc/realfile

and

/etc/wrongfile

and enter "/etc/gile", it will accept "wrongfile" because "g" and
"ile" are in there - it's a substring insertion match.

The underlying cause was a typo, so it should be easy to go back.

So we do a bit of magic and let "cancel" undo, but only right after a
completion was accepted via complete or complete-and-search.

That means that just reflexively pressing escape would, by default, get you back to
the old token and let you fix your mistake.

We don't do this when the completion was accepted via the pager,
because 1. there's more of a chance to see the problem there and 2.
it's harder to redo in that case.

Fixes #7433.
This commit is contained in:
Fabian Homborg 2020-10-30 19:29:46 +01:00
parent 4b74fbf1b7
commit d334dc6643
2 changed files with 35 additions and 1 deletions

View file

@ -2790,7 +2790,19 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
break;
}
case rl::cancel: {
// The only thing we can cancel right now is paging, which we handled up above.
// If we last inserted a completion, undo it.
// This doesn't apply if the completion was selected via the pager
// (in which case the last command is "execute" or similar,
// but never complete{,_and_search})
//
// Also paging is already cancelled above.
if (rls.complete_did_insert &&
(rls.last_cmd == rl::complete
|| rls.last_cmd == rl::complete_and_search)) {
editable_line_t *el = active_edit_line();
el->undo();
update_buff_pos(el);
}
break;
}
case rl::repaint_mode: {

View file

@ -13,6 +13,8 @@ expect_prompt()
sendline(
"""
# Make sure this function does nothing
function my_is; :; end
complete -c my_is -n 'test (count (commandline -opc)) = 1' -xa arg
complete -c my_is -n '__fish_seen_subcommand_from not' -xa '(
set -l cmd (commandline -opc) (commandline -ct)
@ -26,3 +28,23 @@ sendline(
send("my_is not \t")
send("still.alive")
expect_re(".*still.alive")
sendline("")
# Check cancelling completion acceptance
# (bind cancel to something else so we don't have to mess with the escape delay)
sendline("bind \cg cancel")
sendline("complete -c echo -x -a 'foooo bar'")
send("echo fo\t")
send("\x07")
sendline("bar")
expect_re("bar")
sendline("echo fo\t")
expect_re("foooo")
# As soon as something after the "complete" happened,
# cancel should not undo.
# In this case that's the space after the tab!
send("echo fo\t ")
send("\x07")
sendline("bar")
expect_re("foooo bar")