Skip to content

Commit e507fa6

Browse files
committed
feat(progress): Detect OSC 9;4 in tmux and Herdr
Recognize tmux 3.7+ through TERM_PROGRAM and TERM_PROGRAM_VERSION, including patch suffixes such as 3.7b. Recognize Herdr by TERM_PROGRAM. tmux exposes progress to status formats and emits it to clients with Spb, supplied by terminfo, built-in mappings, or configuration. Automatic Ghostty progressbar recognition requires tmux 3.8. Herdr consumes progress for agent detection, not a generic visible bar. These hints work in native and remote panes without probing. Preserve the TTY gate and document detection inputs. Test tmux version parsing directly, covering boundaries, patch suffixes, malformed values, and overflow.
1 parent 5a4a67f commit e507fa6

1 file changed

Lines changed: 82 additions & 1 deletion

File tree

‎crates/anstyle-progress/src/query.rs‎

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,66 @@ pub fn supports_term_progress(is_terminal: bool) -> bool {
6363
return true;
6464
}
6565

66+
// Terminal multiplexers
67+
//
68+
// Environment variables used for detection:
69+
// | Multiplexer | Variable | Value |
70+
// |-------------|----------------------|-------------|
71+
// | cmux | TERM_PROGRAM | ghostty |
72+
// | Herdr | TERM_PROGRAM | herdr |
73+
// | screen | (none) | Not enabled |
74+
// | tmux | TERM_PROGRAM | tmux |
75+
// | | TERM_PROGRAM_VERSION | >= 3.7 |
76+
// | Zellij | (none) | Not enabled |
77+
//
78+
// cmux is a terminal app and already matches the Ghostty check above.
79+
// screen has no verified raw OSC 9;4 support.
80+
// Zellij: https://github.com/zellij-org/zellij/issues/4531
81+
82+
// Herdr 0.6.9 added OSC 9;4 capture in
83+
// https://github.com/herdrdev/herdr/commit/82468a0e03360219898ebf3735bdf559182009f8
84+
if term_program.as_deref() == Some("herdr") {
85+
return true;
86+
}
87+
88+
// tmux 3.7 added OSC 9;4 handling and forwarding to capable client terminals.
89+
// https://github.com/tmux/tmux/blob/3.7/CHANGES
90+
if term_program.as_deref() == Some("tmux")
91+
&& std::env::var("TERM_PROGRAM_VERSION")
92+
.ok()
93+
.map(|version| tmux_version_has_progress(&version))
94+
.unwrap_or(false)
95+
{
96+
return true;
97+
}
98+
6699
false
67100
}
68101

102+
fn tmux_version_has_progress(version: &str) -> bool {
103+
let Some((major, minor)) = version.split_once('.') else {
104+
return false;
105+
};
106+
// tmux patch releases append a lowercase letter, for example "3.7b".
107+
let minor = match minor.as_bytes().last() {
108+
Some(ch) if ch.is_ascii_lowercase() => &minor[..minor.len() - 1],
109+
_ => minor,
110+
};
111+
if major.is_empty()
112+
|| minor.is_empty()
113+
|| !major
114+
.bytes()
115+
.chain(minor.bytes())
116+
.all(|ch| ch.is_ascii_digit())
117+
{
118+
return false;
119+
}
120+
match (major.parse::<u32>(), minor.parse::<u32>()) {
121+
(Ok(major), Ok(minor)) => (major, minor) >= (3, 7),
122+
_ => false,
123+
}
124+
}
125+
69126
// For iTerm, the TERM_FEATURES value "P" indicates OSC 9;4 support.
70127
//
71128
// Context: https://iterm2.com/feature-reporting/
@@ -91,7 +148,7 @@ fn term_features_has_progress(value: &str) -> bool {
91148

92149
#[cfg(test)]
93150
mod tests {
94-
use super::term_features_has_progress;
151+
use super::{term_features_has_progress, tmux_version_has_progress};
95152

96153
#[test]
97154
fn term_features_progress_detection() {
@@ -101,4 +158,28 @@ mod tests {
101158
// Without PROGRESS feature
102159
assert!(!term_features_has_progress("MBT2Sc"));
103160
}
161+
162+
#[test]
163+
fn tmux_progress_detection() {
164+
for (version, expected) in [
165+
("3.6b", false),
166+
("3.7", true),
167+
("3.7b", true),
168+
("3.8", true),
169+
("3.10", true),
170+
("4.0", true),
171+
("2.10", false),
172+
("", false),
173+
("next-3.7", false),
174+
("3.7junk", false),
175+
("3.7.0", false),
176+
("3.", false),
177+
("3.a", false),
178+
("+3.7", false),
179+
("3.+7", false),
180+
("4294967296.7", false),
181+
] {
182+
assert_eq!(tmux_version_has_progress(version), expected, "{version:?}");
183+
}
184+
}
104185
}

0 commit comments

Comments
 (0)