Skip to content

Commit 051bb8a

Browse files
authored
Merge pull request #14 from Neotron-Compute/fix_scroll
2 parents 6675aca + 6e72c19 commit 051bb8a

File tree

2 files changed

+77
-20
lines changed

2 files changed

+77
-20
lines changed

src/lib.rs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,32 @@ static mut SERIAL_CONSOLE: Option<SerialConsole> = None;
3434

3535
static OS_MENU: menu::Menu<Ctx> = menu::Menu {
3636
label: "root",
37-
items: &[&menu::Item {
38-
item_type: menu::ItemType::Callback {
39-
function: cmd_mem,
40-
parameters: &[],
37+
items: &[
38+
&menu::Item {
39+
item_type: menu::ItemType::Callback {
40+
function: cmd_mem,
41+
parameters: &[],
42+
},
43+
command: "mem",
44+
help: Some("Show memory regions"),
4145
},
42-
command: "mem",
43-
help: Some("Show memory regions"),
44-
}],
46+
&menu::Item {
47+
item_type: menu::ItemType::Callback {
48+
function: cmd_clear,
49+
parameters: &[],
50+
},
51+
command: "clear",
52+
help: Some("Clear the screen"),
53+
},
54+
&menu::Item {
55+
item_type: menu::ItemType::Callback {
56+
function: cmd_fill,
57+
parameters: &[],
58+
},
59+
command: "fill",
60+
help: Some("Fill the screen with characters"),
61+
},
62+
],
4563
entry: None,
4664
exit: None,
4765
};
@@ -264,6 +282,34 @@ fn cmd_mem(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _co
264282
}
265283
}
266284

285+
/// Called when the "clear" command is executed.
286+
fn cmd_clear(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _context: &mut Ctx) {
287+
if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } {
288+
console.clear();
289+
}
290+
}
291+
292+
/// Called when the "fill" command is executed.
293+
fn cmd_fill(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _context: &mut Ctx) {
294+
if let Some(ref mut console) = unsafe { &mut VGA_CONSOLE } {
295+
console.clear();
296+
}
297+
let api = API.get();
298+
let mode = (api.video_get_mode)();
299+
let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else {
300+
println!("Unable to get console size");
301+
return;
302+
};
303+
// A range of printable ASCII compatible characters
304+
let mut char_cycle = (' '..='~').cycle();
305+
// Scroll two screen fulls
306+
for _row in 0..height * 2 {
307+
for _col in 0..width {
308+
print!("{}", char_cycle.next().unwrap());
309+
}
310+
}
311+
}
312+
267313
/// Called when we have a panic.
268314
#[inline(never)]
269315
#[panic_handler]

src/vgaconsole.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,40 @@ impl VgaConsole {
3434
self.row += 1;
3535
}
3636

37+
fn reset_cursor(&mut self) {
38+
self.row = 0;
39+
self.col = 0;
40+
}
41+
3742
fn scroll_as_required(&mut self) {
38-
if self.col == self.width {
43+
assert!(self.row <= self.height);
44+
if self.col >= self.width {
3945
self.col = 0;
4046
self.row += 1;
4147
}
4248
if self.row == self.height {
43-
self.row = self.height - 1;
49+
self.row -= 1;
4450
self.scroll_page();
4551
}
4652
}
4753

4854
pub fn clear(&mut self) {
4955
for row in 0..self.height {
5056
for col in 0..self.width {
51-
self.row = row;
52-
self.col = col;
53-
self.write(b' ', Some(Self::DEFAULT_ATTR));
57+
self.write_at(row, col, b' ', Some(Self::DEFAULT_ATTR));
5458
}
5559
}
56-
self.row = 0;
57-
self.col = 0;
60+
self.reset_cursor();
5861
}
5962

6063
fn write(&mut self, glyph: u8, attr: Option<u8>) {
61-
let offset = ((self.row * self.width) + self.col) * 2;
64+
self.write_at(self.row, self.col, glyph, attr);
65+
}
66+
67+
fn write_at(&mut self, row: isize, col: isize, glyph: u8, attr: Option<u8>) {
68+
assert!(row < self.height, "{} >= {}?", row, self.height);
69+
assert!(col < self.width, "{} => {}?", col, self.width);
70+
let offset = ((row * self.width) + col) * 2;
6271
unsafe { core::ptr::write_volatile(self.addr.offset(offset), glyph) };
6372
if let Some(a) = attr {
6473
unsafe { core::ptr::write_volatile(self.addr.offset(offset + 1), a) };
@@ -68,17 +77,16 @@ impl VgaConsole {
6877
fn scroll_page(&mut self) {
6978
let row_len_bytes = self.width * 2;
7079
unsafe {
80+
// Scroll rows[1..=height-1] to become rows[0..=height-2].
7181
core::ptr::copy(
7282
self.addr.offset(row_len_bytes),
7383
self.addr,
7484
(row_len_bytes * (self.height - 1)) as usize,
7585
);
76-
// Blank bottom line
86+
// Blank the bottom line of the screen (rows[height-1]).
7787
for col in 0..self.width {
78-
self.col = col;
79-
self.write(b' ', Some(Self::DEFAULT_ATTR));
88+
self.write_at(self.height - 1, col, b' ', Some(Self::DEFAULT_ATTR));
8089
}
81-
self.col = 0;
8290
}
8391
}
8492

@@ -228,8 +236,12 @@ impl VgaConsole {
228236
impl core::fmt::Write for VgaConsole {
229237
fn write_str(&mut self, data: &str) -> core::fmt::Result {
230238
for ch in data.chars() {
239+
self.scroll_as_required();
231240
match ch {
232241
'\u{0008}' => {
242+
// This is a backspace, so we go back one character (if we
243+
// can). We expect the caller to provide "\u{0008} \u{0008}"
244+
// to actually erase the char then move the cursor over it.
233245
if self.col > 0 {
234246
self.col -= 1;
235247
}
@@ -242,7 +254,6 @@ impl core::fmt::Write for VgaConsole {
242254
self.move_char_down();
243255
}
244256
_ => {
245-
self.scroll_as_required();
246257
self.write(Self::map_char_to_glyph(ch), None);
247258
self.move_char_right();
248259
}

0 commit comments

Comments
 (0)