diff --git a/src/api/prompt.rs b/src/api/prompt.rs index 4cea61f1..e41de9b8 100644 --- a/src/api/prompt.rs +++ b/src/api/prompt.rs @@ -5,12 +5,14 @@ use alloc::vec::Vec; use core::cmp; use vte::{Params, Parser, Perform}; +const MAX_WIDTH: usize = 80; + pub struct Prompt { pub completion: Completion, pub history: History, - offset: usize, // Offset line by the length of the prompt string + offset: usize, // Offset input by the length of the prompt string cursor: usize, - line: Vec, // UTF-32 + input: Vec, // UTF-32 } impl Prompt { @@ -20,7 +22,7 @@ impl Prompt { history: History::new(), offset: 0, cursor: 0, - line: Vec::with_capacity(80), + input: Vec::with_capacity(MAX_WIDTH), } } @@ -28,7 +30,7 @@ impl Prompt { print!("{}", prompt); self.offset = offset_from_prompt(prompt); self.cursor = self.offset; - self.line = Vec::with_capacity(80); + self.input = Vec::with_capacity(MAX_WIDTH); let mut parser = Parser::new(); while let Some(c) = io::stdin().read_char() { match c { @@ -44,7 +46,7 @@ impl Prompt { self.update_completion(); self.update_history(); println!(); - return Some(self.line.iter().collect()); + return Some(self.input.iter().collect()); }, c => { for b in c.to_string().as_bytes() { @@ -59,7 +61,7 @@ impl Prompt { fn update_history(&mut self) { if let Some(i) = self.history.pos { - self.line = self.history.entries[i].chars().collect(); + self.input = self.history.entries[i].chars().collect(); self.history.pos = None; } } @@ -68,7 +70,7 @@ impl Prompt { if let Some(i) = self.completion.pos { let complete = self.completion.entries[i].chars(); self.cursor += complete.clone().count(); - self.line.extend(complete); + self.input.extend(complete); self.completion.pos = None; self.completion.entries = Vec::new(); } @@ -91,8 +93,8 @@ impl Prompt { } }, None => { - let line: String = self.line.iter().collect(); - self.completion.entries = (self.completion.completer)(&line); + let input: String = self.input.iter().collect(); + self.completion.entries = (self.completion.completer)(&input); if !self.completion.entries.is_empty() { (0, 0) } else { @@ -123,8 +125,8 @@ impl Prompt { } }, None => { - let line: String = self.line.iter().collect(); - self.completion.entries = (self.completion.completer)(&line); + let input: String = self.input.iter().collect(); + self.completion.entries = (self.completion.completer)(&input); if !self.completion.entries.is_empty() { (0, 0) } else { @@ -146,13 +148,13 @@ impl Prompt { } let (bs, i) = match self.history.pos { Some(i) => (self.history.entries[i].chars().count(), cmp::max(i, 1) - 1), - None => (self.line.len(), n - 1), + None => (self.input.len(), n - 1), }; - let line = &self.history.entries[i]; + let input = &self.history.entries[i]; let blank = ' '.to_string().repeat((self.offset + bs) - self.cursor); let erase = '\x08'.to_string().repeat(bs); - print!("{}{}{}", blank, erase, line); - self.cursor = self.offset + line.chars().count(); + print!("{}{}{}", blank, erase, input); + self.cursor = self.offset + input.chars().count(); self.history.pos = Some(i); } @@ -166,22 +168,26 @@ impl Prompt { Some(i) => (self.history.entries[i].chars().count(), i + 1), None => return, }; - let (pos, line) = if i < n { + let (pos, input) = if i < n { (Some(i), self.history.entries[i].clone()) } else { - (None, self.line.iter().collect()) + (None, self.input.iter().collect()) }; let erase = '\x08'.to_string().repeat(bs); - print!("{}{}", erase, line); - self.cursor = self.offset + line.chars().count(); + print!("{}{}", erase, input); + self.cursor = self.offset + input.chars().count(); self.history.pos = pos; } fn handle_forward_key(&mut self) { self.update_completion(); self.update_history(); - if self.cursor < self.offset + self.line.len() { - print!("\x1b[1C"); + if self.cursor < self.offset + self.input.len() { + if self.cursor % MAX_WIDTH == MAX_WIDTH - 1 { // Move cursor to begining of next line + print!("\x1b[1E"); + } else { + print!("\x1b[1C"); + } self.cursor += 1; } } @@ -190,7 +196,12 @@ impl Prompt { self.update_completion(); self.update_history(); if self.cursor > self.offset { - print!("\x1b[1D"); + if self.cursor % MAX_WIDTH == 0 { // Move cursor to end of previous line + print!("\x1b[1F"); + print!("\x1b[{}G", MAX_WIDTH); + } else { + print!("\x1b[1D"); + } self.cursor -= 1; } } @@ -198,10 +209,10 @@ impl Prompt { fn handle_delete_key(&mut self) { self.update_completion(); self.update_history(); - if self.cursor < self.offset + self.line.len() { + if self.cursor < self.offset + self.input.len() { let i = self.cursor - self.offset; - self.line.remove(i); - let s = &self.line[i..]; // UTF-32 + self.input.remove(i); + let s = &self.input[i..]; // UTF-32 let n = s.len() + 1; let s: String = s.iter().collect(); // UTF-8 print!("{} \x1b[{}D", s, n); @@ -213,8 +224,8 @@ impl Prompt { self.update_history(); if self.cursor > self.offset { let i = self.cursor - self.offset - 1; - self.line.remove(i); - let s = &self.line[i..]; // UTF-32 + self.input.remove(i); + let s = &self.input[i..]; // UTF-32 let n = s.len() + 1; let s: String = s.iter().collect(); // UTF-8 print!("\x08{} \x1b[{}D", s, n); @@ -227,8 +238,8 @@ impl Prompt { self.update_history(); if console::is_printable(c) { let i = self.cursor - self.offset; - self.line.insert(i, c); - let s = &self.line[i..]; // UTF-32 + self.input.insert(i, c); + let s = &self.input[i..]; // UTF-32 let n = s.len(); let s: String = s.iter().collect(); // UTF-8 print!("{} \x1b[{}D", s, n); @@ -279,7 +290,7 @@ pub struct Completion { pos: Option, } -fn empty_completer(_line: &str) -> Vec { +fn empty_completer(_input: &str) -> Vec { Vec::new() } diff --git a/src/sys/vga.rs b/src/sys/vga.rs index e2d6c1c1..ce735430 100644 --- a/src/sys/vga.rs +++ b/src/sys/vga.rs @@ -4,6 +4,7 @@ use crate::api::vga::color; use crate::sys; use bit_field::BitField; +use core::cmp; use core::fmt; use core::fmt::Write; use lazy_static::lazy_static; @@ -286,74 +287,62 @@ impl Perform for Writer { } fn csi_dispatch(&mut self, params: &Params, _: &[u8], _: bool, c: char) { + let n = params.iter().next().map_or(1, |param| param[0] as usize); + match c { 'm' => { let mut fg = FG; let mut bg = BG; - for param in params.iter() { - match param[0] { - 0 => { - fg = FG; - bg = BG; - }, - 30..=37 | 90..=97 => { - fg = color::from_ansi(param[0] as u8); - }, - 40..=47 | 100..=107 => { - bg = color::from_ansi((param[0] as u8) - 10); - }, - _ => {}, - } + match n { + 0 => { + fg = FG; + bg = BG; + }, + 30..=37 | 90..=97 => { + fg = color::from_ansi(n as u8); + }, + 40..=47 | 100..=107 => { + bg = color::from_ansi((n as u8) - 10); + }, + _ => {}, } self.set_color(fg, bg); }, 'A' => { // Cursor Up - let mut n = 1; - for param in params.iter() { - n = param[0] as usize; - } - // TODO: Don't go past edge - self.writer[1] -= n; - self.cursor[1] -= n; + self.writer[1] = cmp::max(self.writer[1] - n, 0); + self.cursor[1] = cmp::max(self.cursor[1] - n, 0); }, 'B' => { // Cursor Down - let mut n = 1; - for param in params.iter() { - n = param[0] as usize; - } - // TODO: Don't go past edge - self.writer[1] += n; - self.cursor[1] += n; + self.writer[1] = cmp::min(self.writer[1] + n, BUFFER_HEIGHT - 1); + self.cursor[1] = cmp::min(self.cursor[1] + n, BUFFER_HEIGHT - 1); }, 'C' => { // Cursor Forward - let mut n = 1; - for param in params.iter() { - n = param[0] as usize; - } - // TODO: Don't go past edge - self.writer[0] += n; - self.cursor[0] += n; + self.writer[0] = cmp::min(self.writer[0] + n, BUFFER_WIDTH - 1); + self.cursor[0] = cmp::min(self.cursor[0] + n, BUFFER_WIDTH - 1); }, 'D' => { // Cursor Backward - let mut n = 1; - for param in params.iter() { - n = param[0] as usize; - } - // TODO: Don't go past edge - self.writer[0] -= n; - self.cursor[0] -= n; + self.writer[0] = cmp::max(self.writer[0] - n, 0); + self.cursor[0] = cmp::max(self.cursor[0] - n, 0); + }, + 'E' => { // Cursor Next Line + self.writer[0] = 0; // TODO: What should we do at the last line? + self.cursor[0] = 0; + self.writer[1] = cmp::min(self.writer[1] + n, BUFFER_HEIGHT - 1); + self.cursor[1] = cmp::min(self.cursor[1] + n, BUFFER_HEIGHT - 1); + }, + 'F' => { // Cursor Previous Line + self.writer[0] = 0; + self.cursor[0] = 0; + self.writer[1] = cmp::max(self.writer[1] - n, 0); + self.cursor[1] = cmp::max(self.cursor[1] - n, 0); }, 'G' => { // Cursor Horizontal Absolute - let (_, y) = self.cursor_position(); - let mut x = 1; - for param in params.iter() { - x = param[0] as usize; // 1-indexed value + let x = n - 1; // 1-indexed value + let y = self.cursor_position().1; + if x < BUFFER_WIDTH { + self.set_writer_position(x, y); + self.set_cursor_position(x, y); } - if x > BUFFER_WIDTH { - return; - } - self.set_writer_position(x - 1, y); - self.set_cursor_position(x - 1, y); }, 'H' => { // Move cursor let mut x = 1; @@ -372,10 +361,6 @@ impl Perform for Writer { self.set_cursor_position(x - 1, y - 1); }, 'J' => { // Erase in Display - let mut n = 0; - for param in params.iter() { - n = param[0] as usize; - } match n { // TODO: 0 and 1, from cursor to begining or to end of screen 2 => self.clear_screen(), @@ -386,10 +371,6 @@ impl Perform for Writer { }, 'K' => { // Erase in Line let (x, y) = self.cursor_position(); - let mut n = 0; - for param in params.iter() { - n = param[0] as usize; - } match n { 0 => self.clear_row_after(x, y), 1 => return, // TODO: self.clear_row_before(x, y), @@ -400,21 +381,17 @@ impl Perform for Writer { self.set_cursor_position(x, y); }, 'h' => { // Enable - for param in params.iter() { - match param[0] { - 12 => self.enable_echo(), - 25 => self.enable_cursor(), - _ => return, - } + match n { + 12 => self.enable_echo(), + 25 => self.enable_cursor(), + _ => return, } }, 'l' => { // Disable - for param in params.iter() { - match param[0] { - 12 => self.disable_echo(), - 25 => self.disable_cursor(), - _ => return, - } + match n { + 12 => self.disable_echo(), + 25 => self.disable_cursor(), + _ => return, } }, _ => {},