use crate::shadow::Snapshot;
fn is_rule(snap: &Snapshot, r: usize) -> bool {
let row = &snap.rows[r];
let dashes = row.iter().filter(|c| c.c == '─').count();
dashes * 5 >= row.len() * 4
}
pub fn composer_top(snap: &Snapshot) -> Option<usize> {
let rows = snap.rows.len();
(rows / 3..rows).rev().find_map(|r| {
let text: String = snap.rows[r].iter().take(4).map(|c| c.c).collect();
(r > 0 && text.trim_start().starts_with('❯') && is_rule(snap, r - 1)).then(|| r - 1)
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shadow::Shadow;
fn top(capture: &[u8]) -> Option<usize> {
let mut s = Shadow::new(120, 40);
s.advance(capture);
s.flush_sync();
composer_top(&s.snapshot())
}
#[test]
fn finds_the_input_box_in_both_renderers() {
let full = top(include_bytes!(
"../../tests/fixtures/claude_fullscreen_120x40.bin"
));
let inline = top(include_bytes!(
"../../tests/fixtures/claude_inline_120x40.bin"
));
assert_eq!(full, Some(35));
assert!(inline.is_some_and(|k| k > 20 && k < 35), "{inline:?}");
let mut s = Shadow::new(40, 6);
s.advance(b"\xe2\x9d\xaf earlier prompt\r\nanswer\r\n");
assert_eq!(composer_top(&s.snapshot()), None);
}
}