Skip to content

Commit d13aba3

Browse files
committed
feat(shell): 添加exit命令和退格键支持
1 parent 244398d commit d13aba3

File tree

3 files changed

+209
-10
lines changed

3 files changed

+209
-10
lines changed

kernel/src/libs/shell.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ impl Shell {
3333
"clear" => {
3434
print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
3535
}
36+
"exit" => {
37+
print!("goodbye!\n");
38+
// TODO: implement exit functionality
39+
}
3640
_ => {
3741
// ignore empty input, but report unknown commands
3842
if !command.trim().is_empty() {
@@ -59,12 +63,24 @@ impl Shell {
5963
}
6064
match device.read(&mut buf) {
6165
Ok(count) if count > 0 => {
62-
print!("{}", buf[0] as char);
63-
command.push(buf[0] as char);
64-
if buf[0] == '\n' as u8 {
65-
self.handle_command(command.as_str().trim());
66-
command.clear();
67-
need_prompt = true;
66+
let c = buf[0] as char;
67+
match c {
68+
'\x08' | '\x7f' => {
69+
if !command.is_empty() {
70+
command.pop();
71+
print!("{}", '\x08');
72+
}
73+
}
74+
'\n' | '\r' => {
75+
print!("\n");
76+
self.handle_command(command.trim());
77+
command.clear();
78+
need_prompt = true;
79+
}
80+
_ => {
81+
print!("{}", c);
82+
command.push(c);
83+
}
6884
}
6985
}
7086
Ok(_) => {

kernel/src/output/console/console_bitfont.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,35 @@ impl BitfontConsole {
138138
self.position.1 = self.height - FONT_H;
139139
}
140140

141+
// Backspace
142+
if c == 0x08 {
143+
if self.position.0 >= FONT_W {
144+
self.position.0 -= FONT_W;
145+
146+
// Clear the character (draw background rect)
147+
let start_x = self.position.0;
148+
let start_y = self.position.1;
149+
150+
// We use the same loop logic as print_normal_char but writing bg_color everywhere
151+
for line in 0..FONT_H {
152+
for i in 0..FONT_W {
153+
let x = start_x + i;
154+
let y = start_y + line;
155+
if x < self.width && y < self.height {
156+
let pixel_offset = y * self.pitch + x * 4;
157+
unsafe {
158+
self.address
159+
.add(pixel_offset as usize)
160+
.cast::<u32>()
161+
.write(self.bg_color.to_u32(true));
162+
}
163+
}
164+
}
165+
}
166+
}
167+
return;
168+
}
169+
141170
// If character is "\n", just switch to next line.
142171
if c == ('\n' as usize) {
143172
self.position.0 = 0;
@@ -193,6 +222,7 @@ impl BitfontConsole {
193222
fn parse_ansi_command(&mut self, cmd: u8) {
194223
match cmd {
195224
b'm' => self.handle_sgr(),
225+
b'J' => self.handle_erase_display(),
196226
b'A' => self.handle_cursor_up(),
197227
b'B' => self.handle_cursor_down(),
198228
b'C' => self.handle_cursor_right(),
@@ -240,6 +270,49 @@ impl BitfontConsole {
240270
self.current_param = 0;
241271
}
242272

273+
// Handle erase display ANSI command (ESC [ n J)
274+
// n=0: clear from cursor to end of screen
275+
// n=1: clear from beginning to cursor
276+
// n=2: clear entire screen and move cursor to top-left
277+
fn handle_erase_display(&mut self) {
278+
let param = if self.ansi_params.is_empty() {
279+
0
280+
} else {
281+
self.ansi_params[0]
282+
};
283+
284+
match param {
285+
2 => {
286+
// Clear entire screen and reset cursor
287+
unsafe {
288+
core::ptr::write_bytes(self.address, 0, (self.height * self.pitch) as usize);
289+
}
290+
self.position = (0, 0);
291+
}
292+
0 => {
293+
// Clear from cursor to end of screen
294+
let start_x = self.position.0;
295+
let start_y = self.position.1;
296+
let start_offset = start_y * self.pitch + start_x * 4;
297+
let total_bytes = (self.height * self.pitch) as usize;
298+
let clear_bytes = total_bytes - start_offset as usize;
299+
unsafe {
300+
core::ptr::write_bytes(self.address.add(start_offset as usize), 0, clear_bytes);
301+
}
302+
}
303+
1 => {
304+
// Clear from beginning to cursor
305+
let end_offset = self.position.1 * self.pitch + self.position.0 * 4 + 4 * FONT_W;
306+
unsafe {
307+
core::ptr::write_bytes(self.address, 0, end_offset as usize);
308+
}
309+
}
310+
_ => {}
311+
}
312+
self.ansi_params.clear();
313+
self.current_param = 0;
314+
}
315+
243316
/// Print a string to console.
244317
pub fn print_string(&mut self, s: &str) {
245318
for c in s.bytes() {

kernel/src/output/console/console_ttf.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ impl<'a> TtfConsole<'a> {
285285
self.cursor_needs_redraw = true;
286286

287287
if actual_lines.abs() < self.height_chars as i32 {
288+
if !self.hidden_cursor {
289+
self.restore_cursor_bg();
290+
}
288291
let pixel_offset = -(actual_lines * self.font_height as i32);
289292
self.renderer.scroll_y(pixel_offset as i64);
290293

@@ -367,6 +370,9 @@ impl<'a> TtfConsole<'a> {
367370
self.cursor_y = self.height_chars - 1;
368371

369372
if old_scroll_offset_y != self.scroll_offset_y {
373+
if !self.hidden_cursor {
374+
self.restore_cursor_bg();
375+
}
370376
let pixel_offset = -(lines_to_scroll as i32 * self.font_height as i32);
371377
self.renderer.scroll_y(pixel_offset as i64);
372378

@@ -484,10 +490,7 @@ impl<'a> TtfConsole<'a> {
484490
}
485491
}
486492

487-
pub fn draw_cursor(&mut self) {
488-
if !self.cursor_needs_redraw || self.hidden_cursor {
489-
return;
490-
}
493+
fn restore_cursor_bg(&mut self) {
491494
if self.prev_cursor_y < self.height_chars {
492495
let prev_x = self.prev_cursor_x;
493496
let prev_y = self.prev_cursor_y;
@@ -514,6 +517,14 @@ impl<'a> TtfConsole<'a> {
514517
);
515518
}
516519
}
520+
}
521+
522+
pub fn draw_cursor(&mut self) {
523+
if !self.cursor_needs_redraw || self.hidden_cursor {
524+
return;
525+
}
526+
self.restore_cursor_bg();
527+
517528
if self.cursor_y < self.height_chars {
518529
let cursor_x_px = self.cursor_x * self.font_width;
519530
let cursor_y_px = self.cursor_y * self.font_height;
@@ -626,6 +637,29 @@ impl<'a> TtfConsole<'a> {
626637
}
627638
}
628639
}
640+
'\x08' => {
641+
if self.cursor_x > 0 {
642+
self.cursor_x -= 1;
643+
// Clear the character in the buffer
644+
let buf_y = (self.cursor_y + self.scroll_offset_y as u32) as usize;
645+
let idx = buf_y * self.width_chars as usize + self.cursor_x as usize;
646+
647+
if let Some(cell) = self.buffer.get_mut(idx) {
648+
*cell = None;
649+
}
650+
651+
// Clear visually
652+
self.renderer.fill_rect(
653+
Pixel::new(
654+
(self.cursor_x * self.font_width) as u64,
655+
(self.cursor_y * self.font_height) as u64,
656+
),
657+
self.font_width as u64,
658+
self.font_height as u64,
659+
self.current_bg_color,
660+
);
661+
}
662+
}
629663
_ => {
630664
self.put_char_impl(c);
631665
self.cursor_x += 1;
@@ -674,6 +708,15 @@ impl<'a> TtfConsole<'a> {
674708

675709
self.apply_ansi_codes(&params[..count]);
676710
self.ansi_parse_state = AnsiParseState::Normal;
711+
} else if c == 'J' {
712+
// Handle erase display command
713+
let param = if self.ansi_has_digit {
714+
self.ansi_params[0]
715+
} else {
716+
0
717+
};
718+
self.handle_erase_display(param);
719+
self.ansi_parse_state = AnsiParseState::Normal;
677720
} else {
678721
self.ansi_parse_state = AnsiParseState::Normal;
679722
}
@@ -773,6 +816,50 @@ impl<'a> TtfConsole<'a> {
773816
self.redraw();
774817
}
775818
}
819+
820+
/// Handle erase display ANSI command (ESC [ n J)
821+
/// n=0: clear from cursor to end of screen
822+
/// n=1: clear from beginning to cursor
823+
/// n=2: clear entire screen and move cursor to top-left
824+
fn handle_erase_display(&mut self, n: u32) {
825+
match n {
826+
2 => {
827+
// Clear entire screen and reset cursor
828+
self.buffer.clear();
829+
self.buffer
830+
.resize((self.width_chars * self.height_chars) as usize, None);
831+
self.cursor_x = 0;
832+
self.cursor_y = 0;
833+
self.scroll_offset_y = 0;
834+
self.cursor_needs_redraw = true;
835+
self.redraw();
836+
}
837+
0 => {
838+
// Clear from cursor to end of screen
839+
let start_buf_y = (self.cursor_y + self.scroll_offset_y as u32) as usize;
840+
let start_idx = start_buf_y * self.width_chars as usize + self.cursor_x as usize;
841+
for i in start_idx..self.buffer.len() {
842+
if let Some(cell) = self.buffer.get_mut(i) {
843+
*cell = None;
844+
}
845+
}
846+
// Clear visually from cursor to end
847+
self.redraw();
848+
}
849+
1 => {
850+
// Clear from beginning to cursor
851+
let end_buf_y = (self.cursor_y + self.scroll_offset_y as u32) as usize;
852+
let end_idx = end_buf_y * self.width_chars as usize + self.cursor_x as usize;
853+
for i in 0..=end_idx.min(self.buffer.len() - 1) {
854+
if let Some(cell) = self.buffer.get_mut(i) {
855+
*cell = None;
856+
}
857+
}
858+
self.redraw();
859+
}
860+
_ => {}
861+
}
862+
}
776863
}
777864

778865
impl Write for TtfConsole<'_> {
@@ -845,6 +932,29 @@ impl<'a> crate::output::console::Console for TtfConsole<'a> {
845932
}
846933
}
847934
}
935+
'\x08' => {
936+
if self.cursor_x > 0 {
937+
self.cursor_x -= 1;
938+
// Clear the character in the buffer
939+
let buf_y = (self.cursor_y + self.scroll_offset_y as u32) as usize;
940+
let idx = buf_y * self.width_chars as usize + self.cursor_x as usize;
941+
942+
if let Some(cell) = self.buffer.get_mut(idx) {
943+
*cell = None;
944+
}
945+
946+
// Clear visually
947+
self.renderer.fill_rect(
948+
Pixel::new(
949+
(self.cursor_x * self.font_width) as u64,
950+
(self.cursor_y * self.font_height) as u64,
951+
),
952+
self.font_width as u64,
953+
self.font_height as u64,
954+
self.current_bg_color,
955+
);
956+
}
957+
}
848958
_ => {
849959
self.put_char_impl(ch);
850960
self.cursor_x += 1;

0 commit comments

Comments
 (0)