use alacritty_terminal::term::TermMode;
use super::vt::VtState;
#[derive(Clone, Debug)]
pub enum SemanticEvent {
AltScreenEnter,
AltScreenExit,
ModeChange { added: TermMode, removed: TermMode },
}
pub fn detect_events(vt: &VtState, prev_mode: &mut TermMode) -> Vec<SemanticEvent> {
let cur_mode = vt.mode();
let mut events = Vec::new();
let was_alt = prev_mode.contains(TermMode::ALT_SCREEN);
let is_alt = cur_mode.contains(TermMode::ALT_SCREEN);
if !was_alt && is_alt {
events.push(SemanticEvent::AltScreenEnter);
} else if was_alt && !is_alt {
events.push(SemanticEvent::AltScreenExit);
}
let diff_added = cur_mode - *prev_mode;
let diff_removed = *prev_mode - cur_mode;
if !diff_added.is_empty() || !diff_removed.is_empty() {
let added = diff_added & !TermMode::ALT_SCREEN;
let removed = diff_removed & !TermMode::ALT_SCREEN;
if !added.is_empty() || !removed.is_empty() {
events.push(SemanticEvent::ModeChange { added, removed });
}
}
*prev_mode = cur_mode;
events
}
#[cfg(test)]
mod tests {
use super::super::vt::VtState;
use super::*;
#[test]
fn detect_alt_screen_enter() {
let mut v = VtState::new(24, 80);
v.feed(b"\x1b[?1049h"); let mut prev_mode = TermMode::empty();
let events = detect_events(&v, &mut prev_mode);
assert!(
matches!(events[0], SemanticEvent::AltScreenEnter),
"expected AltScreenEnter, got: {events:?}"
);
}
#[test]
fn detect_alt_screen_exit() {
let mut v = VtState::new(24, 80);
v.feed(b"\x1b[?1049h");
let mut prev_mode = TermMode::empty();
let _ = detect_events(&v, &mut prev_mode); v.feed(b"\x1b[?1049l");
let events = detect_events(&v, &mut prev_mode);
assert!(
matches!(events[0], SemanticEvent::AltScreenExit),
"expected AltScreenExit, got: {events:?}"
);
}
#[test]
fn no_event_on_unchanged_mode() {
let v = VtState::new(24, 80);
let mut prev_mode = v.mode();
let events = detect_events(&v, &mut prev_mode);
assert!(events.is_empty(), "no change yet: {events:?}");
}
#[test]
fn detect_mode_change_other_than_alt() {
let mut v = VtState::new(24, 80);
v.feed(b"\x1b[?1h"); let mut prev_mode = TermMode::empty();
let events = detect_events(&v, &mut prev_mode);
let has_mode_change = events.iter().any(|e| matches!(e, SemanticEvent::ModeChange { .. }));
assert!(has_mode_change, "expected ModeChange, got: {events:?}");
}
}