From e2b746dd64b1fd41351f0e1de11c276865e80c91 Mon Sep 17 00:00:00 2001 From: Vassiliy Yegorov Date: Tue, 9 Jun 2026 20:10:49 +0700 Subject: [PATCH] feat(core): GridSurface feeding PTY bytes into alacritty term Co-Authored-By: Claude Opus 4.8 (1M context) --- crates/spacesh-core/src/grid.rs | 83 +++++++++++++++++++++++++++++++++ crates/spacesh-core/src/lib.rs | 7 ++- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 crates/spacesh-core/src/grid.rs diff --git a/crates/spacesh-core/src/grid.rs b/crates/spacesh-core/src/grid.rs new file mode 100644 index 0000000..1f5e361 --- /dev/null +++ b/crates/spacesh-core/src/grid.rs @@ -0,0 +1,83 @@ +use alacritty_terminal::event::VoidListener; +use alacritty_terminal::grid::Dimensions; +use alacritty_terminal::index::{Column, Line, Point}; +use alacritty_terminal::term::{Config, Term}; +use alacritty_terminal::vte::ansi::Processor; + +/// Fixed-size terminal dimensions for the daemon-side grid. +#[derive(Clone, Copy)] +pub struct GridSize { + pub cols: usize, + pub lines: usize, +} + +impl Dimensions for GridSize { + fn total_lines(&self) -> usize { + self.lines + } + fn screen_lines(&self) -> usize { + self.lines + } + fn columns(&self) -> usize { + self.cols + } +} + +/// Owns an alacritty terminal model and feeds raw PTY bytes into it. +pub struct GridSurface { + term: Term, + parser: Processor, + size: GridSize, +} + +impl GridSurface { + pub fn new(cols: u16, rows: u16) -> Self { + let size = GridSize { cols: cols as usize, lines: rows as usize }; + let term = Term::new(Config::default(), &size, VoidListener); + Self { term, parser: Processor::new(), size } + } + + pub fn feed(&mut self, bytes: &[u8]) { + self.parser.advance(&mut self.term, bytes); + } + + pub fn resize(&mut self, cols: u16, rows: u16) { + self.size = GridSize { cols: cols as usize, lines: rows as usize }; + self.term.resize(self.size); + } + + pub fn size(&self) -> GridSize { + self.size + } + + /// Read the visible character at (line, col) — used by tests and the snapshot writer. + pub fn char_at(&self, line: usize, col: usize) -> char { + let point = Point::new(Line(line as i32), Column(col)); + self.term.grid()[point].c + } + + pub fn term(&self) -> &Term { + &self.term + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn feeding_plain_text_lands_in_the_grid() { + let mut g = GridSurface::new(20, 5); + g.feed(b"hello"); + assert_eq!(g.char_at(0, 0), 'h'); + assert_eq!(g.char_at(0, 4), 'o'); + } + + #[test] + fn carriage_return_and_newline_move_the_cursor() { + let mut g = GridSurface::new(20, 5); + g.feed(b"ab\r\ncd"); + assert_eq!(g.char_at(0, 0), 'a'); + assert_eq!(g.char_at(1, 0), 'c'); + } +} diff --git a/crates/spacesh-core/src/lib.rs b/crates/spacesh-core/src/lib.rs index 1b486d8..50db45b 100644 --- a/crates/spacesh-core/src/lib.rs +++ b/crates/spacesh-core/src/lib.rs @@ -1 +1,6 @@ -// modules added in Tasks 11-12 +pub mod grid; +// snapshot module added in Task 12 +// pub mod snapshot; + +pub use grid::GridSurface; +// pub use snapshot::Snapshot;