fish_tab_title: fix tab title accidentally including window title

Also use the correct OSC number.

Note that this only works on few terminals (such as iTerm2).  Not sure
if it's worth for us to have this feature but I guess multiple users
have requested it.
This commit is contained in:
Johannes Altmanninger
2025-11-09 07:52:48 +01:00
parent 78f71971cb
commit 33bf808084
3 changed files with 14 additions and 17 deletions

View File

@@ -221,7 +221,7 @@ Optional Commands
- Set terminal window title (OSC 0). Used in :doc:`fish_title <cmds/fish_title>`. - Set terminal window title (OSC 0). Used in :doc:`fish_title <cmds/fish_title>`.
* - ``\e]2; Pt \x07`` * - ``\e]2; Pt \x07``
- ts - ts
- Set terminal tab title (OSC 2). Used in :doc:`fish_tab_title <cmds/fish_tab_title>`. - Set terminal tab title (OSC 1). Used in :doc:`fish_tab_title <cmds/fish_tab_title>`.
* - ``\e]7;file:// Pt / Pt \x07`` * - ``\e]7;file:// Pt / Pt \x07``
- -
- Report working directory (OSC 7). - Report working directory (OSC 7).

View File

@@ -129,7 +129,7 @@
use crate::terminal::Outputter; use crate::terminal::Outputter;
use crate::terminal::TerminalCommand::{ use crate::terminal::TerminalCommand::{
self, ClearScreen, DecrstAlternateScreenBuffer, DecsetAlternateScreenBuffer, DecsetShowCursor, self, ClearScreen, DecrstAlternateScreenBuffer, DecsetAlternateScreenBuffer, DecsetShowCursor,
Osc0WindowTitle, Osc2TabTitle, Osc133CommandFinished, Osc133CommandStart, QueryCursorPosition, Osc0WindowTitle, Osc1TabTitle, Osc133CommandFinished, Osc133CommandStart, QueryCursorPosition,
QueryKittyKeyboardProgressiveEnhancements, QueryPrimaryDeviceAttribute, QueryXtgettcap, QueryKittyKeyboardProgressiveEnhancements, QueryPrimaryDeviceAttribute, QueryXtgettcap,
QueryXtversion, QueryXtversion,
}; };
@@ -4647,14 +4647,13 @@ pub fn reader_write_title(
parser: &Parser, parser: &Parser,
reset_cursor_position: bool, /* = true */ reset_cursor_position: bool, /* = true */
) { ) {
fn write_title<'a>( fn write_title(
parser: &Parser, parser: &Parser,
out: &mut BufferedOutputter, out: &mut BufferedOutputter,
cmd: &wstr, cmd: &wstr,
osc: fn(&'a [WString]) -> TerminalCommand<'a>, osc: fn(&[WString]) -> TerminalCommand<'_>,
function_name: &wstr, function_name: &wstr,
fallback_title: Option<&wstr>, fallback_title: Option<&wstr>,
title_buffer: &'a mut Vec<WString>,
) -> bool { ) -> bool {
let mut title_function_call; let mut title_function_call;
let mut title_command = fallback_title; let mut title_command = fallback_title;
@@ -4672,15 +4671,16 @@ fn write_title<'a>(
let Some(title_command) = title_command else { let Some(title_command) = title_command else {
return false; return false;
}; };
let mut title_buffer = vec![];
let _ = exec_subshell( let _ = exec_subshell(
title_command, title_command,
parser, parser,
Some(title_buffer), Some(&mut title_buffer),
/*apply_exit_status=*/ false, /*apply_exit_status=*/ false,
); );
if !title_buffer.is_empty() { if !title_buffer.is_empty() {
out.write_command(osc(&*title_buffer)); out.write_command(osc(&title_buffer));
return true; return true;
} }
false false
@@ -4693,24 +4693,21 @@ fn write_title<'a>(
let mut out = BufferedOutputter::new(Outputter::stdoutput()); let mut out = BufferedOutputter::new(Outputter::stdoutput());
let mut written = false; let mut written = false;
let mut lst = vec![];
written |= write_title( written |= write_title(
parser, parser,
&mut out, &mut out,
cmd, cmd,
Osc0WindowTitle, |title_buffer| Osc0WindowTitle(title_buffer),
L!("fish_title"), L!("fish_title"),
Some(DEFAULT_TITLE), Some(DEFAULT_TITLE),
&mut lst,
); );
written |= write_title( written |= write_title(
parser, parser,
&mut out, &mut out,
cmd, cmd,
Osc2TabTitle, |title_buffer| Osc1TabTitle(title_buffer),
L!("fish_tab_title"), L!("fish_tab_title"),
/*default_title=*/ None, /*default_title=*/ None,
&mut lst,
); );
out.reset_text_face(); out.reset_text_face();

View File

@@ -102,7 +102,7 @@ pub(crate) enum TerminalCommand<'a> {
// Note that OSC 7 and OSC 52 are written from fish script, and OSC 8 is written in our // Note that OSC 7 and OSC 52 are written from fish script, and OSC 8 is written in our
// man pages (via "man_show_urls"). // man pages (via "man_show_urls").
Osc0WindowTitle(&'a [WString]), Osc0WindowTitle(&'a [WString]),
Osc2TabTitle(&'a [WString]), Osc1TabTitle(&'a [WString]),
Osc133CommandStart(&'a wstr), Osc133CommandStart(&'a wstr),
Osc133PromptStart, Osc133PromptStart,
Osc133CommandFinished(libc::c_int), Osc133CommandFinished(libc::c_int),
@@ -176,8 +176,8 @@ fn write(out: &mut impl Output, sequence: &'static [u8]) -> bool {
ModifyOtherKeysDisable => write(self, b"\x1b[>4;0m"), ModifyOtherKeysDisable => write(self, b"\x1b[>4;0m"),
ApplicationKeypadModeEnable => write(self, b"\x1b="), ApplicationKeypadModeEnable => write(self, b"\x1b="),
ApplicationKeypadModeDisable => write(self, b"\x1b>"), ApplicationKeypadModeDisable => write(self, b"\x1b>"),
Osc0WindowTitle(title) => osc_0_or_2_terminal_title(self, false, title), Osc0WindowTitle(title) => osc_0_or_1_terminal_title(self, false, title),
Osc2TabTitle(title) => osc_0_or_2_terminal_title(self, true, title), Osc1TabTitle(title) => osc_0_or_1_terminal_title(self, true, title),
Osc133PromptStart => osc_133_prompt_start(self), Osc133PromptStart => osc_133_prompt_start(self),
Osc133CommandStart(command) => osc_133_command_start(self, command), Osc133CommandStart(command) => osc_133_command_start(self, command),
Osc133CommandFinished(s) => osc_133_command_finished(self, s), Osc133CommandFinished(s) => osc_133_command_finished(self, s),
@@ -371,8 +371,8 @@ fn query_kitty_progressive_enhancements(out: &mut impl Output) -> bool {
true true
} }
fn osc_0_or_2_terminal_title(out: &mut impl Output, is_2: bool, title: &[WString]) -> bool { fn osc_0_or_1_terminal_title(out: &mut impl Output, is_1: bool, title: &[WString]) -> bool {
out.write_bytes(if is_2 { b"\x1b]2;" } else { b"\x1b]0;" }); out.write_bytes(if is_1 { b"\x1b]1;" } else { b"\x1b]0;" });
for title_line in title { for title_line in title {
out.write_bytes(&wcs2bytes(title_line)); out.write_bytes(&wcs2bytes(title_line));
} }