use std::io::Write;
pub const MARKER: &str = "▞";
const PUSH_STACK: &[u8] = b"\x1b[22;2t";
const POP_STACK: &[u8] = b"\x1b[23;2t";
fn sanitize(text: &str) -> String {
text.chars().filter(|c| !c.is_control()).collect()
}
pub fn tab_title_text(role: Option<&str>, stem: &str) -> String {
let body = role
.map(sanitize)
.map(|text| text.trim().to_string())
.filter(|text| !text.is_empty())
.unwrap_or_else(|| sanitize(stem).trim().to_string());
format!("{MARKER} {body}")
}
pub struct TabTitleGuard<W: Write> {
out: W,
last: String,
}
impl<W: Write> TabTitleGuard<W> {
pub fn set_over_stack(mut out: W, text: &str) -> std::io::Result<Self> {
out.write_all(PUSH_STACK)?;
let mut guard = TabTitleGuard {
out,
last: String::new(),
};
guard.set(text)?;
Ok(guard)
}
pub fn set(&mut self, text: &str) -> std::io::Result<()> {
if self.last == text {
return Ok(());
}
self.out.write_all(b"\x1b]2;")?;
self.out.write_all(text.as_bytes())?;
self.out.write_all(b"\x07")?;
self.out.flush()?;
self.last = text.to_string();
Ok(())
}
}
impl<W: Write> Drop for TabTitleGuard<W> {
fn drop(&mut self) {
let _ = self.out.write_all(POP_STACK);
let _ = self.out.flush();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_text_is_marker_plus_role_or_the_stem() {
assert_eq!(tab_title_text(Some("3 failing"), "deploy"), "▞ 3 failing");
assert_eq!(tab_title_text(None, "deploy"), "▞ deploy");
assert_eq!(
tab_title_text(Some("a\u{7}b\u{1b}]0;evil\u{7}"), "deploy"),
"▞ ab]0;evil"
);
assert_eq!(tab_title_text(Some("\u{7} \u{1b}"), "deploy"), "▞ deploy");
}
#[test]
fn the_guard_pushes_sets_and_pops_and_never_repeats_itself() {
let mut bytes: Vec<u8> = Vec::new();
{
let mut guard =
TabTitleGuard::set_over_stack(&mut bytes, "▞ one").expect("write to a vec");
guard.set("▞ one").expect("idempotent");
guard.set("▞ two").expect("second title");
}
let text = String::from_utf8(bytes).expect("utf8");
assert_eq!(
text, "\u{1b}[22;2t\u{1b}]2;▞ one\u{7}\u{1b}]2;▞ two\u{7}\u{1b}[23;2t",
"push, first set, ONE re-set, pop — nothing else"
);
}
}