mod cell;
mod cursor;
mod escape;
mod line;
mod render;
mod ui_command;
pub use cell::*;
pub use cursor::*;
use escape::{EscapeSequence, EscapeState};
pub use line::*;
pub use ui_command::*;
use std::collections::VecDeque;
pub const MAX_SCROLLBACK: usize = 10000;
#[derive(Debug)]
pub struct ScreenBuffer {
width: u16,
height: u16,
lines: VecDeque<Line>,
view_start: usize,
cursor_pos: Position,
selection_start: Option<(u16, usize)>,
selection_end: Option<(u16, usize)>,
max_scrollback: usize,
escape_state: EscapeState,
escape_sequence: EscapeSequence,
last_render: Option<tokio::time::Instant>,
needs_render: bool,
}
impl ScreenBuffer {
pub fn new(width: u16, height: u16) -> Self {
let mut buffer = Self {
width,
height,
lines: VecDeque::new(),
view_start: 0,
cursor_pos: Position::home(),
selection_start: None,
selection_end: None,
max_scrollback: MAX_SCROLLBACK,
last_render: None,
needs_render: false,
escape_state: EscapeState::Normal,
escape_sequence: EscapeSequence::new(),
};
buffer.lines.push_back(Line::new(width as usize));
buffer
}
fn set_char_at_cursor(&mut self, ch: char) {
while self.cursor_pos.y >= self.lines.len() {
self.lines.push_back(Line::new(self.width as usize));
}
if let Some(line) = self.lines.get_mut(self.cursor_pos.y)
&& (self.cursor_pos.x as usize) < line.len()
{
line.set_char(self.cursor_pos.x as usize, ch);
}
}
fn clear_from_cursor_to_sol(&mut self) {
if let Some(line) = self.lines.get_mut(self.cursor_pos.y) {
line.reset_to(self.cursor_pos.x as usize);
}
}
fn clear_from_cursor_to_sos(&mut self) {
self.clear_from_cursor_to_sol();
for line in self
.lines
.range_mut(self.view_start..=self.cursor_pos.y - 1)
{
line.reset();
}
}
fn clear_from_cursor_to_eol(&mut self) {
if let Some(line) = self.lines.get_mut(self.cursor_pos.y) {
line.reset_from(self.cursor_pos.x as usize);
}
}
fn clear_from_cursor_to_eos(&mut self) {
self.clear_from_cursor_to_eol();
for line in self.lines.range_mut(self.cursor_pos.y + 1..) {
line.reset();
}
}
fn clear_whole_line(&mut self) {
if let Some(line) = self.lines.get_mut(self.cursor_pos.y) {
line.reset();
}
}
fn new_line(&mut self) {
self.set_cursor_pos((0, self.cursor_pos.y + 1));
if self.cursor_pos.y >= self.lines.len() {
self.lines.push_back(Line::new(self.width as usize));
}
while self.lines.len() > self.max_scrollback {
self.lines.pop_front();
if self.cursor_pos.y > 0 {
self.cursor_pos.y -= 1;
}
if self.view_start > 0 {
self.view_start -= 1;
}
}
}
}