aboutsummaryrefslogtreecommitdiff
path: root/vendor/vt100/src/grid.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-05 16:24:20 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 16:38:50 +0300
commitb2e6929aa8199574565fd4adf1e631c68d479e6c (patch)
tree99964965fe84f9ea31a0dec7ede2393631dc7f50 /vendor/vt100/src/grid.rs
parent822c3b9e2d1edb7481fa558497dd33c7f5dca9ee (diff)
refactor: remove vt100 backend and make ghostty default
Diffstat (limited to 'vendor/vt100/src/grid.rs')
-rw-r--r--vendor/vt100/src/grid.rs740
1 files changed, 0 insertions, 740 deletions
diff --git a/vendor/vt100/src/grid.rs b/vendor/vt100/src/grid.rs
deleted file mode 100644
index f8958579..00000000
--- a/vendor/vt100/src/grid.rs
+++ /dev/null
@@ -1,740 +0,0 @@
-use crate::term::BufWrite as _;
-
-#[derive(Clone, Debug)]
-pub struct Grid {
- size: Size,
- pos: Pos,
- saved_pos: Pos,
- rows: Vec<crate::row::Row>,
- scroll_top: u16,
- scroll_bottom: u16,
- origin_mode: bool,
- saved_origin_mode: bool,
- scrollback: std::collections::VecDeque<crate::row::Row>,
- scrollback_len: usize,
- scrollback_offset: usize,
-}
-
-impl Grid {
- pub fn new(size: Size, scrollback_len: usize) -> Self {
- Self {
- size,
- pos: Pos::default(),
- saved_pos: Pos::default(),
- rows: vec![],
- scroll_top: 0,
- scroll_bottom: size.rows - 1,
- origin_mode: false,
- saved_origin_mode: false,
- scrollback: std::collections::VecDeque::new(),
- scrollback_len,
- scrollback_offset: 0,
- }
- }
-
- pub fn allocate_rows(&mut self) {
- if self.rows.is_empty() {
- self.rows.extend(
- std::iter::repeat_with(|| {
- crate::row::Row::new(self.size.cols)
- })
- .take(usize::from(self.size.rows)),
- );
- }
- }
-
- fn new_row(&self) -> crate::row::Row {
- crate::row::Row::new(self.size.cols)
- }
-
- pub fn clear(&mut self) {
- self.pos = Pos::default();
- self.saved_pos = Pos::default();
- for row in self.drawing_rows_mut() {
- row.clear(crate::attrs::Attrs::default());
- }
- self.scroll_top = 0;
- self.scroll_bottom = self.size.rows - 1;
- self.origin_mode = false;
- self.saved_origin_mode = false;
- }
-
- pub fn size(&self) -> Size {
- self.size
- }
-
- pub fn set_size(&mut self, size: Size) {
- if size.cols != self.size.cols {
- for row in &mut self.rows {
- row.wrap(false);
- }
- }
-
- if self.scroll_bottom == self.size.rows - 1 {
- self.scroll_bottom = size.rows - 1;
- }
-
- self.size = size;
- for row in &mut self.rows {
- row.resize(size.cols, crate::Cell::new());
- }
- self.rows.resize(usize::from(size.rows), self.new_row());
-
- if self.scroll_bottom >= size.rows {
- self.scroll_bottom = size.rows - 1;
- }
- if self.scroll_bottom < self.scroll_top {
- self.scroll_top = 0;
- }
-
- self.row_clamp_top(false);
- self.row_clamp_bottom(false);
- self.col_clamp();
-
- if self.saved_pos.row > self.size.rows - 1 {
- self.saved_pos.row = self.size.rows - 1;
- }
- if self.saved_pos.col > self.size.cols - 1 {
- self.saved_pos.col = self.size.cols - 1;
- }
- }
-
- pub fn pos(&self) -> Pos {
- self.pos
- }
-
- pub fn set_pos(&mut self, mut pos: Pos) {
- if self.origin_mode {
- pos.row = pos.row.saturating_add(self.scroll_top);
- }
- self.pos = pos;
- self.row_clamp_top(self.origin_mode);
- self.row_clamp_bottom(self.origin_mode);
- self.col_clamp();
- }
-
- pub fn save_cursor(&mut self) {
- self.saved_pos = self.pos;
- self.saved_origin_mode = self.origin_mode;
- }
-
- pub fn restore_cursor(&mut self) {
- self.pos = self.saved_pos;
- self.origin_mode = self.saved_origin_mode;
- }
-
- pub fn visible_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
- let scrollback_len = self.scrollback.len();
- let rows_len = self.rows.len();
- self.scrollback
- .iter()
- .skip(scrollback_len - self.scrollback_offset)
- // when scrollback_offset > rows_len (e.g. rows = 3,
- // scrollback_len = 10, offset = 9) the skip(10 - 9)
- // will take 9 rows instead of 3. we need to set
- // the upper bound to rows_len (e.g. 3)
- .take(rows_len)
- // same for rows_len - scrollback_offset (e.g. 3 - 9).
- // it'll panic with overflow. we have to saturate the subtraction.
- .chain(
- self.rows
- .iter()
- .take(rows_len.saturating_sub(self.scrollback_offset)),
- )
- }
-
- pub fn drawing_rows(&self) -> impl Iterator<Item = &crate::row::Row> {
- self.rows.iter()
- }
-
- pub fn drawing_rows_mut(
- &mut self,
- ) -> impl Iterator<Item = &mut crate::row::Row> {
- self.rows.iter_mut()
- }
-
- pub fn visible_row(&self, row: u16) -> Option<&crate::row::Row> {
- self.visible_rows().nth(usize::from(row))
- }
-
- pub fn drawing_row(&self, row: u16) -> Option<&crate::row::Row> {
- self.drawing_rows().nth(usize::from(row))
- }
-
- pub fn drawing_row_mut(
- &mut self,
- row: u16,
- ) -> Option<&mut crate::row::Row> {
- self.drawing_rows_mut().nth(usize::from(row))
- }
-
- pub fn current_row_mut(&mut self) -> &mut crate::row::Row {
- self.drawing_row_mut(self.pos.row)
- // we assume self.pos.row is always valid
- .unwrap()
- }
-
- pub fn visible_cell(&self, pos: Pos) -> Option<&crate::Cell> {
- self.visible_row(pos.row).and_then(|r| r.get(pos.col))
- }
-
- pub fn drawing_cell(&self, pos: Pos) -> Option<&crate::Cell> {
- self.drawing_row(pos.row).and_then(|r| r.get(pos.col))
- }
-
- pub fn drawing_cell_mut(&mut self, pos: Pos) -> Option<&mut crate::Cell> {
- self.drawing_row_mut(pos.row)
- .and_then(|r| r.get_mut(pos.col))
- }
-
- pub fn scrollback_len(&self) -> usize {
- self.scrollback_len
- }
-
- pub fn scrollback(&self) -> usize {
- self.scrollback_offset
- }
-
- pub fn set_scrollback(&mut self, rows: usize) {
- self.scrollback_offset = rows.min(self.scrollback.len());
- }
-
- pub fn write_contents(&self, contents: &mut String) {
- let mut wrapping = false;
- for row in self.visible_rows() {
- row.write_contents(contents, 0, self.size.cols, wrapping);
- if !row.wrapped() {
- contents.push('\n');
- }
- wrapping = row.wrapped();
- }
-
- while contents.ends_with('\n') {
- contents.truncate(contents.len() - 1);
- }
- }
-
- pub fn write_contents_formatted(
- &self,
- contents: &mut Vec<u8>,
- ) -> crate::attrs::Attrs {
- crate::term::ClearAttrs.write_buf(contents);
- crate::term::ClearScreen.write_buf(contents);
-
- let mut prev_attrs = crate::attrs::Attrs::default();
- let mut prev_pos = Pos::default();
- let mut wrapping = false;
- for (i, row) in self.visible_rows().enumerate() {
- // we limit the number of cols to a u16 (see Size), so
- // visible_rows() can never return more rows than will fit
- let i = i.try_into().unwrap();
- let (new_pos, new_attrs) = row.write_contents_formatted(
- contents,
- 0,
- self.size.cols,
- i,
- wrapping,
- Some(prev_pos),
- Some(prev_attrs),
- );
- prev_pos = new_pos;
- prev_attrs = new_attrs;
- wrapping = row.wrapped();
- }
-
- self.write_cursor_position_formatted(
- contents,
- Some(prev_pos),
- Some(prev_attrs),
- );
-
- prev_attrs
- }
-
- pub fn write_contents_diff(
- &self,
- contents: &mut Vec<u8>,
- prev: &Self,
- mut prev_attrs: crate::attrs::Attrs,
- ) -> crate::attrs::Attrs {
- let mut prev_pos = prev.pos;
- let mut wrapping = false;
- let mut prev_wrapping = false;
- for (i, (row, prev_row)) in
- self.visible_rows().zip(prev.visible_rows()).enumerate()
- {
- // we limit the number of cols to a u16 (see Size), so
- // visible_rows() can never return more rows than will fit
- let i = i.try_into().unwrap();
- let (new_pos, new_attrs) = row.write_contents_diff(
- contents,
- prev_row,
- 0,
- self.size.cols,
- i,
- wrapping,
- prev_wrapping,
- prev_pos,
- prev_attrs,
- );
- prev_pos = new_pos;
- prev_attrs = new_attrs;
- wrapping = row.wrapped();
- prev_wrapping = prev_row.wrapped();
- }
-
- self.write_cursor_position_formatted(
- contents,
- Some(prev_pos),
- Some(prev_attrs),
- );
-
- prev_attrs
- }
-
- pub fn write_cursor_position_formatted(
- &self,
- contents: &mut Vec<u8>,
- prev_pos: Option<Pos>,
- prev_attrs: Option<crate::attrs::Attrs>,
- ) {
- let prev_attrs = prev_attrs.unwrap_or_default();
- // writing a character to the last column of a row doesn't wrap the
- // cursor immediately - it waits until the next character is actually
- // drawn. it is only possible for the cursor to have this kind of
- // position after drawing a character though, so if we end in this
- // position, we need to redraw the character at the end of the row.
- if prev_pos != Some(self.pos) && self.pos.col >= self.size.cols {
- let mut pos = Pos {
- row: self.pos.row,
- col: self.size.cols - 1,
- };
- if self
- .drawing_cell(pos)
- // we assume self.pos.row is always valid, and self.size.cols
- // - 1 is always a valid column
- .unwrap()
- .is_wide_continuation()
- {
- pos.col = self.size.cols - 2;
- }
- let cell =
- // we assume self.pos.row is always valid, and self.size.cols
- // - 2 must be a valid column because self.size.cols - 1 is
- // always valid and we just checked that the cell at
- // self.size.cols - 1 is a wide continuation character, which
- // means that the first half of the wide character must be
- // before it
- self.drawing_cell(pos).unwrap();
- if cell.has_contents() {
- if let Some(prev_pos) = prev_pos {
- crate::term::MoveFromTo::new(prev_pos, pos)
- .write_buf(contents);
- } else {
- crate::term::MoveTo::new(pos).write_buf(contents);
- }
- cell.attrs().write_escape_code_diff(contents, &prev_attrs);
- contents.extend(cell.contents().as_bytes());
- prev_attrs.write_escape_code_diff(contents, cell.attrs());
- } else {
- // if the cell doesn't have contents, we can't have gotten
- // here by drawing a character in the last column. this means
- // that as far as i'm aware, we have to have reached here from
- // a newline when we were already after the end of an earlier
- // row. in the case where we are already after the end of an
- // earlier row, we can just write a few newlines, otherwise we
- // also need to do the same as above to get ourselves to after
- // the end of a row.
- let mut found = false;
- for i in (0..self.pos.row).rev() {
- pos.row = i;
- pos.col = self.size.cols - 1;
- if self
- .drawing_cell(pos)
- // i is always less than self.pos.row, which we assume
- // to be always valid, so it must also be valid.
- // self.size.cols - 1 is always a valid col.
- .unwrap()
- .is_wide_continuation()
- {
- pos.col = self.size.cols - 2;
- }
- let cell = self
- .drawing_cell(pos)
- // i is always less than self.pos.row, which we assume
- // to be always valid, so it must also be valid.
- // self.size.cols - 2 is valid because self.size.cols
- // - 1 is always valid, and col gets set to
- // self.size.cols - 2 when the cell at self.size.cols
- // - 1 is a wide continuation character, meaning that
- // the first half of the wide character must be before
- // it
- .unwrap();
- if cell.has_contents() {
- if let Some(prev_pos) = prev_pos {
- if prev_pos.row != i
- || prev_pos.col < self.size.cols
- {
- crate::term::MoveFromTo::new(prev_pos, pos)
- .write_buf(contents);
- cell.attrs().write_escape_code_diff(
- contents,
- &prev_attrs,
- );
- contents.extend(cell.contents().as_bytes());
- prev_attrs.write_escape_code_diff(
- contents,
- cell.attrs(),
- );
- }
- } else {
- crate::term::MoveTo::new(pos).write_buf(contents);
- cell.attrs().write_escape_code_diff(
- contents,
- &prev_attrs,
- );
- contents.extend(cell.contents().as_bytes());
- prev_attrs.write_escape_code_diff(
- contents,
- cell.attrs(),
- );
- }
- contents.extend(
- "\n".repeat(usize::from(self.pos.row - i))
- .as_bytes(),
- );
- found = true;
- break;
- }
- }
-
- // this can happen if you get the cursor off the end of a row,
- // and then do something to clear the end of the current row
- // without moving the cursor (IL, DL, ED, EL, etc). we know
- // there can't be something in the last column because we
- // would have caught that above, so it should be safe to
- // overwrite it.
- if !found {
- pos = Pos {
- row: self.pos.row,
- col: self.size.cols - 1,
- };
- if let Some(prev_pos) = prev_pos {
- crate::term::MoveFromTo::new(prev_pos, pos)
- .write_buf(contents);
- } else {
- crate::term::MoveTo::new(pos).write_buf(contents);
- }
- contents.push(b' ');
- // we know that the cell has no contents, but it still may
- // have drawing attributes (background color, etc)
- let end_cell = self
- .drawing_cell(pos)
- // we assume self.pos.row is always valid, and
- // self.size.cols - 1 is always a valid column
- .unwrap();
- end_cell
- .attrs()
- .write_escape_code_diff(contents, &prev_attrs);
- crate::term::SaveCursor.write_buf(contents);
- crate::term::Backspace.write_buf(contents);
- crate::term::EraseChar::new(1).write_buf(contents);
- crate::term::RestoreCursor.write_buf(contents);
- prev_attrs
- .write_escape_code_diff(contents, end_cell.attrs());
- }
- }
- } else if let Some(prev_pos) = prev_pos {
- crate::term::MoveFromTo::new(prev_pos, self.pos)
- .write_buf(contents);
- } else {
- crate::term::MoveTo::new(self.pos).write_buf(contents);
- }
- }
-
- pub fn erase_all(&mut self, attrs: crate::attrs::Attrs) {
- for row in self.drawing_rows_mut() {
- row.clear(attrs);
- }
- }
-
- pub fn erase_all_forward(&mut self, attrs: crate::attrs::Attrs) {
- let pos = self.pos;
- for row in self.drawing_rows_mut().skip(usize::from(pos.row) + 1) {
- row.clear(attrs);
- }
-
- self.erase_row_forward(attrs);
- }
-
- pub fn erase_all_backward(&mut self, attrs: crate::attrs::Attrs) {
- let pos = self.pos;
- for row in self.drawing_rows_mut().take(usize::from(pos.row)) {
- row.clear(attrs);
- }
-
- self.erase_row_backward(attrs);
- }
-
- pub fn erase_row(&mut self, attrs: crate::attrs::Attrs) {
- self.current_row_mut().clear(attrs);
- }
-
- pub fn erase_row_forward(&mut self, attrs: crate::attrs::Attrs) {
- let size = self.size;
- let pos = self.pos;
- let row = self.current_row_mut();
- for col in pos.col..size.cols {
- row.erase(col, attrs);
- }
- }
-
- pub fn erase_row_backward(&mut self, attrs: crate::attrs::Attrs) {
- let size = self.size;
- let pos = self.pos;
- let row = self.current_row_mut();
- for col in 0..=pos.col.min(size.cols - 1) {
- row.erase(col, attrs);
- }
- }
-
- pub fn insert_cells(&mut self, count: u16) {
- let size = self.size;
- let pos = self.pos;
- let wide = pos.col < size.cols
- && self
- .drawing_cell(pos)
- // we assume self.pos.row is always valid, and we know we are
- // not off the end of a row because we just checked pos.col <
- // size.cols
- .unwrap()
- .is_wide_continuation();
- let row = self.current_row_mut();
- for _ in 0..count {
- if wide {
- row.get_mut(pos.col).unwrap().set_wide_continuation(false);
- }
- row.insert(pos.col, crate::Cell::new());
- if wide {
- row.get_mut(pos.col).unwrap().set_wide_continuation(true);
- }
- }
- row.truncate(size.cols);
- }
-
- pub fn delete_cells(&mut self, count: u16) {
- let size = self.size;
- let pos = self.pos;
- let row = self.current_row_mut();
- for _ in 0..(count.min(size.cols - pos.col)) {
- row.remove(pos.col);
- }
- row.resize(size.cols, crate::Cell::new());
- }
-
- pub fn erase_cells(&mut self, count: u16, attrs: crate::attrs::Attrs) {
- let size = self.size;
- let pos = self.pos;
- let row = self.current_row_mut();
- for col in pos.col..((pos.col.saturating_add(count)).min(size.cols)) {
- row.erase(col, attrs);
- }
- }
-
- pub fn insert_lines(&mut self, count: u16) {
- for _ in 0..count {
- self.rows.remove(usize::from(self.scroll_bottom));
- self.rows.insert(usize::from(self.pos.row), self.new_row());
- // self.scroll_bottom is maintained to always be a valid row
- self.rows[usize::from(self.scroll_bottom)].wrap(false);
- }
- }
-
- pub fn delete_lines(&mut self, count: u16) {
- for _ in 0..(count.min(self.size.rows - self.pos.row)) {
- self.rows
- .insert(usize::from(self.scroll_bottom) + 1, self.new_row());
- self.rows.remove(usize::from(self.pos.row));
- }
- }
-
- pub fn scroll_up(&mut self, count: u16) {
- for _ in 0..(count.min(self.size.rows - self.scroll_top)) {
- self.rows
- .insert(usize::from(self.scroll_bottom) + 1, self.new_row());
- let removed = self.rows.remove(usize::from(self.scroll_top));
- // Top-anchored scroll regions still represent terminal output moving
- // off the visible transcript and should feed host scrollback.
- if self.scrollback_len > 0 && self.scroll_top == 0 {
- self.scrollback.push_back(removed);
- while self.scrollback.len() > self.scrollback_len {
- self.scrollback.pop_front();
- }
- if self.scrollback_offset > 0 {
- self.scrollback_offset =
- self.scrollback.len().min(self.scrollback_offset + 1);
- }
- }
- }
- }
-
- pub fn scroll_down(&mut self, count: u16) {
- for _ in 0..count {
- self.rows.remove(usize::from(self.scroll_bottom));
- self.rows
- .insert(usize::from(self.scroll_top), self.new_row());
- // self.scroll_bottom is maintained to always be a valid row
- self.rows[usize::from(self.scroll_bottom)].wrap(false);
- }
- }
-
- pub fn set_scroll_region(&mut self, top: u16, bottom: u16) {
- let bottom = bottom.min(self.size().rows - 1);
- if top < bottom {
- self.scroll_top = top;
- self.scroll_bottom = bottom;
- } else {
- self.scroll_top = 0;
- self.scroll_bottom = self.size().rows - 1;
- }
- self.pos.row = self.scroll_top;
- self.pos.col = 0;
- }
-
- fn in_scroll_region(&self) -> bool {
- self.pos.row >= self.scroll_top && self.pos.row <= self.scroll_bottom
- }
-
- pub fn set_origin_mode(&mut self, mode: bool) {
- self.origin_mode = mode;
- self.set_pos(Pos { row: 0, col: 0 });
- }
-
- pub fn row_inc_clamp(&mut self, count: u16) {
- let in_scroll_region = self.in_scroll_region();
- self.pos.row = self.pos.row.saturating_add(count);
- self.row_clamp_bottom(in_scroll_region);
- }
-
- pub fn row_inc_scroll(&mut self, count: u16) -> u16 {
- let in_scroll_region = self.in_scroll_region();
- self.pos.row = self.pos.row.saturating_add(count);
- let lines = self.row_clamp_bottom(in_scroll_region);
- if in_scroll_region {
- self.scroll_up(lines);
- lines
- } else {
- 0
- }
- }
-
- pub fn row_dec_clamp(&mut self, count: u16) {
- let in_scroll_region = self.in_scroll_region();
- self.pos.row = self.pos.row.saturating_sub(count);
- self.row_clamp_top(in_scroll_region);
- }
-
- pub fn row_dec_scroll(&mut self, count: u16) {
- let in_scroll_region = self.in_scroll_region();
- // need to account for clamping by both row_clamp_top and by
- // saturating_sub
- let extra_lines = count.saturating_sub(self.pos.row);
- self.pos.row = self.pos.row.saturating_sub(count);
- let lines = self.row_clamp_top(in_scroll_region);
- self.scroll_down(lines + extra_lines);
- }
-
- pub fn row_set(&mut self, i: u16) {
- self.pos.row = i;
- self.row_clamp();
- }
-
- pub fn col_inc(&mut self, count: u16) {
- self.pos.col = self.pos.col.saturating_add(count);
- }
-
- pub fn col_inc_clamp(&mut self, count: u16) {
- self.pos.col = self.pos.col.saturating_add(count);
- self.col_clamp();
- }
-
- pub fn col_dec(&mut self, count: u16) {
- self.pos.col = self.pos.col.saturating_sub(count);
- }
-
- pub fn col_tab(&mut self) {
- self.pos.col -= self.pos.col % 8;
- self.pos.col += 8;
- self.col_clamp();
- }
-
- pub fn col_set(&mut self, i: u16) {
- self.pos.col = i;
- self.col_clamp();
- }
-
- pub fn col_wrap(&mut self, width: u16, wrap: bool) {
- if self.pos.col > self.size.cols - width {
- let mut prev_pos = self.pos;
- self.pos.col = 0;
- let scrolled = self.row_inc_scroll(1);
- prev_pos.row -= scrolled;
- let new_pos = self.pos;
- self.drawing_row_mut(prev_pos.row)
- // we assume self.pos.row is always valid, and so prev_pos.row
- // must be valid because it is always less than or equal to
- // self.pos.row
- .unwrap()
- .wrap(wrap && prev_pos.row + 1 == new_pos.row);
- }
- }
-
- fn row_clamp_top(&mut self, limit_to_scroll_region: bool) -> u16 {
- if limit_to_scroll_region && self.pos.row < self.scroll_top {
- let rows = self.scroll_top - self.pos.row;
- self.pos.row = self.scroll_top;
- rows
- } else {
- 0
- }
- }
-
- fn row_clamp_bottom(&mut self, limit_to_scroll_region: bool) -> u16 {
- let bottom = if limit_to_scroll_region {
- self.scroll_bottom
- } else {
- self.size.rows - 1
- };
- if self.pos.row > bottom {
- let rows = self.pos.row - bottom;
- self.pos.row = bottom;
- rows
- } else {
- 0
- }
- }
-
- fn row_clamp(&mut self) {
- if self.pos.row > self.size.rows - 1 {
- self.pos.row = self.size.rows - 1;
- }
- }
-
- fn col_clamp(&mut self) {
- if self.pos.col > self.size.cols - 1 {
- self.pos.col = self.size.cols - 1;
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
-pub struct Size {
- pub rows: u16,
- pub cols: u16,
-}
-
-#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
-pub struct Pos {
- pub row: u16,
- pub col: u16,
-}