Skip to content

Commit 2f8d907

Browse files
committed
fix(man): strip grotty backspace overstrikes from groff output
Grotty (groff's terminal output driver) uses char+backspace+char sequences for bold and _+backspace+char for underline. Strip these overstrike sequences in the binary rather than relying on external tools like col(1) or groff's -P -c flag. https://claude.ai/code/session_01CrXuWDMVQsiUBoy6ceACsF
1 parent c5b9190 commit 2f8d907

1 file changed

Lines changed: 22 additions & 12 deletions

File tree

cli/man_page.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,8 @@ fn man_path(page_num: u8) -> String {
6262
fn render_man_output(page_num: u8) -> Result<String, String> {
6363
let roff_file = roff_path(page_num);
6464
let output = Command::new("groff")
65-
.args([
66-
"-man",
67-
"-T",
68-
"utf8",
69-
"-K",
70-
"utf8",
71-
"-P",
72-
"-c",
73-
"-r",
74-
&format!("LL={LINE_LENGTH}n"),
75-
])
65+
.args(["-man", "-T", "utf8", "-K", "utf8"])
66+
.arg(format!("-rLL={LINE_LENGTH}n"))
7667
.arg(format!("./{roff_file}"))
7768
.output()
7869
.map_err(|error| format!("failed to run groff: {error}"))?;
@@ -82,7 +73,26 @@ fn render_man_output(page_num: u8) -> Result<String, String> {
8273
}
8374
let content = String::from_utf8(output.stdout)
8475
.map_err(|error| format!("groff output is not UTF-8: {error}"))?;
85-
Ok(normalize_text(&content))
76+
Ok(normalize_text(&strip_overstrikes(&content)))
77+
}
78+
79+
/// Strips backspace-based overstriking sequences produced by grotty.
80+
///
81+
/// Grotty uses `X\x08X` for bold and `_\x08X` for underline. This function
82+
/// removes the overstrike prefix (char + `\x08`) leaving only the visible character.
83+
fn strip_overstrikes(text: &str) -> String {
84+
let chars: Vec<char> = text.chars().collect();
85+
let mut result = String::with_capacity(text.len());
86+
let mut index = 0;
87+
while index < chars.len() {
88+
if index + 1 < chars.len() && chars[index + 1] == '\x08' {
89+
index += 2;
90+
} else {
91+
result.push(chars[index]);
92+
index += 1;
93+
}
94+
}
95+
result
8696
}
8797

8898
/// Strips trailing whitespace per line, trims trailing blank lines,

0 commit comments

Comments
 (0)