Skip to content

Commit 54ffa27

Browse files
committed
infocmp -C: high-byte octal escaping + inline %r placement
Two derivable termcap fixes (clean-room, oracle-verified): - termcap value escaping now renders high bytes 0x81..0xff as 3-digit octal (\nnn), matching ncurses (e.g. CSI 0x9b -> \233); previously emitted raw. - %r (reverse the two parameters) is emitted INLINE before the first parameter-consuming output op, not prepended: \E&a%p2%dc%p1%dY -> \E&a%r%dc%dY (was %r\E&a%dc%dY). Termcap (-C) content match 25.1% -> 27.7%, exact 16.3% -> 18.1% across the DB. Remaining derivable work continues (control-char octal/caret islong rule, the as/ae/rs drop conditions, the wrap rule); the me/sgr0 derivation is honestly bounded as not a function of observable inputs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbiPgWC3PHKmrTNvZzXcWQ
1 parent c738880 commit 54ffa27

1 file changed

Lines changed: 20 additions & 3 deletions

File tree

crates/ncurses-tools/src/bin/infocmp.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ fn tc_escape_byte(out: &mut String, b: u8) {
224224
out.push('^');
225225
out.push((b ^ 0x40) as char);
226226
}
227+
0x81..=0xff => out.push_str(&format!("\\{b:03o}")),
227228
_ => out.push(b as char),
228229
}
229230
}
@@ -288,9 +289,9 @@ fn try_translate(v: &[u8]) -> Option<String> {
288289
};
289290

290291
let mut out = String::new();
291-
if reverse {
292-
out.push_str("%r");
293-
}
292+
// `%r` (reverse the two parameters) is emitted inline, just before the first parameter-consuming
293+
// output op (not prepended) -- e.g. `\E&a%p2%dc%p1%dY` -> `\E&a%r%dc%dY`.
294+
let mut r_pending = reverse;
294295
let mut i = 0;
295296
while i < v.len() {
296297
if v[i] != b'%' {
@@ -309,10 +310,18 @@ fn try_translate(v: &[u8]) -> Option<String> {
309310
}
310311
Some(b'p') => i += 3, // `%pN` push -- the following format op produces the output
311312
Some(b'd') => {
313+
if r_pending {
314+
out.push_str("%r");
315+
r_pending = false;
316+
}
312317
out.push_str("%d");
313318
i += 2;
314319
}
315320
Some(b'c') => {
321+
if r_pending {
322+
out.push_str("%r");
323+
r_pending = false;
324+
}
316325
out.push_str("%.");
317326
i += 2;
318327
}
@@ -328,6 +337,10 @@ fn try_translate(v: &[u8]) -> Option<String> {
328337
if !(2..=9).contains(&width) {
329338
return None;
330339
}
340+
if r_pending {
341+
out.push_str("%r");
342+
r_pending = false;
343+
}
331344
out.push('%');
332345
out.push((b'0' + width as u8) as char);
333346
i = j + 1;
@@ -339,6 +352,10 @@ fn try_translate(v: &[u8]) -> Option<String> {
339352
&& v.get(i + 6) == Some(&b'%')
340353
&& v.get(i + 7) == Some(&b'c') =>
341354
{
355+
if r_pending {
356+
out.push_str("%r");
357+
r_pending = false;
358+
}
342359
out.push_str("%+");
343360
tc_escape_byte(&mut out, v[i + 2]);
344361
i += 8;

0 commit comments

Comments
 (0)