From 6900b89c82bd2adee29062b7d74d07dc0e64dadf Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 27 Aug 2025 09:13:27 +0200 Subject: [PATCH] Add mark-prompt feature flag So far, terminals that fail to parse OSC sequences are the only reason for wanting to turn off OSC 133. Let's allow to work around it by adding a feature flag (which is implied to be temporary). To use it, run this once, and restart fish: set -Ua fish_features no-mark-prompt Tested with fish -i | string escape | grep 133 && ! fish_features=no-mark-prompt fish -i | string escape | grep 133 See #11749 Also #11609 --- CHANGELOG.rst | 2 ++ src/future_feature_flags.rs | 12 ++++++++++++ src/reader.rs | 31 ++++++++++++++++++------------- src/screen.rs | 8 ++++++-- tests/checks/status.fish | 1 + 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 00691d461..ad2fc69ce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -32,6 +32,8 @@ This release of fish fixes a number of issues identified in fish 4.0.2: - The routines to save history and universal variables have seen some robustness improvements. - Vi mode: The cursor position after pasting via :kbd:`p` has been corrected. - Vi mode: Trying to replace the last character via :kbd:`r` no longer replaces the last-but-one character (:issue:`11484`), +- To work around terminals that fail to parse OSC sequences, a temporary feature flag has been added. + It allows you to disable prompt marking (OSC 133) by running (once) ``set -Ua fish_features no-mark-prompt" and restarting fish (:issue:`11749`). fish 4.0.2 (released April 20, 2025) ==================================== diff --git a/src/future_feature_flags.rs b/src/future_feature_flags.rs index 38000e38a..dbef7638b 100644 --- a/src/future_feature_flags.rs +++ b/src/future_feature_flags.rs @@ -30,6 +30,9 @@ pub enum FeatureFlag { /// Whether keyboard protocols (kitty's CSI x u, xterm's modifyOtherKeys) are used keyboard_protocols, + + /// Whether to write OSC 133 prompt markers + mark_prompt, } struct Features { @@ -118,6 +121,14 @@ pub struct FeatureMetadata { default_value: true, read_only: false, }, + FeatureMetadata { + flag: FeatureFlag::mark_prompt, + name: L!("mark-prompt"), + groups: L!("4.0"), + description: L!("Write OSC 133 prompt markers to the terminal"), + default_value: true, + read_only: false, + }, ]; thread_local!( @@ -180,6 +191,7 @@ const fn new() -> Self { AtomicBool::new(METADATA[4].default_value), AtomicBool::new(METADATA[5].default_value), AtomicBool::new(METADATA[6].default_value), + AtomicBool::new(METADATA[7].default_value), ], } } diff --git a/src/reader.rs b/src/reader.rs index 496982ad3..783aaa1b2 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -66,6 +66,7 @@ use crate::flog::{FLOG, FLOGF}; #[allow(unused_imports)] use crate::future::IsSomeAnd; +use crate::future_feature_flags::{feature_test, FeatureFlag}; use crate::global_safety::RelaxedAtomicBool; use crate::highlight::{ autosuggest_validate_from_history, highlight_shell, HighlightRole, HighlightSpec, @@ -664,13 +665,15 @@ fn read_i(parser: &Parser) -> i32 { data.command_line.clear(); data.update_buff_pos(EditableLineTag::Commandline, None); data.command_line_changed(EditableLineTag::Commandline); - // OSC 133 "Command start" - write!( - BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()), - "\x1b]133;C;cmdline_url={}\x07", - escape_string(&command, EscapeStringStyle::Url), - ) - .unwrap(); + if feature_test(FeatureFlag::mark_prompt) { + // OSC 133 "Command start" + write!( + BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()), + "\x1b]133;C;cmdline_url={}\x07", + escape_string(&command, EscapeStringStyle::Url), + ) + .unwrap(); + } event::fire_generic(parser, L!("fish_preexec").to_owned(), vec![command.clone()]); let eval_res = reader_run_command(parser, &command); signal_clear_cancel(); @@ -683,12 +686,14 @@ fn read_i(parser: &Parser) -> i32 { parser.libdata_mut().exit_current_script = false; // OSC 133 "Command finished" - write!( - BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()), - "\x1b]133;D;{}\x07", - parser.get_last_status() - ) - .unwrap(); + if feature_test(FeatureFlag::mark_prompt) { + write!( + BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()), + "\x1b]133;D;{}\x07", + parser.get_last_status() + ) + .unwrap(); + } event::fire_generic(parser, L!("fish_postexec").to_owned(), vec![command]); // Allow any pending history items to be returned in the history array. data.history.resolve_pending(); diff --git a/src/screen.rs b/src/screen.rs index 158512e1e..edcbb1c65 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -7,6 +7,7 @@ //! The current implementation is less smart than ncurses allows and can not for example move blocks //! of text around to handle text insertion. +use crate::future_feature_flags::{feature_test, FeatureFlag}; use crate::pager::{PageRendering, Pager, PAGER_MIN_HEIGHT}; use std::cell::RefCell; use std::collections::LinkedList; @@ -931,8 +932,11 @@ fn update( } else if left_prompt != zelf.actual_left_prompt || (zelf.scrolled && is_final_rendering) { zelf.r#move(0, 0); let mut start = 0; - let osc_133_prompt_start = - |zelf: &mut Screen| zelf.write_bytes(b"\x1b]133;A;special_key=1\x07"); + let osc_133_prompt_start = |zelf: &mut Screen| { + if feature_test(FeatureFlag::mark_prompt) { + zelf.write_bytes(b"\x1b]133;A;special_key=1\x07"); + } + }; if left_prompt_layout.line_breaks.is_empty() { osc_133_prompt_start(&mut zelf); } diff --git a/tests/checks/status.fish b/tests/checks/status.fish index 7626d437e..82bc2950a 100644 --- a/tests/checks/status.fish +++ b/tests/checks/status.fish @@ -63,6 +63,7 @@ status features #CHECK: remove-percent-self off 4.0 %self is no longer expanded (use $fish_pid) #CHECK: test-require-arg off 4.0 builtin test requires an argument #CHECK: keyboard-protocols on 4.0 Use keyboard protocols (kitty, xterm's modifyotherkeys +#CHECK: mark-prompt on 4.0 Write OSC 133 prompt markers to the terminal status test-feature stderr-nocaret echo $status #CHECK: 0