Use ST (\x1b\\) as OSC terminator

The test balloon in 012007ce7b (Test balloon for ST OSC terminator,
2025-11-18) released in 4.3.0 did not trigger problem reports.
Bravely switch over to the standard ST rather than xterm's BEL.

Closes #12032
This commit is contained in:
Johannes Altmanninger
2026-05-15 21:51:28 +08:00
parent afd869be2a
commit ec52a999b3
3 changed files with 33 additions and 35 deletions

View File

@@ -8,7 +8,6 @@ while others enable optional features and may be ignored by the terminal.
The terminal must be able to parse Control Sequence Introducer (CSI) commands, Operating System Commands (OSC) and :ref:`optionally <term-compat-dcs-gnu-screen>` Device Control Strings (DCS).
These are defined by ECMA-48.
If a valid CSI, OSC or DCS sequence does not represent a command implemented by the terminal, the terminal must ignore it.
For historical reasons, OSC sequences may be terminated with ``\x07`` instead of ``\e\\``.
Control sequences are denoted in a fish-like syntax.
Special characters other than ``\`` are not escaped.

View File

@@ -2099,16 +2099,18 @@ fn test_escape_code_length() {
// iTerm2 escape sequences.
assert_eq!(
lc.escape_code_length(L!("\x1B]50;CurrentDir=test/foo\x07NOT_PART_OF_SEQUENCE")),
25
lc.escape_code_length(L!("\x1B]50;CurrentDir=test/foo\x1b\\NOT_PART_OF_SEQUENCE")),
26
);
assert_eq!(
lc.escape_code_length(L!("\x1B]50;SetMark\x07NOT_PART_OF_SEQUENCE")),
13
lc.escape_code_length(L!("\x1B]50;SetMark\x1b\\NOT_PART_OF_SEQUENCE")),
14
);
assert_eq!(
lc.escape_code_length(L!("\x1B]6;1;bg;red;brightness;255\x07NOT_PART_OF_SEQUENCE")),
28
lc.escape_code_length(L!(
"\x1B]6;1;bg;red;brightness;255\x1b\\NOT_PART_OF_SEQUENCE"
)),
29
);
assert_eq!(
lc.escape_code_length(L!("\x1B]Pg4040ff\x1B\\NOT_PART_OF_SEQUENCE")),
@@ -2273,22 +2275,7 @@ fn test_prompt_truncation() {
// Escape sequences are not truncated.
let layout = cache.calc_prompt_layout(
L!("\x1B]50;CurrentDir=test/foo\x07NOT_PART_OF_SEQUENCE"),
Some(&mut trunc),
4,
);
assert_eq!(
layout,
PromptLayout {
line_starts: vec![0],
last_line_width: 4,
},
);
assert_eq!(trunc, ellipsis() + L!("\x1B]50;CurrentDir=test/foo\x07NCE"));
// Newlines in escape sequences are skipped.
let layout = cache.calc_prompt_layout(
L!("\x1B]50;CurrentDir=\ntest/foo\x07NOT_PART_OF_SEQUENCE"),
L!("\x1B]50;CurrentDir=test/foo\x1b\\NOT_PART_OF_SEQUENCE"),
Some(&mut trunc),
4,
);
@@ -2301,7 +2288,25 @@ fn test_prompt_truncation() {
);
assert_eq!(
trunc,
ellipsis() + L!("\x1B]50;CurrentDir=\ntest/foo\x07NCE")
ellipsis() + L!("\x1B]50;CurrentDir=test/foo\x1b\\NCE")
);
// Newlines in escape sequences are skipped.
let layout = cache.calc_prompt_layout(
L!("\x1B]50;CurrentDir=\ntest/foo\x1b\\NOT_PART_OF_SEQUENCE"),
Some(&mut trunc),
4,
);
assert_eq!(
layout,
PromptLayout {
line_starts: vec![0],
last_line_width: 4,
},
);
assert_eq!(
trunc,
ellipsis() + L!("\x1B]50;CurrentDir=\ntest/foo\x1b\\NCE")
);
// We will truncate down to one character if we have to.

View File

@@ -1,4 +1,3 @@
use crate::global_safety::RelaxedAtomicBool;
// Generic output functions.
use crate::prelude::*;
use crate::{
@@ -179,7 +178,7 @@ fn osc_0_or_1_terminal_title(out: &mut Outputter, is_1: bool, title: &[WString])
for title_line in title {
out.write_bytes(&wcs2bytes(title_line));
}
out.write_bytes(b"\x07"); // BEL
out.write_bytes(b"\x1b\\"); // BEL
true
}
@@ -187,12 +186,7 @@ fn osc_133_prompt_start(out: &mut Outputter) -> bool {
if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) {
return false;
}
static TEST_BALLOON: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
if !TEST_BALLOON.swap(true) {
write_to_output!(out, "\x1b]133;A;click_events=1\x1b\\");
} else {
write_to_output!(out, "\x1b]133;A;click_events=1\x07");
}
write_to_output!(out, "\x1b]133;A;click_events=1\x1b\\");
true
}
@@ -200,7 +194,7 @@ fn osc_133_prompt_end(out: &mut Outputter) -> bool {
if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) {
return false;
}
write_to_output!(out, "\x1b]133;B\x07");
write_to_output!(out, "\x1b]133;B\x1b\\");
true
}
@@ -210,7 +204,7 @@ fn osc_133_command_start(out: &mut Outputter, command: &wstr) -> bool {
}
write_to_output!(
out,
"\x1b]133;C;cmdline_url={}\x07",
"\x1b]133;C;cmdline_url={}\x1b\\",
escape_string(command, EscapeStringStyle::Url),
);
true
@@ -220,7 +214,7 @@ fn osc_133_command_finished(out: &mut Outputter, exit_status: libc::c_int) -> bo
if !fish_feature_flags::feature_test(FeatureFlag::MarkPrompt) {
return false;
}
write_to_output!(out, "\x1b]133;D;{}\x07", exit_status);
write_to_output!(out, "\x1b]133;D;{}\x1b\\", exit_status);
true
}