diff --git a/src/reader.cpp b/src/reader.cpp index d07af18a9..b361cccfc 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -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: { diff --git a/tests/pexpects/complete.py b/tests/pexpects/complete.py index 0324c365e..6815bb657 100644 --- a/tests/pexpects/complete.py +++ b/tests/pexpects/complete.py @@ -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")