mirror of https://github.com/vinc/moros.git
Improve console (#74)
* Move keyboard key decoding to keyboard interrupt handler * Read keys from serial * Disable cursor in shell for serial * Trim cpu brand string * Use array for writer position * Add Serial struct * Add console::clear_row() * Update autocomplete commands * Parse ANSI color code * Add colors to banner * Remove newline before diskless mode * Use lighter colors in banner * Fix ansi color code parsing * Use ansi colors in logger * Rewrite colors command * Add color to halt command * Rewrite help command * Use yellow color for titles * User kernel::console::color() in shell * Update screenshot * Fix execute state in vte parser * Fix typo * Add colors to serial logger * Fix banner colors * Add some randomnly darker colors to banner * Autocomplete devices path * Create /ini/version.txt during install
This commit is contained in:
parent
5118a3db2c
commit
5828c7f4d3
|
@ -1,5 +1,11 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
|
@ -178,6 +184,7 @@ dependencies = [
|
|||
"spin",
|
||||
"uart_16550",
|
||||
"volatile",
|
||||
"vte",
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
|
@ -211,6 +218,24 @@ dependencies = [
|
|||
"cpuio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "8.1.0"
|
||||
|
@ -312,12 +337,45 @@ dependencies = [
|
|||
"x86_64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
|
||||
|
||||
[[package]]
|
||||
name = "volatile"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96cc8a191608603611e78c6ec11dafef37e3cca0775aeef1931824753e81711d"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"utf8parse",
|
||||
"vte_generate_state_changes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte_generate_state_changes"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x86_64"
|
||||
version = "0.11.1"
|
||||
|
|
|
@ -33,3 +33,4 @@ spin = "0.5.2"
|
|||
uart_16550 = "0.2.7"
|
||||
volatile = "0.2.6"
|
||||
x86_64 = "0.11.1"
|
||||
vte = "0.8.0"
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
(o o)
|
||||
+-------------------ooO--(_)--Ooo------------------+
|
||||
| |
|
||||
| .100 110. .1100. 111110. .1001. .01000. |
|
||||
| 00'1001`11 .11 01. 00 `00 .10 00. 10' 11 |
|
||||
| 01 00 10 10 00 001101' 01 00 `100. |
|
||||
| 10 01 10 01 11 01`00 01 11 `100. |
|
||||
| 00 01 01 `00 11' 10 `11. `00 11' 01 00 |
|
||||
| 11 10 10 `1001' 00 01 `0110' `01101' |
|
||||
| .[92m1[0m[36m0[0m[96m0[0m [92m1[0m[32m1[0m[36m0[0m. .[92m1[0m[32m1[0m[96m0[0m[96m0[0m. [92m1[0m[32m1[0m[92m1[0m[92m1[0m[32m1[0m[36m0[0m. .[32m1[0m[96m0[0m[36m0[0m[32m1[0m. .[36m0[0m[92m1[0m[36m0[0m[96m0[0m[96m0[0m. |
|
||||
| [96m0[0m[36m0[0m'[32m1[0m[96m0[0m[36m0[0m[92m1[0m`[32m1[0m[92m1[0m .[32m1[0m[92m1[0m [96m0[0m[92m1[0m. [36m0[0m[36m0[0m `[96m0[0m[36m0[0m .[32m1[0m[36m0[0m [36m0[0m[96m0[0m. [92m1[0m[96m0[0m' [32m1[0m[32m1[0m |
|
||||
| [36m0[0m[92m1[0m [96m0[0m[36m0[0m [32m1[0m[36m0[0m [32m1[0m[96m0[0m [96m0[0m[36m0[0m [36m0[0m[96m0[0m[92m1[0m[32m1[0m[96m0[0m[32m1[0m' [36m0[0m[32m1[0m [96m0[0m[36m0[0m `[92m1[0m[96m0[0m[36m0[0m. |
|
||||
| [32m1[0m[36m0[0m [36m0[0m[92m1[0m [92m1[0m[96m0[0m [96m0[0m[92m1[0m [92m1[0m[32m1[0m [36m0[0m[92m1[0m`[96m0[0m[36m0[0m [96m0[0m[32m1[0m [92m1[0m[32m1[0m `[32m1[0m[96m0[0m[96m0[0m. |
|
||||
| [36m0[0m[36m0[0m [96m0[0m[92m1[0m [36m0[0m[32m1[0m `[36m0[0m[96m0[0m [92m1[0m[32m1[0m' [92m1[0m[36m0[0m `[32m1[0m[32m1[0m. `[36m0[0m[96m0[0m [92m1[0m[32m1[0m' [36m0[0m[32m1[0m [36m0[0m[96m0[0m |
|
||||
| [92m1[0m[92m1[0m [92m1[0m[36m0[0m [32m1[0m[96m0[0m `[92m1[0m[36m0[0m[96m0[0m[32m1[0m' [36m0[0m[36m0[0m [36m0[0m[92m1[0m `[96m0[0m[32m1[0m[32m1[0m[96m0[0m' `[96m0[0m[92m1[0m[92m1[0m[36m0[0m[32m1[0m' |
|
||||
| |
|
||||
| MOROS: Obscure Rust Operating System |
|
||||
| [92mMOROS[0m: [92mO[96mbscure [92mR[96must [92mO[96mperating [92mS[96mystem[0m |
|
||||
| |
|
||||
| (v0.3.1) |
|
||||
| (v{x.x.x}) |
|
||||
| |
|
||||
+--------------------------------------------------+
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
MOROS v{x.x.x}
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -1,16 +1,58 @@
|
|||
use crate::{print, kernel};
|
||||
use alloc::string::String;
|
||||
use lazy_static::lazy_static;
|
||||
use pc_keyboard::{KeyCode, DecodedKey};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
pub fn color(name: &str) -> &str {
|
||||
match name {
|
||||
"Black" => "\x1b[30m",
|
||||
"Red" => "\x1b[31m",
|
||||
"Green" => "\x1b[32m",
|
||||
"Brown" => "\x1b[33m",
|
||||
"Blue" => "\x1b[34m",
|
||||
"Magenta" => "\x1b[35m",
|
||||
"Cyan" => "\x1b[36m",
|
||||
"LightGray" => "\x1b[37m",
|
||||
"DarkGray" => "\x1b[90m",
|
||||
"LightRed" => "\x1b[91m",
|
||||
"LightGreen" => "\x1b[92m",
|
||||
"Yellow" => "\x1b[93m",
|
||||
"LightBlue" => "\x1b[94m",
|
||||
"Pink" => "\x1b[95m",
|
||||
"LightCyan" => "\x1b[96m",
|
||||
"White" => "\x1b[97m",
|
||||
"Reset" => "\x1b[0m",
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STDIN: Mutex<String> = Mutex::new(String::new());
|
||||
pub static ref ECHO: Mutex<bool> = Mutex::new(true);
|
||||
pub static ref RAW: Mutex<bool> = Mutex::new(false);
|
||||
}
|
||||
|
||||
#[cfg(feature="vga")]
|
||||
pub fn has_cursor() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(feature="serial")]
|
||||
pub fn has_cursor() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(feature="vga")]
|
||||
pub fn clear_row() {
|
||||
kernel::vga::clear_row();
|
||||
}
|
||||
|
||||
#[cfg(feature="serial")]
|
||||
pub fn clear_row() {
|
||||
print!("\x1b[2K\r");
|
||||
}
|
||||
|
||||
#[cfg(feature="vga")]
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
|
@ -32,10 +74,9 @@ macro_rules! print {
|
|||
macro_rules! log {
|
||||
($($arg:tt)*) => ({
|
||||
let uptime = $crate::kernel::clock::uptime();
|
||||
let (fg, bg) = $crate::kernel::vga::color();
|
||||
$crate::kernel::vga::set_color($crate::kernel::vga::Color::Green, bg);
|
||||
$crate::kernel::vga::print_fmt(format_args!("[{:.6}] ", uptime));
|
||||
$crate::kernel::vga::set_color(fg, bg);
|
||||
let csi_color = $crate::kernel::console::color("LightGreen");
|
||||
let csi_reset = $crate::kernel::console::color("Reset");
|
||||
$crate::kernel::vga::print_fmt(format_args!("{}[{:.6}]{} ", csi_color, uptime, csi_reset));
|
||||
$crate::kernel::vga::print_fmt(format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
@ -45,7 +86,9 @@ macro_rules! log {
|
|||
macro_rules! log {
|
||||
($($arg:tt)*) => ({
|
||||
let uptime = $crate::kernel::clock::uptime();
|
||||
$crate::kernel::serial::print_fmt(format_args!("[{:.6}] ", uptime));
|
||||
let csi_color = $crate::kernel::console::color("LightGreen");
|
||||
let csi_reset = $crate::kernel::console::color("Reset");
|
||||
$crate::kernel::serial::print_fmt(format_args!("{}[{:.6}]{} ", csi_color, uptime, csi_reset));
|
||||
$crate::kernel::serial::print_fmt(format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
@ -78,18 +121,10 @@ pub fn is_raw_enabled() -> bool {
|
|||
*RAW.lock()
|
||||
}
|
||||
|
||||
pub fn key_handle(key: DecodedKey) {
|
||||
let c = match key {
|
||||
DecodedKey::Unicode(c) => c,
|
||||
DecodedKey::RawKey(KeyCode::ArrowLeft) => '←', // U+2190
|
||||
DecodedKey::RawKey(KeyCode::ArrowUp) => '↑', // U+2191
|
||||
DecodedKey::RawKey(KeyCode::ArrowRight) => '→', // U+2192
|
||||
DecodedKey::RawKey(KeyCode::ArrowDown) => '↓', // U+2193
|
||||
DecodedKey::RawKey(_) => '\0'
|
||||
};
|
||||
pub fn key_handle(key: char) {
|
||||
let mut stdin = STDIN.lock();
|
||||
|
||||
if c == '\x08' && !is_raw_enabled() {
|
||||
if key == '\x08' && !is_raw_enabled() {
|
||||
// Avoid printing more backspaces than chars inserted into STDIN.
|
||||
// Also, the VGA driver support only ASCII so unicode chars will
|
||||
// be displayed with one square for each codepoint.
|
||||
|
@ -104,9 +139,9 @@ pub fn key_handle(key: DecodedKey) {
|
|||
} else {
|
||||
// TODO: Replace non-ascii chars by ascii square symbol to keep length
|
||||
// at 1 instead of being variable?
|
||||
stdin.push(c);
|
||||
stdin.push(key);
|
||||
if is_echo_enabled() {
|
||||
print!("{}", c);
|
||||
print!("{}", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn init() {
|
|||
|
||||
if let Some(extended_function_info) = cpuid.get_extended_function_info() {
|
||||
if let Some(processor_brand_string) = extended_function_info.processor_brand_string() {
|
||||
log!("CPU {}\n", processor_brand_string);
|
||||
log!("CPU {}\n", processor_brand_string.trim());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::kernel;
|
||||
use lazy_static::lazy_static;
|
||||
use pc_keyboard::{Keyboard, ScancodeSet1, HandleControl, layouts};
|
||||
use pc_keyboard::{Keyboard, ScancodeSet1, HandleControl, layouts, KeyCode, DecodedKey};
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
|
@ -84,7 +84,15 @@ fn interrupt_handler() {
|
|||
let scancode = read_scancode();
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
kernel::console::key_handle(key);
|
||||
let c = match key {
|
||||
DecodedKey::Unicode(c) => c,
|
||||
DecodedKey::RawKey(KeyCode::ArrowLeft) => '←', // U+2190
|
||||
DecodedKey::RawKey(KeyCode::ArrowUp) => '↑', // U+2191
|
||||
DecodedKey::RawKey(KeyCode::ArrowRight) => '→', // U+2192
|
||||
DecodedKey::RawKey(KeyCode::ArrowDown) => '↓', // U+2193
|
||||
DecodedKey::RawKey(_) => '\0'
|
||||
};
|
||||
kernel::console::key_handle(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,58 @@
|
|||
use crate::kernel;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use uart_16550::SerialPort;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SERIAL1: Mutex<SerialPort> = {
|
||||
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
|
||||
serial_port.init();
|
||||
Mutex::new(serial_port)
|
||||
};
|
||||
pub static ref SERIAL: Mutex<Serial> = Mutex::new(Serial::new(0x3F8));
|
||||
}
|
||||
|
||||
pub struct Serial {
|
||||
pub port: SerialPort
|
||||
}
|
||||
|
||||
impl Serial {
|
||||
fn new(addr: u16) -> Self {
|
||||
let mut port = unsafe { SerialPort::new(addr) };
|
||||
port.init();
|
||||
Self { port }
|
||||
}
|
||||
|
||||
fn write_string(&mut self, s: &str) {
|
||||
for byte in s.bytes() {
|
||||
self.write_byte(byte)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_byte(&mut self, byte: u8) {
|
||||
self.port.send(byte);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Serial {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write_string(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn print_fmt(args: ::core::fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
SERIAL1.lock().write_fmt(args).expect("Could not print to serial");
|
||||
pub fn print_fmt(args: fmt::Arguments) {
|
||||
SERIAL.lock().write_fmt(args).expect("Could not print to serial");
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
kernel::idt::set_irq_handler(4, interrupt_handler);
|
||||
}
|
||||
|
||||
fn interrupt_handler() {
|
||||
let b = SERIAL.lock().port.receive();
|
||||
let c = match b as char {
|
||||
'\r' => '\n',
|
||||
'\x7F' => '\x08', // Delete => Backspace
|
||||
c => c,
|
||||
};
|
||||
kernel::console::key_handle(c);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
use crate::kernel;
|
||||
use bit_field::BitField;
|
||||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use volatile::Volatile;
|
||||
use x86_64::instructions::port::Port;
|
||||
use vte;
|
||||
use x86_64::instructions::interrupts;
|
||||
use x86_64::instructions::port::Port;
|
||||
|
||||
const FG: Color = Color::LightGray;
|
||||
const BG: Color = Color::Black;
|
||||
const UNPRINTABLE: u8 = 0xFE; // Unprintable characters will be replaced by a square
|
||||
|
||||
lazy_static! {
|
||||
/// A global `Writer` instance that can be used for printing to the VGA text buffer.
|
||||
///
|
||||
/// Used by the `print!` and `println!` macros.
|
||||
pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
|
||||
cursor: [0; 2],
|
||||
col_pos: 0,
|
||||
row_pos: 0,
|
||||
color_code: ColorCode::new(Color::LightGray, Color::Black),
|
||||
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
|
||||
writer: [0; 2],
|
||||
color_code: ColorCode::new(FG, BG),
|
||||
buffer: unsafe { &mut *(0xB8000 as *mut Buffer) },
|
||||
});
|
||||
}
|
||||
|
||||
/// The standard color palette in VGA text mode.
|
||||
/// The standard color palette in VGA text mode
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
|
@ -62,57 +64,67 @@ const COLORS: [Color; 16] = [
|
|||
Color::White,
|
||||
];
|
||||
|
||||
/// A combination of a foreground and a background color.
|
||||
fn color_from_ansi(code: u8) -> Color {
|
||||
match code {
|
||||
30 => Color::Black,
|
||||
31 => Color::Red,
|
||||
32 => Color::Green,
|
||||
33 => Color::Brown,
|
||||
34 => Color::Blue,
|
||||
35 => Color::Magenta,
|
||||
36 => Color::Cyan,
|
||||
37 => Color::LightGray,
|
||||
90 => Color::DarkGray,
|
||||
91 => Color::LightRed,
|
||||
92 => Color::LightGreen,
|
||||
93 => Color::Yellow,
|
||||
94 => Color::LightBlue,
|
||||
95 => Color::Pink,
|
||||
96 => Color::LightCyan,
|
||||
97 => Color::White,
|
||||
_ => FG, // Error
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(transparent)]
|
||||
struct ColorCode(u8);
|
||||
|
||||
impl ColorCode {
|
||||
/// Create a new `ColorCode` with the given foreground and background colors.
|
||||
fn new(foreground: Color, background: Color) -> ColorCode {
|
||||
ColorCode((background as u8) << 4 | (foreground as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// A screen character in the VGA text buffer, consisting of an ASCII character and a `ColorCode`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
struct ScreenChar {
|
||||
ascii_character: u8,
|
||||
ascii_code: u8,
|
||||
color_code: ColorCode,
|
||||
}
|
||||
|
||||
/// The height of the text buffer (normally 25 lines).
|
||||
const BUFFER_HEIGHT: usize = 25;
|
||||
/// The width of the text buffer (normally 80 columns).
|
||||
const BUFFER_WIDTH: usize = 80;
|
||||
|
||||
/// A structure representing the VGA text buffer.
|
||||
#[repr(transparent)]
|
||||
struct Buffer {
|
||||
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
|
||||
}
|
||||
|
||||
/// A writer type that allows writing ASCII bytes and strings to an underlying `Buffer`.
|
||||
///
|
||||
/// Wraps lines at `BUFFER_WIDTH`. Supports newline characters and implements the
|
||||
/// `core::fmt::Write` trait.
|
||||
pub struct Writer {
|
||||
cursor: [usize; 2],
|
||||
col_pos: usize,
|
||||
row_pos: usize,
|
||||
cursor: [usize; 2], // x, y
|
||||
writer: [usize; 2], // x, y
|
||||
color_code: ColorCode,
|
||||
buffer: &'static mut Buffer,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn writer_position(&self) -> (usize, usize) {
|
||||
(self.col_pos, self.row_pos)
|
||||
(self.writer[0], self.writer[1])
|
||||
}
|
||||
|
||||
pub fn set_writer_position(&mut self, x: usize, y: usize) {
|
||||
self.col_pos = x;
|
||||
self.row_pos = y;
|
||||
self.writer = [x, y];
|
||||
}
|
||||
|
||||
pub fn cursor_position(&self) -> (usize, usize) {
|
||||
|
@ -151,7 +163,7 @@ impl Writer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Writes an ASCII byte to the buffer.
|
||||
/// Writes an ASCII byte to the screen buffer
|
||||
pub fn write_byte(&mut self, byte: u8) {
|
||||
match byte {
|
||||
0x0A => { // Newline
|
||||
|
@ -160,63 +172,59 @@ impl Writer {
|
|||
0x0D => { // Carriage Return
|
||||
},
|
||||
0x08 => { // Backspace
|
||||
if self.col_pos > 0 {
|
||||
self.col_pos -= 1;
|
||||
if self.writer[0] > 0 {
|
||||
self.writer[0] -= 1;
|
||||
let blank = ScreenChar {
|
||||
ascii_character: b' ',
|
||||
ascii_code: b' ',
|
||||
color_code: self.color_code,
|
||||
};
|
||||
let x = self.col_pos;
|
||||
let y = self.row_pos;
|
||||
let x = self.writer[0];
|
||||
let y = self.writer[1];
|
||||
self.buffer.chars[y][x].write(blank);
|
||||
}
|
||||
},
|
||||
byte => {
|
||||
if self.col_pos >= BUFFER_WIDTH {
|
||||
if self.writer[0] >= BUFFER_WIDTH {
|
||||
self.new_line();
|
||||
}
|
||||
|
||||
let col = self.col_pos;
|
||||
let row = self.row_pos;
|
||||
let x = self.writer[0];
|
||||
let y = self.writer[1];
|
||||
let ascii_code = if is_printable(byte) { byte } else { UNPRINTABLE };
|
||||
let color_code = self.color_code;
|
||||
self.buffer.chars[row][col].write(ScreenChar {
|
||||
ascii_character: byte,
|
||||
color_code,
|
||||
});
|
||||
self.col_pos += 1;
|
||||
self.buffer.chars[y][x].write(ScreenChar { ascii_code, color_code });
|
||||
self.writer[0] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_string(&mut self, s: &str) {
|
||||
let mut state_machine = vte::Parser::new();
|
||||
for byte in s.bytes() {
|
||||
if is_printable(byte) {
|
||||
self.write_byte(byte) // Printable chars, backspace, newline
|
||||
} else {
|
||||
self.write_byte(0xFE) // Square
|
||||
}
|
||||
state_machine.advance(self, byte);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_line(&mut self) {
|
||||
if self.row_pos < BUFFER_HEIGHT - 1 {
|
||||
self.row_pos += 1;
|
||||
if self.writer[1] < BUFFER_HEIGHT - 1 {
|
||||
self.writer[1] += 1;
|
||||
} else {
|
||||
for row in 1..BUFFER_HEIGHT {
|
||||
for col in 0..BUFFER_WIDTH {
|
||||
let character = self.buffer.chars[row][col].read();
|
||||
self.buffer.chars[row - 1][col].write(character);
|
||||
for y in 1..BUFFER_HEIGHT {
|
||||
for x in 0..BUFFER_WIDTH {
|
||||
let character = self.buffer.chars[y][x].read();
|
||||
self.buffer.chars[y - 1][x].write(character);
|
||||
}
|
||||
}
|
||||
self.clear_row(BUFFER_HEIGHT - 1);
|
||||
}
|
||||
self.col_pos = 0;
|
||||
self.writer[0] = 0;
|
||||
|
||||
}
|
||||
|
||||
/// Clears a row by overwriting it with blank characters.
|
||||
/// Clears a row by overwriting it with blank characters
|
||||
fn clear_row(&mut self, y: usize) {
|
||||
let blank = ScreenChar {
|
||||
ascii_character: b' ',
|
||||
ascii_code: b' ',
|
||||
color_code: self.color_code,
|
||||
};
|
||||
for x in 0..BUFFER_WIDTH {
|
||||
|
@ -228,9 +236,8 @@ impl Writer {
|
|||
for y in 0..BUFFER_HEIGHT {
|
||||
self.clear_row(y);
|
||||
}
|
||||
self.row_pos = 0;
|
||||
self.col_pos = 0;
|
||||
self.set_cursor_position(self.col_pos, self.row_pos);
|
||||
self.set_writer_position(0, 0);
|
||||
self.set_cursor_position(0, 0);
|
||||
}
|
||||
|
||||
pub fn set_color(&mut self, foreground: Color, background: Color) {
|
||||
|
@ -245,16 +252,72 @@ impl Writer {
|
|||
}
|
||||
}
|
||||
|
||||
/// See https://vt100.net/emu/dec_ansi_parser
|
||||
impl vte::Perform for Writer {
|
||||
fn print(&mut self, c: char) {
|
||||
self.write_byte(c as u8);
|
||||
}
|
||||
|
||||
fn execute(&mut self, byte: u8) {
|
||||
self.write_byte(byte);
|
||||
kernel::serial::print_fmt(format_args!("[execute] {:02x}\n", byte));
|
||||
}
|
||||
|
||||
fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) {
|
||||
kernel::serial::print_fmt(format_args!("[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}\n", params, intermediates, ignore, c));
|
||||
}
|
||||
|
||||
fn put(&mut self, byte: u8) {
|
||||
kernel::serial::print_fmt(format_args!("[put] {:02x}\n", byte));
|
||||
}
|
||||
|
||||
fn unhook(&mut self) {
|
||||
kernel::serial::print_fmt(format_args!("[unhook]\n"));
|
||||
}
|
||||
|
||||
fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
|
||||
kernel::serial::print_fmt(format_args!("[osc_dispatch] params={:?} bell_terminated={}\n", params, bell_terminated));
|
||||
}
|
||||
|
||||
fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) {
|
||||
if c == 'm' {
|
||||
let mut fg = FG;
|
||||
let mut bg = BG;
|
||||
for ¶m in params {
|
||||
match param {
|
||||
0 => {
|
||||
fg = FG;
|
||||
bg = BG;
|
||||
},
|
||||
30..=37 | 90..=97 => {
|
||||
fg = color_from_ansi(param as u8);
|
||||
},
|
||||
40..=47 | 100..=107 => {
|
||||
bg = color_from_ansi((param as u8) - 10);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.set_color(fg, bg);
|
||||
}
|
||||
|
||||
kernel::serial::print_fmt(format_args!("[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}\n", params, intermediates, ignore, c));
|
||||
}
|
||||
|
||||
fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
|
||||
kernel::serial::print_fmt(format_args!("[esc_dispatch] intermediates={:?}, ignore={:?}, byte={:02x}\n", intermediates, ignore, byte));
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Writer {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write_string(s);
|
||||
self.set_cursor_position(self.col_pos, self.row_pos);
|
||||
let (x, y) = self.writer_position();
|
||||
self.set_cursor_position(x, y);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the given formatted string to the VGA text buffer
|
||||
/// through the global `WRITER` instance.
|
||||
#[doc(hidden)]
|
||||
pub fn print_fmt(args: fmt::Arguments) {
|
||||
interrupts::without_interrupts(|| {
|
||||
|
|
|
@ -20,6 +20,7 @@ pub fn init(boot_info: &'static BootInfo) {
|
|||
|
||||
kernel::time::init();
|
||||
kernel::keyboard::init();
|
||||
kernel::serial::init();
|
||||
kernel::mem::init(boot_info);
|
||||
kernel::cpu::init();
|
||||
kernel::pci::init(); // Require MEM
|
||||
|
|
|
@ -22,7 +22,6 @@ fn main(boot_info: &'static BootInfo) -> ! {
|
|||
print!("MFS is not mounted to '/'\n");
|
||||
}
|
||||
print!("Running console in diskless mode\n");
|
||||
print!("\n");
|
||||
|
||||
user::shell::main(&["shell"]);
|
||||
}
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
use crate::{print, kernel, user};
|
||||
use alloc::format;
|
||||
use crate::{print, user};
|
||||
|
||||
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||
let colors = kernel::vga::colors();
|
||||
let (fg, bg) = kernel::vga::color();
|
||||
let csi_reset = "\x1b[0m";
|
||||
|
||||
for i in 0..colors.len() {
|
||||
let c = colors[i];
|
||||
kernel::vga::set_color(c, bg);
|
||||
print!(" {:02} ", i);
|
||||
if i == 7 || i == 15 {
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("\n");
|
||||
}
|
||||
for i in 30..38 {
|
||||
let csi_color = format!("\x1b[{};40m", i);
|
||||
print!(" {}{:3}{}", csi_color, i, csi_reset);
|
||||
}
|
||||
|
||||
for i in 0..colors.len() {
|
||||
let c = colors[i];
|
||||
kernel::vga::set_color(bg, c);
|
||||
print!(" {:02} ", i);
|
||||
if i == 7 || i == 15 {
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("\n");
|
||||
}
|
||||
print!("\n");
|
||||
for i in 90..98 {
|
||||
let csi_color = format!("\x1b[{};40m", i);
|
||||
print!(" {}{:3}{}", csi_color, i, csi_reset);
|
||||
}
|
||||
print!("\n");
|
||||
for i in 40..48 {
|
||||
let csi_color = format!("\x1b[30;{}m", i);
|
||||
print!(" {}{:3}{}", csi_color, i, csi_reset);
|
||||
}
|
||||
print!("\n");
|
||||
for i in 100..108 {
|
||||
let csi_color = format!("\x1b[30;{}m", i);
|
||||
print!(" {}{:3}{}", csi_color, i, csi_reset);
|
||||
}
|
||||
print!("\n");
|
||||
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::{print, kernel, user};
|
||||
|
||||
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||
print!("MOROS has reached its fate, the system is now halted.\n");
|
||||
let csi_color = kernel::console::color("Yellow");
|
||||
let csi_reset = kernel::console::color("Reset");
|
||||
print!("{}MOROS has reached its fate, the system is now halted.{}\n", csi_color, csi_reset);
|
||||
kernel::time::sleep(3.0);
|
||||
kernel::acpi::poweroff();
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
use crate::{print, user, kernel};
|
||||
use crate::kernel::vga::Color;
|
||||
|
||||
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||
let (fg, bg) = kernel::vga::color();
|
||||
let csi_color = kernel::console::color("Yellow");
|
||||
let csi_reset = kernel::console::color("Reset");
|
||||
print!("{}Commands:{}\n", csi_color, csi_reset);
|
||||
print!("\n");
|
||||
|
||||
let cmds = [
|
||||
("c", "opy <file> <file>", "Copy file from source to destination\n"),
|
||||
("d", "elete <file>", "Delete file or empty directory\n"),
|
||||
("e", "dit <file>", "Edit existing or new file\n"),
|
||||
("g", "oto <dir>", "Go to directory\n"),
|
||||
("h", "elp", "Display this text\n"),
|
||||
("l", "ist <dir>", "List entries in directory\n"),
|
||||
("m", "ove <file> <file>", "Move file from source to destination\n"),
|
||||
|
@ -15,11 +19,16 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
("r", "ead <file>", "Read file to screen\n"),
|
||||
("w", "rite <file>", "Write file or directory\n"),
|
||||
];
|
||||
for (cmd, args, usage) in &cmds {
|
||||
kernel::vga::set_color(Color::White, bg);
|
||||
print!("{}", cmd);
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{:20}{}", args, usage);
|
||||
for (alias, command, usage) in &cmds {
|
||||
let csi_col1 = kernel::console::color("LightGreen");
|
||||
let csi_col2 = kernel::console::color("LightCyan");
|
||||
print!(" {}{}{}{:20}{}{}", csi_col1, alias, csi_col2, command, csi_reset, usage);
|
||||
}
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
print!("\n");
|
||||
|
||||
print!("{}Credits:{}\n", csi_color, csi_reset);
|
||||
print!("\n");
|
||||
|
||||
print!("Made with <3 in 2019-2020 by Vincent Ollivier <v@vinc.cc>\n");
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use crate::{print, kernel, user};
|
||||
use crate::kernel::vga::Color;
|
||||
|
||||
pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
||||
let (fg, bg) = kernel::vga::color();
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Welcome to MOROS v{} installation program!\n", env!("CARGO_PKG_VERSION"));
|
||||
kernel::vga::set_color(fg, bg);
|
||||
let csi_color = kernel::console::color("Yellow");
|
||||
let csi_reset = kernel::console::color("Reset");
|
||||
print!("{}Welcome to MOROS v{} installation program!{}\n", csi_color, env!("CARGO_PKG_VERSION"), csi_reset);
|
||||
print!("\n");
|
||||
|
||||
print!("Proceed? [y/N] ");
|
||||
|
@ -13,15 +11,11 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
print!("\n");
|
||||
|
||||
if !kernel::fs::is_mounted() {
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Listing disks ...\n");
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{}Listing disks ...{}\n", csi_color, csi_reset);
|
||||
user::disk::main(&["disk", "list"]);
|
||||
print!("\n");
|
||||
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Formatting disk ...\n");
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{}Formatting disk ...{}\n", csi_color, csi_reset);
|
||||
print!("Enter path of disk to format: ");
|
||||
let pathname = kernel::console::get_line();
|
||||
let res = user::disk::main(&["disk", "format", pathname.trim_end()]);
|
||||
|
@ -31,9 +25,7 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
print!("\n");
|
||||
}
|
||||
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Populating filesystem ...\n");
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{}Populating filesystem...{}\n", csi_color, csi_reset);
|
||||
create_dir("/bin"); // Binaries
|
||||
create_dir("/dev"); // Devices
|
||||
create_dir("/ini"); // Initializers
|
||||
|
@ -46,13 +38,12 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
|
||||
copy_file("/ini/boot.sh", include_str!("../../dsk/ini/boot.sh"));
|
||||
copy_file("/ini/banner.txt", include_str!("../../dsk/ini/banner.txt"));
|
||||
copy_file("/ini/version.txt", include_str!("../../dsk/ini/version.txt"));
|
||||
copy_file("/tmp/alice.txt", include_str!("../../dsk/tmp/alice.txt"));
|
||||
|
||||
if kernel::process::user().is_none() {
|
||||
print!("\n");
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Creating user ...\n");
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{}Creating user...{}\n", csi_color, csi_reset);
|
||||
let res = user::user::main(&["user", "create"]);
|
||||
if res == user::shell::ExitCode::CommandError {
|
||||
return res;
|
||||
|
@ -60,9 +51,7 @@ pub fn main(_args: &[&str]) -> user::shell::ExitCode {
|
|||
}
|
||||
|
||||
print!("\n");
|
||||
kernel::vga::set_color(Color::LightCyan, bg);
|
||||
print!("Installation successful!\n");
|
||||
kernel::vga::set_color(fg, bg);
|
||||
print!("{}Installation successful!{}\n", csi_color, csi_reset);
|
||||
print!("\n");
|
||||
print!("Exit console or reboot to apply changes\n");
|
||||
}
|
||||
|
@ -81,6 +70,7 @@ fn copy_file(pathname: &str, contents: &str) {
|
|||
return;
|
||||
}
|
||||
if let Some(mut file) = kernel::fs::File::create(pathname) {
|
||||
let contents = contents.replace("{x.x.x}", env!("CARGO_PKG_VERSION"));
|
||||
file.write(&contents.as_bytes()).unwrap();
|
||||
print!("Copied '{}'\n", pathname);
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@ pub fn main(args: &[&str]) -> user::shell::ExitCode {
|
|||
"/dev/clk/uptime" => {
|
||||
user::uptime::main(&["uptime", "--raw"])
|
||||
},
|
||||
"/sys/version" => {
|
||||
print!("MOROS v{}\n", env!("CARGO_PKG_VERSION"));
|
||||
user::shell::ExitCode::CommandSuccessful
|
||||
},
|
||||
_ => {
|
||||
if pathname.starts_with("/net/") {
|
||||
// Examples:
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
use crate::{print, user, kernel};
|
||||
use crate::kernel::vga::Color;
|
||||
use alloc::format;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::string::String;
|
||||
|
||||
// TODO: Scan /bin
|
||||
const AUTOCOMPLETE_COMMANDS: [&str; 29] = [
|
||||
"base64", "clear", "colors", "copy", "delete", "dhcp", "disk", "edit",
|
||||
"geotime", "goto", "halt", "help", "hex", "host", "http", "install", "ip",
|
||||
"list", "move", "net", "print", "quit", "read", "route", "shell", "sleep",
|
||||
"tcp", "user", "write",
|
||||
];
|
||||
|
||||
// TODO: Scan /dev
|
||||
const AUTOCOMPLETE_DEVICES: [&str; 5] = [
|
||||
"/dev/ata",
|
||||
"/dev/clk",
|
||||
"/dev/clk/uptime",
|
||||
"/dev/clk/realtime",
|
||||
"/dev/rtc",
|
||||
];
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq)]
|
||||
pub enum ExitCode {
|
||||
|
@ -143,37 +159,49 @@ impl Shell {
|
|||
'\x08' => { // Backspace
|
||||
self.update_history();
|
||||
self.update_autocomplete();
|
||||
let cmd = self.cmd.clone();
|
||||
if cmd.len() > 0 && x > self.prompt.len() {
|
||||
let (before_cursor, mut after_cursor) = cmd.split_at(x - 1 - self.prompt.len());
|
||||
if after_cursor.len() > 0 {
|
||||
after_cursor = &after_cursor[1..];
|
||||
if self.cmd.len() > 0 {
|
||||
if kernel::console::has_cursor() {
|
||||
if x > self.prompt.len() {
|
||||
let cmd = self.cmd.clone();
|
||||
let (before_cursor, mut after_cursor) = cmd.split_at(x - 1 - self.prompt.len());
|
||||
if after_cursor.len() > 0 {
|
||||
after_cursor = &after_cursor[1..];
|
||||
}
|
||||
self.cmd.clear();
|
||||
self.cmd.push_str(before_cursor);
|
||||
self.cmd.push_str(after_cursor);
|
||||
kernel::vga::clear_row();
|
||||
self.print_prompt();
|
||||
print!("{}", self.cmd);
|
||||
kernel::vga::set_cursor_position(x - 1, y);
|
||||
kernel::vga::set_writer_position(x - 1, y);
|
||||
}
|
||||
} else {
|
||||
self.cmd.pop();
|
||||
print!("{}", c);
|
||||
}
|
||||
self.cmd.clear();
|
||||
self.cmd.push_str(before_cursor);
|
||||
self.cmd.push_str(after_cursor);
|
||||
kernel::vga::clear_row();
|
||||
self.print_prompt();
|
||||
print!("{}", self.cmd);
|
||||
kernel::vga::set_cursor_position(x - 1, y);
|
||||
kernel::vga::set_writer_position(x - 1, y);
|
||||
}
|
||||
},
|
||||
c => {
|
||||
self.update_history();
|
||||
self.update_autocomplete();
|
||||
if c.is_ascii() && kernel::vga::is_printable(c as u8) {
|
||||
let cmd = self.cmd.clone();
|
||||
let (before_cursor, after_cursor) = cmd.split_at(x - self.prompt.len());
|
||||
self.cmd.clear();
|
||||
self.cmd.push_str(before_cursor);
|
||||
self.cmd.push(c);
|
||||
self.cmd.push_str(after_cursor);
|
||||
kernel::vga::clear_row();
|
||||
self.print_prompt();
|
||||
print!("{}", self.cmd);
|
||||
kernel::vga::set_cursor_position(x + 1, y);
|
||||
kernel::vga::set_writer_position(x + 1, y);
|
||||
if kernel::console::has_cursor() {
|
||||
let cmd = self.cmd.clone();
|
||||
let (before_cursor, after_cursor) = cmd.split_at(x - self.prompt.len());
|
||||
self.cmd.clear();
|
||||
self.cmd.push_str(before_cursor);
|
||||
self.cmd.push(c);
|
||||
self.cmd.push_str(after_cursor);
|
||||
kernel::vga::clear_row();
|
||||
self.print_prompt();
|
||||
print!("{}", self.cmd);
|
||||
kernel::vga::set_cursor_position(x + 1, y);
|
||||
kernel::vga::set_writer_position(x + 1, y);
|
||||
} else {
|
||||
self.cmd.push(c);
|
||||
print!("{}", c);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -230,25 +258,28 @@ impl Shell {
|
|||
let mut args = self.parse(&self.cmd);
|
||||
let i = args.len() - 1;
|
||||
if self.autocomplete_index == 0 {
|
||||
if args.len() == 1 {
|
||||
// Autocomplete command
|
||||
let autocomplete_commands = vec![ // TODO: scan /bin
|
||||
"copy", "delete", "edit", "help", "move", "print", "quit", "read", "write", "sleep", "clear"
|
||||
];
|
||||
if args.len() == 1 { // Autocomplete cmd
|
||||
self.autocomplete = vec![args[i].into()];
|
||||
for cmd in autocomplete_commands {
|
||||
for &cmd in &AUTOCOMPLETE_COMMANDS {
|
||||
if cmd.starts_with(args[i]) {
|
||||
self.autocomplete.push(cmd.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Autocomplete path
|
||||
} else { // Autocomplete path
|
||||
let pathname = kernel::fs::realpath(args[i]);
|
||||
let dirname = kernel::fs::dirname(&pathname);
|
||||
let filename = kernel::fs::filename(&pathname);
|
||||
self.autocomplete = vec![args[i].into()];
|
||||
if let Some(dir) = kernel::fs::Dir::open(dirname) {
|
||||
let sep = if dirname.ends_with("/") { "" } else { "/" };
|
||||
let sep = if dirname.ends_with("/") { "" } else { "/" };
|
||||
if pathname.starts_with("/dev") {
|
||||
for dev in &AUTOCOMPLETE_DEVICES {
|
||||
let d = kernel::fs::dirname(dev);
|
||||
let f = kernel::fs::filename(dev);
|
||||
if d == dirname && f.starts_with(filename) {
|
||||
self.autocomplete.push(format!("{}{}{}", d, sep, f));
|
||||
}
|
||||
}
|
||||
} else if let Some(dir) = kernel::fs::Dir::open(dirname) {
|
||||
for entry in dir.read() {
|
||||
if entry.name().starts_with(filename) {
|
||||
self.autocomplete.push(format!("{}{}{}", dirname, sep, entry.name()));
|
||||
|
@ -262,7 +293,7 @@ impl Shell {
|
|||
args[i] = &self.autocomplete[self.autocomplete_index];
|
||||
|
||||
let cmd = args.join(" ");
|
||||
kernel::vga::clear_row();
|
||||
kernel::console::clear_row();
|
||||
self.print_prompt();
|
||||
print!("{}", cmd);
|
||||
}
|
||||
|
@ -375,10 +406,10 @@ impl Shell {
|
|||
}
|
||||
|
||||
fn print_prompt(&self) {
|
||||
let (fg, bg) = kernel::vga::color();
|
||||
kernel::vga::set_color(if self.errored { Color::Red } else { Color::Magenta }, bg);
|
||||
print!("{}", self.prompt);
|
||||
kernel::vga::set_color(fg, bg);
|
||||
let color = if self.errored { "Red" } else { "Magenta" };
|
||||
let csi_color = kernel::console::color(color);
|
||||
let csi_reset = kernel::console::color("Reset");
|
||||
print!("{}{}{}", csi_color, self.prompt, csi_reset);
|
||||
}
|
||||
|
||||
fn change_dir(&self, args: &[&str]) -> ExitCode {
|
||||
|
|
Loading…
Reference in New Issue