Control-C to simply clear commandline buffer again

Commit 5f849d0 changed control-C to print an inverted ^C and then a newline.

The original motivation was

> In bash if you type something and press ctrl-c then the content of the line
> is preserved and the cursor is moved to a new line. In fish the ctrl-c just
> clears the line. For me the behaviour of bash is a bit better, because it
> allows me to type something then press ctrl-c and I have the typed string
> in the log for further reference.

This sounds like a valid use case in some scenarios but I think that most
abandoned commands are noise. After all, the user erased them. Also, now that
we have undo that can be used to get back a limited set of canceled commands.

I believe the original motivation for existing behavior (in other shells) was
that TERM=dumb does not support erasing characters. Similarly, other shells
like to leave behind other artifacts, for example when using tab-completion
or in their interactive menus but we generally don't.

Control-C is the obvious way to quickly clear a multi-line commandline.
IPython does the same. For the other behavior we have Alt-# although that's
probably not very well-known.

Restore the old Control-C behavior of simply clearing the command line.

Our unused __fish_cancel_commandline still prints the ^C. For folks who
have explicitly bound ^C to that, it's probably better to keep the existing
behavior, so let's leave this one.

Previous attempt at #4713 fizzled.

Closes #10213
This commit is contained in:
Johannes Altmanninger 2023-12-28 14:41:30 +01:00
parent 5389d84285
commit fff8e8163b
3 changed files with 11 additions and 32 deletions

View file

@ -30,6 +30,7 @@ Scripting improvements
Interactive improvements Interactive improvements
------------------------ ------------------------
- :kbd:`Control-C` during command input no longer prints ``^C`` and a new prompt but merely clears the command line. This restores the behavior from version 2.2. To revert to the old behavior use ``bind \cc __fish_cancel_commandline`` (:issue:`10213`).
- Command-specific tab completions may now offer results whose first character is a period. For example, it is now possible to tab-complete ``git add`` for files with leading periods. The default file completions hide these files, unless the token itself has a leading period (:issue:`3707`). - Command-specific tab completions may now offer results whose first character is a period. For example, it is now possible to tab-complete ``git add`` for files with leading periods. The default file completions hide these files, unless the token itself has a leading period (:issue:`3707`).
- The :kbd:`Control-R` history search now uses glob syntax (:issue:`10131`). - The :kbd:`Control-R` history search now uses glob syntax (:issue:`10131`).

View file

@ -72,7 +72,7 @@ use crate::io::IoChain;
use crate::kill::{kill_add, kill_replace, kill_yank, kill_yank_rotate}; use crate::kill::{kill_add, kill_replace, kill_yank, kill_yank_rotate};
use crate::libc::MB_CUR_MAX; use crate::libc::MB_CUR_MAX;
use crate::operation_context::{get_bg_context, OperationContext}; use crate::operation_context::{get_bg_context, OperationContext};
use crate::output::{parse_color, Outputter}; use crate::output::Outputter;
use crate::pager::{PageRendering, Pager, SelectionMotion}; use crate::pager::{PageRendering, Pager, SelectionMotion};
use crate::parse_constants::SourceRange; use crate::parse_constants::SourceRange;
use crate::parse_constants::{ParseTreeFlags, ParserTestErrorBits}; use crate::parse_constants::{ParseTreeFlags, ParserTestErrorBits};
@ -2060,35 +2060,10 @@ impl ReaderData {
if self.command_line.is_empty() { if self.command_line.is_empty() {
return; return;
} }
let outp = Outputter::stdoutput().get_mut(); self.push_edit(
// Move cursor to the end of the line.
let end = self.command_line.len();
self.update_buff_pos(EditableLineTag::Commandline, Some(end));
self.autosuggestion.clear();
// Repaint also changes the actual cursor position
if self.is_repaint_needed(None) {
self.layout_and_repaint(L!("cancel"));
}
if let Some(fish_color_cancel) = self.vars().get(L!("fish_color_cancel")) {
outp.set_color(
parse_color(&fish_color_cancel, false),
parse_color(&fish_color_cancel, true),
);
}
outp.write_wstr(L!("^C"));
outp.set_color(RgbColor::RESET, RgbColor::RESET);
// We print a newline last so the prompt_sp hack doesn't get us.
outp.push(b'\n');
self.set_command_line_and_position(
EditableLineTag::Commandline, EditableLineTag::Commandline,
L!("").to_owned(), Edit::new(0..self.command_line.len(), L!("").to_owned()),
0,
); );
self.screen
.reset_abandoning_line(usize::try_from(termsize_last().width).unwrap());
// Post fish_cancel. // Post fish_cancel.
event::fire_generic(self.parser(), L!("fish_cancel").to_owned(), vec![]); event::fire_generic(self.parser(), L!("fish_cancel").to_owned(), vec![]);

View file

@ -27,13 +27,16 @@ if "CI" in os.environ:
send("not executed") send("not executed")
sleep(timeout) sleep(timeout)
os.kill(sp.spawn.pid, signal.SIGINT) os.kill(sp.spawn.pid, signal.SIGINT)
sp.expect_str("not executed^C") sendline("echo marker")
expect_prompt(increment=False) sp.expect_str("marker")
expect_prompt()
sendline("function cancelhandler --on-event fish_cancel ; echo yay cancelled ; end") sendline("function cancelhandler --on-event fish_cancel ; echo yay cancelled ; end")
expect_prompt() expect_prompt()
send("still not executed") send("still not executed")
sleep(timeout) sleep(timeout)
os.kill(sp.spawn.pid, signal.SIGINT) os.kill(sp.spawn.pid, signal.SIGINT)
expect_str("still not executed^C") expect_str("yay cancelled")
expect_prompt("yay cancelled", increment=False) sendline("echo marker")
sp.expect_str("marker")
expect_prompt()