diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 6c6aca1..d81265e 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,10 +5,11 @@ extern crate alloc; use libk::{ drivers::{ - io::{self, keyboard}, + io, scheduling::task::{Executor, Task}, }, prelude::*, + util::shell::shell, }; #[unsafe(no_mangle)] @@ -26,28 +27,7 @@ extern "C" fn kmain() -> ! { println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1); println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); - println!( - " - $$$$$$$$\\ $$\\ - $$ _____| $$ | - $$ | $$$$$$\\ $$\\ $$\\ $$$$$$$\\ $$$$$$$ | $$$$$$\\ $$\\ $$\\ - $$$$$\\ $$ __$$\\ $$ | $$ |$$ __$$\\ $$ __$$ |$$ __$$\\ $$ | $$ | - $$ __|$$ / $$ |$$ | $$ |$$ | $$ |$$ / $$ |$$ | \\__|$$ | $$ | - $$ | $$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ | $$ | - $$ | \\$$$$$$ |\\$$$$$$ |$$ | $$ |\\$$$$$$$ |$$ | \\$$$$$$$ | - \\__| \\______/ \\______/ \\__| \\__| \\_______|\\__| \\____$$ | - $$$$$$\\ $$$$$$\\ $$\\ $$\\ $$\\ $$\\ $$ | - $$ __$$\\ $$ __$$\\ $$ | $$ |$$$$ | \\$$$$$$ | - $$ / $$ |$$ / \\__| $$ | $$ |\\_$$ | \\______/ - $$ | $$ |\\$$$$$$\\ \\$$\\ $$ | $$ | - $$ | $$ | \\____$$\\ \\$$\\$$ / $$ | - $$ | $$ |$$\\ $$ | \\$$$ / $$ | - $$$$$$ |\\$$$$$$ | \\$ / $$$$$$\\ - \\______/ \\______/ \\_/ \\______| - " - ); - let mut executor = Executor::new(); - executor.spawn(Task::new(keyboard::print_keypresses())); + executor.spawn(Task::new(shell())); executor.run(); } diff --git a/libk/src/drivers/io/ascii/mod.rs b/libk/src/drivers/io/ascii/mod.rs index 949aa22..e57ab5d 100644 --- a/libk/src/drivers/io/ascii/mod.rs +++ b/libk/src/drivers/io/ascii/mod.rs @@ -29,9 +29,6 @@ pub struct Writer { fg_color: Colour, bg_color: Colour, - - offset1: usize, - offset2: usize, } impl Default for Writer { @@ -54,8 +51,6 @@ impl Writer { text_col: 0, fg_color: Colour::White, bg_color: Colour::Black, - offset1: 16, - offset2: 0, }, ) } @@ -65,10 +60,10 @@ impl Writer { } /// This is sent when the user types a backspace. - const BACKSPACE: u16 = 8; + const BACKSPACE: u8 = 8; - pub fn write_glyph(&mut self, c: u16) { - if c == b'\n' as u16 { + pub fn write_glyph(&mut self, c: u8) { + if c == b'\n' { self.newline(); return; } else if c == Self::BACKSPACE { @@ -104,11 +99,6 @@ impl Writer { } } - pub const fn set_offset(&mut self, offset1: usize, offset2: usize) { - self.offset1 = offset1; - self.offset2 = offset2; - } - pub const fn dimensions(&self) -> (u32, u32) { (self.screen_width, self.screen_height) } @@ -133,14 +123,14 @@ impl Writer { if self.text_col > 0 { self.text_col -= 1; // Blank out the previous char. - self.write_glyph(' ' as u16); + self.write_glyph(b' '); self.text_col -= 1; } } pub fn write_string(&mut self, s: &str) { for c in s.chars() { - self.write_glyph(c as u16); + self.write_glyph(c as u8); } } @@ -203,6 +193,14 @@ pub fn clear_screen() { }); } +pub fn reset_cursor() { + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writer.text_line = 0; + writer.text_col = 0; + }); +} + #[macro_export] macro_rules! println_log { () => ($crate::print_log!("\n")); diff --git a/libk/src/drivers/io/keyboard.rs b/libk/src/drivers/io/keyboard.rs index e2e9da2..a480a90 100644 --- a/libk/src/drivers/io/keyboard.rs +++ b/libk/src/drivers/io/keyboard.rs @@ -24,9 +24,8 @@ pub static KEYBOARD: Lazy>> = Lazy::new(| HandleControl::Ignore, )) }); - -pub static KEYBOARD_HANDLER: Lazy> = - Lazy::new(|| Mutex::new(KeyboardHandler::new())); +pub static SCANCODE_STREAM: Lazy> = + Lazy::new(|| Mutex::new(ScancodeStream::new())); pub fn add_scancode(scancode: u8) { if let Some(queue) = KBD_QUEUE.get() { @@ -49,6 +48,10 @@ impl ScancodeStream { KBD_QUEUE.call_once(|| ArrayQueue::new(5)); Self { _private: () } } + + pub fn try_next(&mut self) -> Option { + KBD_QUEUE.get().and_then(|queue| queue.pop()) + } } impl Default for ScancodeStream { @@ -77,42 +80,23 @@ impl Stream for ScancodeStream { } } -pub async fn print_keypresses() { - let mut scancodes = ScancodeStream::new(); - let mut keyboard = Keyboard::new( - ScancodeSet1::new(), - layouts::Uk105Key, - HandleControl::Ignore, - ); - - while let Some(scancode) = scancodes.next().await { - if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { - if let Some(key) = keyboard.process_keyevent(key_event) { - match key { - DecodedKey::Unicode(character) => print!("{}", character), - DecodedKey::RawKey(key) => print!("{:?}", key), - } +pub async fn get_keystroke_async() -> KeyStroke { + loop { + if let Some(scancode) = SCANCODE_STREAM.lock().next().await { + if let Ok(keystroke) = KeyStroke::try_from(scancode) { + return keystroke; } } } } -pub struct KeyboardHandler { - _scancodes: ScancodeStream, -} - -impl KeyboardHandler { - pub fn new() -> Self { - Self { - _scancodes: ScancodeStream::new(), +pub fn get_keystroke_optional() -> Option { + if let Some(scancode) = SCANCODE_STREAM.lock().try_next() { + if let Ok(keystroke) = KeyStroke::try_from(scancode) { + return Some(keystroke); } } -} - -impl Default for KeyboardHandler { - fn default() -> Self { - Self::new() - } + None } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -185,6 +169,17 @@ impl TryFrom for KeyStroke { } } +impl TryInto for KeyStroke { + type Error = (); + + fn try_into(self) -> Result { + match self { + Self::Char(c) => Ok(c), + _ => Err(()), + } + } +} + impl core::fmt::Display for KeyStroke { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { diff --git a/libk/src/lib.rs b/libk/src/lib.rs index a139d5b..1846161 100644 --- a/libk/src/lib.rs +++ b/libk/src/lib.rs @@ -21,6 +21,7 @@ extern crate alloc; pub mod drivers; pub mod resources; +pub mod util; #[allow(unused)] // We aren't using much of this right now. pub mod std; diff --git a/libk/src/std/io/io.rs b/libk/src/std/io/io.rs index d48d4ce..8802c1c 100644 --- a/libk/src/std/io/io.rs +++ b/libk/src/std/io/io.rs @@ -8,6 +8,11 @@ pub use crate::drivers::io::{ pub mod stdin { use alloc::string::String; + use crate::drivers::io::{ + ascii::WRITER, + keyboard::{KeyStroke, get_keystroke_async, get_keystroke_optional}, + }; + /// Reads a line of input from standard input asynchronously, returning a `String` containing /// the input line. Does not include the newline character at the end of the line. /// @@ -15,7 +20,45 @@ pub mod stdin { /// /// This function is currently unimplemented. pub async fn read_line() -> String { - todo!() + let mut writer = WRITER.lock(); + + let mut buff = String::new(); + loop { + match get_keystroke_async().await { + KeyStroke::Char(c) => match c { + '\n' => { + writer.write_glyph(c as u8); + return buff; + } + '\r' => { + writer.write_glyph(c as u8); + return buff; + } + '\x08' => { + if !buff.is_empty() { + buff.pop(); + writer.backspace(); + } + } + + c => { + writer.write_glyph(c as u8); + buff.push(c) + } + }, + KeyStroke::Enter => { + writer.write_glyph(b'\n'); + return buff; + } + KeyStroke::Backspace => { + if !buff.is_empty() { + buff.pop(); + writer.backspace(); + } + } + _ => continue, + } + } } /// Reads a character from standard input and blocks the current task until a character is @@ -24,8 +67,8 @@ pub mod stdin { /// # Note /// /// This function is not yet implemented. - pub async fn read_char() -> char { - todo!() + pub async fn async_keystroke() -> KeyStroke { + get_keystroke_async().await } /// Attempt to read a character from standard input without blocking the current task. @@ -35,7 +78,7 @@ pub mod stdin { /// # Note /// /// This function is not yet implemented. - pub fn try_read_char() -> Option { - todo!() + pub fn keystroke() -> Option { + get_keystroke_optional() } } diff --git a/libk/src/util/mod.rs b/libk/src/util/mod.rs new file mode 100644 index 0000000..327cf1b --- /dev/null +++ b/libk/src/util/mod.rs @@ -0,0 +1 @@ +pub mod shell; diff --git a/libk/src/util/shell.rs b/libk/src/util/shell.rs index e69de29..fceb8ee 100644 --- a/libk/src/util/shell.rs +++ b/libk/src/util/shell.rs @@ -0,0 +1,40 @@ +use x86_64::registers::rflags::read; + +use crate::{drivers::io::ascii::clear_screen, prelude::stdin::read_line, print, println}; + +static FETCH: &str = " + $$$$$$$$\\ $$\\ + $$ _____| $$ | + $$ | $$$$$$\\ $$\\ $$\\ $$$$$$$\\ $$$$$$$ | $$$$$$\\ $$\\ $$\\ + $$$$$\\ $$ __$$\\ $$ | $$ |$$ __$$\\ $$ __$$ |$$ __$$\\ $$ | $$ | + $$ __|$$ / $$ |$$ | $$ |$$ | $$ |$$ / $$ |$$ | \\__|$$ | $$ | + $$ | $$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ | $$ | + $$ | \\$$$$$$ |\\$$$$$$ |$$ | $$ |\\$$$$$$$ |$$ | \\$$$$$$$ | + \\__| \\______/ \\______/ \\__| \\__| \\_______|\\__| \\____$$ | + $$$$$$\\ $$$$$$\\ $$\\ $$\\ $$\\ $$\\ $$ | + $$ __$$\\ $$ __$$\\ $$ | $$ |$$$$ | \\$$$$$$ | + $$ / $$ |$$ / \\__| $$ | $$ |\\_$$ | \\______/ + $$ | $$ |\\$$$$$$\\ \\$$\\ $$ | $$ | + $$ | $$ | \\____$$\\ \\$$\\$$ / $$ | + $$ | $$ |$$\\ $$ | \\$$$ / $$ | + $$$$$$ |\\$$$$$$ | \\$ / $$$$$$\\ + \\______/ \\______/ \\_/ \\______| +"; + +pub async fn shell() { + println!("{}", FETCH); + + loop { + print!(" Shell> "); + let line = read_line().await; + match line.as_str() { + "fetch" => { + println!("{}", FETCH); + } + "clear" => clear_screen(), + _ => { + println!("Unknown command: {}", line); + } + } + } +}