use alacritty_terminal::vte::ansi::CursorShape;
use serde::Serialize;
#[derive(Serialize)]
pub struct CellFrame {
pub t: &'static str,
pub session_id: String,
pub width: u16,
pub height: u16,
pub full: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<CursorState>,
pub overlay: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub row_indices: Option<Vec<usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub viewport: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alt_screen: Option<bool>,
pub history_size: u32,
pub rows: Vec<RowData>,
}
#[derive(Serialize)]
pub struct RowData {
pub runs: Vec<String>,
}
#[derive(Serialize)]
pub struct CursorState {
pub row: i32,
pub col: u16,
#[serde(skip_serializing_if = "Option::is_none")]
pub shape: Option<u8>,
pub visible: bool,
}
#[derive(Default)]
pub struct DiffEngine {
prev: Vec<Option<u64>>,
}
impl DiffEngine {
pub fn with_rows(rows: usize) -> Self {
Self { prev: vec![None; rows] }
}
pub fn invalidate(&mut self) {
self.prev.fill(None);
}
pub fn is_untracked(&self) -> bool {
self.prev.is_empty() || self.prev.iter().all(|h| h.is_none())
}
pub fn resize(&mut self, new_rows: usize) {
if new_rows > self.prev.len() {
self.prev.resize(new_rows, None);
} else {
self.prev.truncate(new_rows);
}
}
pub fn changed_rows_from(&mut self, hashes: &[u64]) -> Vec<usize> {
let mut changed = Vec::new();
for (i, &h) in hashes.iter().enumerate() {
if let Some(entry) = self.prev.get(i) {
if *entry != Some(h) {
changed.push(i);
if let Some(slot) = self.prev.get_mut(i) {
*slot = Some(h);
}
}
} else {
changed.push(i);
if i < self.prev.len() {
self.prev[i] = Some(h);
}
}
}
changed
}
}
#[inline]
pub fn decscusr_code(shape: CursorShape) -> u8 {
match shape {
CursorShape::Block => 0,
CursorShape::Underline => 3,
CursorShape::Beam => 5,
CursorShape::Hidden => 0,
CursorShape::HollowBlock => 0,
}
}