pub mod style;
pub mod cell;
pub mod grid;
pub mod performer;
pub mod render;
use vte::Parser;
use grid::Grid;
use performer::ScreenPerformer;
use render::render_screen;
pub use render::RenderCache;
use style::Style;
#[derive(Copy, Clone)]
pub struct SavedCursor {
pub x: u16,
pub y: u16,
pub style: Style,
pub g0_charset: grid::Charset,
pub g1_charset: grid::Charset,
pub active_charset: grid::ActiveCharset,
pub autowrap_mode: bool,
}
pub struct ScreenState {
pub current_style: Style,
pub in_alt_screen: bool,
pub saved_grid: Option<grid::SavedGrid>,
pub saved_cursor_state: Option<SavedCursor>,
pub saved_modes: Option<grid::TerminalModes>,
pub pending_responses: Vec<Vec<u8>>,
pub pending_passthrough: Vec<Vec<u8>>,
pub title: String,
pub last_printed_char: char,
}
impl Default for ScreenState {
fn default() -> Self {
Self {
current_style: Style::default(),
in_alt_screen: false,
saved_grid: None,
saved_cursor_state: None,
saved_modes: None,
pending_responses: Vec::new(),
pending_passthrough: Vec::new(),
title: String::new(),
last_printed_char: ' ',
}
}
}
pub struct Screen {
pub grid: Grid,
state: ScreenState,
parser: Parser,
}
impl Screen {
pub fn new(cols: u16, rows: u16, scrollback_limit: usize) -> Self {
Self {
grid: Grid::new(cols, rows, scrollback_limit),
state: ScreenState::default(),
parser: Parser::new(),
}
}
pub fn in_alt_screen(&self) -> bool {
self.state.in_alt_screen
}
pub fn process(&mut self, bytes: &[u8]) {
let mut performer = ScreenPerformer {
grid: &mut self.grid,
state: &mut self.state,
};
for &byte in bytes {
self.parser.advance(&mut performer, byte);
}
}
pub fn take_responses(&mut self) -> Vec<Vec<u8>> {
std::mem::take(&mut self.state.pending_responses)
}
pub fn take_passthrough(&mut self) -> Vec<Vec<u8>> {
std::mem::take(&mut self.state.pending_passthrough)
}
pub fn take_pending_scrollback(&mut self) -> Vec<Vec<u8>> {
let start = self.grid.pending_start;
let end = self.grid.scrollback_len;
self.grid.pending_start = end;
self.grid.cells.iter().skip(start).take(end - start)
.map(|row| render::render_line(row))
.collect()
}
pub fn get_history(&self) -> Vec<Vec<u8>> {
self.grid.cells.iter().take(self.grid.scrollback_len)
.map(|row| render::render_line(row)).collect()
}
pub fn render(&self, full: bool, cache: &mut RenderCache) -> Vec<u8> {
render_screen(&self.grid, &self.state.title, full, cache)
}
pub fn render_with_scrollback(&self, scrollback: &[Vec<u8>], cache: &mut RenderCache) -> Vec<u8> {
render::render_screen_with_scrollback(&self.grid, &self.state.title, scrollback, cache)
}
pub fn resize(&mut self, cols: u16, rows: u16) {
let old_rows = self.grid.rows;
if !self.state.in_alt_screen && rows > old_rows {
let grow = (rows - old_rows) as usize;
let restore_count = grow.min(self.grid.scrollback_len);
self.grid.scrollback_len -= restore_count;
self.grid.pending_start = self.grid.pending_start.min(self.grid.scrollback_len);
self.grid.cursor_y += restore_count as u16;
}
self.grid.resize(cols, rows);
}
}
#[cfg(test)]
mod history_boundary_tests;
#[cfg(test)]
mod tests_large_updates;
#[cfg(test)]
mod tests_screen;
#[cfg(test)]
mod tests_reattach;
#[cfg(test)]
mod tests_resize;
#[cfg(test)]
mod tests_reconnect_scrollback;
#[cfg(test)]
mod tests_live_scrollback;
#[cfg(test)]
mod tests_progress_bar_scrollback;