mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-11 20:48:49 +00:00
Work around terminals that echo DCS queries
Some terminals such as conhost and putty cannot parse DCS commands, and will echo them back. Work around this by making sure that this echoed text will not be visible. Do so by temporarily enabling the alternative screen buffer when sending DCS queries (in this case only XTGETTCAP). The alternative screen buffer feature seems widely supported, and easier to get right than trying to clear individual lines etc. The alternative screen may still be visible for a short time. Luckily we can use [Synchronized Output]( https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036) to make sure the screen change is never visible to the user. Querying support for that is deemed safe since it only requires a CSI command. Note that it seems that every terminal that supports Synchronized Output also parses DCS commands successfully. This means that we could get away without the alternative screen buffer in practice. Not sure yet. The implementation is slightly more complex than necessary in that it defines a redundant ImplicitEvent. This is for two reasons: 1. I have a pending change that wants to use it, so this removes diff noise and 2. we historically have sc/input_common.rs not depend on src/output.rs. I dont' think any are strong reasons though.
This commit is contained in:
parent
e6d57f2fb2
commit
14df28382d
3 changed files with 38 additions and 8 deletions
|
@ -23,8 +23,9 @@ New or improved bindings
|
|||
- :kbd:`ctrl-z` (undo) after executing a command will restore the previous cursor position instead of placing the cursor at the end of the command line.
|
||||
- The OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking.
|
||||
- :kbd:`ctrl-l` no longer clears the screen but only pushes to the terminal's scrollback all text above the prompt (via a new special input function ``scrollback-push``).
|
||||
This feature depends on the terminal advertising via XTGETTCAP support for the ``indn`` and ``cuu`` terminfo capabilities.
|
||||
If not presesnt, the binding falls back to ``clear-screen``.
|
||||
This feature depends on the terminal advertising via XTGETTCAP support for the ``indn`` and ``cuu`` terminfo capabilities,
|
||||
and on the terminal supporting Synchronized Output (which is used by fish to detect features).
|
||||
If any is missing, the binding falls back to ``clear-screen``.
|
||||
|
||||
Completions
|
||||
^^^^^^^^^^^
|
||||
|
|
|
@ -194,6 +194,8 @@ pub enum ImplicitEvent {
|
|||
MouseLeftClickContinuation(ViewportPosition, ViewportPosition),
|
||||
/// Push prompt to top.
|
||||
ScrollbackPushContinuation(usize),
|
||||
/// The Synchronized Output feature is supported by the terminal.
|
||||
SynchronizedOutputSupported,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -957,8 +959,14 @@ pub trait InputEventQueuer {
|
|||
|
||||
let key = match c {
|
||||
b'$' => {
|
||||
// DECRPM
|
||||
if private_mode == Some(b'?') && next_char(self) == b'y' {
|
||||
// DECRPM
|
||||
if params[0][0] == 2026 && matches!(params[1][0], 1 | 2) {
|
||||
self.push_front(CharEvent::Implicit(
|
||||
ImplicitEvent::SynchronizedOutputSupported,
|
||||
));
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
match params[0][0] {
|
||||
|
|
|
@ -2098,11 +2098,8 @@ impl<'a> Reader<'a> {
|
|||
let _ = out.write(KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY);
|
||||
// Query for cursor position reporting support.
|
||||
zelf.request_cursor_position(&mut out, CursorPositionWait::InitialFeatureProbe);
|
||||
let mut xtgettcap = |cap| {
|
||||
let _ = write!(&mut out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
||||
};
|
||||
xtgettcap("indn");
|
||||
xtgettcap("cuu");
|
||||
// Query for synchronized output support.
|
||||
let _ = out.write(b"\x1b[?2026$p");
|
||||
out.end_buffering();
|
||||
}
|
||||
|
||||
|
@ -2422,12 +2419,36 @@ impl<'a> Reader<'a> {
|
|||
self.screen.push_to_scrollback(cursor_y);
|
||||
self.stop_waiting_for_cursor_position();
|
||||
}
|
||||
ImplicitEvent::SynchronizedOutputSupported => {
|
||||
synchronized_supported();
|
||||
}
|
||||
},
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
fn xtgettcap(out: &mut impl Write, cap: &str) {
|
||||
let _ = write!(out, "\x1bP+q{}\x1b\\", DisplayAsHex(cap));
|
||||
}
|
||||
|
||||
fn synchronized_supported() {
|
||||
static QUERIED: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
|
||||
if QUERIED.load() {
|
||||
return;
|
||||
}
|
||||
QUERIED.store(true);
|
||||
let mut out = Outputter::stdoutput().borrow_mut();
|
||||
out.begin_buffering();
|
||||
let _ = out.write(b"\x1b[?2026h"); // begin synchronized update
|
||||
let _ = out.write(b"\x1b[?1049h"); // enable alternative screen buffer
|
||||
xtgettcap(out.by_ref(), "indn");
|
||||
xtgettcap(out.by_ref(), "cuu");
|
||||
let _ = out.write(b"\x1b[?1049l"); // disable alternative screen buffer
|
||||
let _ = out.write(b"\x1b[?2026l"); // end synchronized update
|
||||
out.end_buffering();
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
// Convenience cover to return the length of the command line.
|
||||
fn command_line_len(&self) -> usize {
|
||||
|
|
Loading…
Reference in a new issue