strat9_kernel/arch/x86_64/vga/
scrollback.rs1use alloc::vec::Vec;
8
9pub(crate) const MAX_SCROLLBACK: usize = 500;
11
12#[derive(Clone, Copy)]
14pub(crate) struct SbCell {
15 pub ch: char,
16 pub fg: u32, pub bg: u32, }
19
20pub(crate) struct ScrollbackBuffer {
26 pub rows: Vec<Vec<SbCell>>,
28 pub cur_row: Vec<SbCell>,
30 pub row_head: usize,
32}
33
34impl ScrollbackBuffer {
35 pub const fn new() -> Self {
37 Self {
38 rows: Vec::new(),
39 cur_row: Vec::new(),
40 row_head: 0,
41 }
42 }
43
44 #[inline]
46 pub fn capacity(&self, visible_rows: usize) -> usize {
47 MAX_SCROLLBACK + visible_rows + 1
48 }
49
50 pub fn row_at(&self, logical_idx: usize) -> Option<&Vec<SbCell>> {
52 if logical_idx >= self.rows.len() {
53 return None;
54 }
55 let phys = (self.row_head + logical_idx) % self.rows.len();
56 self.rows.get(phys)
57 }
58
59 pub fn push_row(&mut self, row: Vec<SbCell>, visible_rows: usize) {
61 let cap = self.capacity(visible_rows);
62 if cap == 0 {
63 return;
64 }
65 if self.rows.len() < cap {
66 self.rows.push(row);
67 return;
68 }
69 if self.rows.is_empty() {
70 self.rows.push(row);
71 self.row_head = 0;
72 return;
73 }
74 self.rows[self.row_head] = row;
75 self.row_head = (self.row_head + 1) % self.rows.len();
76 }
77
78 #[inline]
80 pub fn trim(&mut self, visible_rows: usize) {
81 let cap = self.capacity(visible_rows);
82 if self.rows.len() <= cap {
83 return;
84 }
85 let remove_count = self.rows.len() - cap;
86 self.rows.drain(..remove_count);
87 self.row_head = 0;
88 }
89
90 pub fn mirror_char(&mut self, c: char, cols: usize, fg: u32, bg: u32, visible_rows: usize) {
96 match c {
97 '\n' => {
98 let row = core::mem::take(&mut self.cur_row);
99 self.push_row(row, visible_rows);
100 self.trim(visible_rows);
101 }
102 '\r' => {
103 self.cur_row.clear();
104 }
105 '\t' => {
106 let stop = (self.cur_row.len() + 4) & !3;
107 let end = stop.min(cols);
108 while self.cur_row.len() < end {
109 self.cur_row.push(SbCell { ch: ' ', fg, bg });
110 }
111 if self.cur_row.len() >= cols {
112 let row = core::mem::take(&mut self.cur_row);
113 self.push_row(row, visible_rows);
114 self.trim(visible_rows);
115 }
116 }
117 '\u{8}' => {
118 self.cur_row.pop();
119 }
120 '\0' => {}
121 ch => {
122 self.cur_row.push(SbCell { ch, fg, bg });
123 if self.cur_row.len() >= cols {
124 let row = core::mem::take(&mut self.cur_row);
125 self.push_row(row, visible_rows);
126 self.trim(visible_rows);
127 }
128 }
129 }
130 }
131}