stevenkhan commited on
Commit
41a96ee
·
verified ·
1 Parent(s): 05879f6

Upload spectral-core/src/grid.rs

Browse files
Files changed (1) hide show
  1. spectral-core/src/grid.rs +186 -0
spectral-core/src/grid.rs ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ use crate::cell::Cell;
2
+
3
+ /// A line of terminal cells.
4
+ #[derive(Clone, Debug, Default, PartialEq)]
5
+ pub struct Line {
6
+ pub cells: Vec<Cell>,
7
+ pub dirty: bool,
8
+ pub wrapped: bool,
9
+ }
10
+
11
+ impl Line {
12
+ pub fn new(cols: usize) -> Self {
13
+ Self {
14
+ cells: vec![Cell::default(); cols],
15
+ dirty: false,
16
+ wrapped: false,
17
+ }
18
+ }
19
+
20
+ pub fn clear(&mut self) {
21
+ for cell in &mut self.cells {
22
+ cell.reset();
23
+ }
24
+ self.dirty = true;
25
+ self.wrapped = false;
26
+ }
27
+
28
+ pub fn resize(&mut self, cols: usize) {
29
+ if self.cells.len() < cols {
30
+ self.cells.resize(cols, Cell::default());
31
+ } else if self.cells.len() > cols {
32
+ self.cells.truncate(cols);
33
+ }
34
+ }
35
+ }
36
+
37
+ /// Terminal grid with scrollback buffer.
38
+ pub struct Grid {
39
+ pub lines: Vec<Line>,
40
+ pub scrollback: Vec<Line>,
41
+ pub cols: usize,
42
+ pub rows: usize,
43
+ pub scrollback_limit: usize,
44
+ pub cursor_row: usize,
45
+ pub cursor_col: usize,
46
+ pub saved_cursor_row: usize,
47
+ pub saved_cursor_col: usize,
48
+ pub top_margin: usize,
49
+ pub bottom_margin: usize,
50
+ }
51
+
52
+ impl Grid {
53
+ pub fn new(cols: usize, rows: usize, scrollback_limit: usize) -> Self {
54
+ Self {
55
+ lines: (0..rows).map(|_| Line::new(cols)).collect(),
56
+ scrollback: Vec::new(),
57
+ cols,
58
+ rows,
59
+ scrollback_limit,
60
+ cursor_row: 0,
61
+ cursor_col: 0,
62
+ saved_cursor_row: 0,
63
+ saved_cursor_col: 0,
64
+ top_margin: 0,
65
+ bottom_margin: rows.saturating_sub(1),
66
+ }
67
+ }
68
+
69
+ pub fn resize(&mut self, cols: usize, rows: usize) {
70
+ let old_rows = self.lines.len();
71
+
72
+ for line in &mut self.lines {
73
+ line.resize(cols);
74
+ }
75
+
76
+ if rows > old_rows {
77
+ self.lines.reserve(rows - old_rows);
78
+ for _ in old_rows..rows {
79
+ self.lines.push(Line::new(cols));
80
+ }
81
+ } else if rows < old_rows {
82
+ let excess = old_rows - rows;
83
+ let limit = self.scrollback_limit;
84
+ for line in self.lines.drain(0..excess) {
85
+ if self.scrollback.len() >= limit {
86
+ self.scrollback.remove(0);
87
+ }
88
+ self.scrollback.push(line);
89
+ }
90
+ }
91
+
92
+ self.cols = cols;
93
+ self.rows = rows;
94
+ self.cursor_row = self.cursor_row.min(rows.saturating_sub(1));
95
+ self.cursor_col = self.cursor_col.min(cols.saturating_sub(1));
96
+ self.top_margin = 0;
97
+ self.bottom_margin = rows.saturating_sub(1);
98
+ }
99
+
100
+ pub fn clear_screen(&mut self) {
101
+ for line in &mut self.lines {
102
+ line.clear();
103
+ }
104
+ }
105
+
106
+ pub fn clear_line(&mut self, row: usize) {
107
+ if let Some(line) = self.lines.get_mut(row) {
108
+ line.clear();
109
+ }
110
+ }
111
+
112
+ pub fn clear_line_right(&mut self, row: usize, col: usize) {
113
+ if let Some(line) = self.lines.get_mut(row) {
114
+ for cell in &mut line.cells[col..] {
115
+ cell.reset();
116
+ }
117
+ line.dirty = true;
118
+ }
119
+ }
120
+
121
+ pub fn clear_line_left(&mut self, row: usize, col: usize) {
122
+ if let Some(line) = self.lines.get_mut(row) {
123
+ for cell in &mut line.cells[..=col] {
124
+ cell.reset();
125
+ }
126
+ line.dirty = true;
127
+ }
128
+ }
129
+
130
+ pub fn scroll_up(&mut self, n: usize) {
131
+ let top = self.top_margin;
132
+ let bottom = self.bottom_margin;
133
+ let n = n.min(bottom.saturating_sub(top) + 1);
134
+
135
+ for _ in 0..n {
136
+ let removed = self.lines.remove(top);
137
+ if top == 0 && self.scrollback.len() < self.scrollback_limit {
138
+ self.scrollback.push(removed);
139
+ }
140
+ let mut new_line = Line::new(self.cols);
141
+ new_line.dirty = true;
142
+ self.lines.insert(bottom, new_line);
143
+ }
144
+
145
+ for i in top..=bottom {
146
+ if let Some(line) = self.lines.get_mut(i) {
147
+ line.dirty = true;
148
+ }
149
+ }
150
+ }
151
+
152
+ pub fn scroll_down(&mut self, n: usize) {
153
+ let top = self.top_margin;
154
+ let bottom = self.bottom_margin;
155
+ let n = n.min(bottom.saturating_sub(top) + 1);
156
+
157
+ for _ in 0..n {
158
+ self.lines.remove(bottom);
159
+ let mut new_line = Line::new(self.cols);
160
+ new_line.dirty = true;
161
+ self.lines.insert(top, new_line);
162
+ }
163
+
164
+ for i in top..=bottom {
165
+ if let Some(line) = self.lines.get_mut(i) {
166
+ line.dirty = true;
167
+ }
168
+ }
169
+ }
170
+
171
+ pub fn line(&self, row: usize) -> Option<&Line> {
172
+ self.lines.get(row)
173
+ }
174
+
175
+ pub fn line_mut(&mut self, row: usize) -> Option<&mut Line> {
176
+ self.lines.get_mut(row)
177
+ }
178
+
179
+ pub fn cell(&self, row: usize, col: usize) -> Option<&Cell> {
180
+ self.lines.get(row)?.cells.get(col)
181
+ }
182
+
183
+ pub fn cell_mut(&mut self, row: usize, col: usize) -> Option<&mut Cell> {
184
+ self.lines.get_mut(row)?.cells.get_mut(col)
185
+ }
186
+ }