226 lines
6.4 KiB
Rust
226 lines
6.4 KiB
Rust
pub mod color;
|
|
pub mod cursor;
|
|
|
|
pub use self::color::{Color, ColorCode};
|
|
use self::cursor::CURSOR;
|
|
|
|
use console;
|
|
|
|
pub static mut VGA: Writer = self::Writer::new();
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
#[repr(C)]
|
|
struct ScreenChar {
|
|
ascii_character: u8,
|
|
color_code: ColorCode,
|
|
}
|
|
|
|
macro_rules! print {
|
|
($($arg:tt)*) => ({
|
|
$crate::vga::print(format_args!($($arg)*));
|
|
});
|
|
}
|
|
|
|
macro_rules! println {
|
|
($fmt:expr) => (print!(concat!($fmt, "\n")));
|
|
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
|
|
}
|
|
|
|
macro_rules! flush {
|
|
() => (unsafe { $crate::vga::VGA.flush() });
|
|
}
|
|
|
|
macro_rules! set_color {
|
|
() => (unsafe { $crate::vga::VGA.color_code =
|
|
$crate::vga::ColorCode::new($crate::vga::Color::White, $crate::vga::Color::Black)} );
|
|
($fg:ident) => (unsafe { $crate::vga::VGA.color_code =
|
|
$crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::Black)} );
|
|
($fg:ident, $bg:ident) => (unsafe { $crate::vga::VGA.color_code =
|
|
$crate::vga::ColorCode::new($crate::vga::Color::$fg, $crate::vga::Color::$bg)} );
|
|
}
|
|
|
|
pub fn print(args: fmt::Arguments) {
|
|
use core::fmt::Write;
|
|
unsafe {
|
|
self::VGA.write_fmt(args).unwrap();
|
|
}
|
|
}
|
|
|
|
extern crate core;
|
|
|
|
const BUFFER_ROWS: usize = 25;
|
|
const BUFFER_COLS: usize = 80 * 2;
|
|
|
|
pub struct Writer {
|
|
pub buffer_pos: usize,
|
|
pub color_code: ColorCode,
|
|
buffer: [u8; BUFFER_ROWS * BUFFER_COLS],
|
|
command: [u8; 10],
|
|
command_len: usize,
|
|
}
|
|
|
|
impl Writer {
|
|
pub const fn new() -> Writer {
|
|
Writer {
|
|
buffer_pos: 0,
|
|
color_code: ColorCode::new(Color::White, Color::Black),
|
|
buffer: [0; BUFFER_ROWS * BUFFER_COLS],
|
|
command: [b'\0'; 10],
|
|
command_len: 0,
|
|
}
|
|
}
|
|
|
|
pub fn prompt(&mut self) {
|
|
set_color!(Blue);
|
|
self.write_str("> ");
|
|
set_color!();
|
|
flush!();
|
|
}
|
|
|
|
pub fn backspace(&mut self) {
|
|
if self.command_len > 0 {
|
|
self.command_len -= 1;
|
|
self.erase_byte();
|
|
}
|
|
}
|
|
|
|
pub fn get_command(&self) -> Result<&str, &'static str> {
|
|
match core::str::from_utf8(&self.command) {
|
|
Ok(y) => Ok(&y[..self.command_len]),
|
|
Err(_) => Err("Command is not utf8 char"),
|
|
}
|
|
}
|
|
|
|
pub fn keypress(&mut self, ascii: u8) {
|
|
match ascii {
|
|
b'\n' if self.command_len == 0 => {
|
|
self.write_byte(b'\n');
|
|
self.prompt();
|
|
}
|
|
b'\n' => {
|
|
self.write_byte(b'\n');
|
|
if let Err(msg) = console::exec(&self) {
|
|
set_color!(Red, Black);
|
|
println!("Something wrong: {}", msg);
|
|
set_color!();
|
|
}
|
|
self.command_len = 0;
|
|
self.prompt();
|
|
}
|
|
_ if self.command_len >= 10 => (),
|
|
byte if self.command_len == 0 && byte == b' ' => (),
|
|
byte => {
|
|
if self.command_len >= 10 {
|
|
return;
|
|
};
|
|
self.command[self.command_len] = byte;
|
|
self.write_byte(byte);
|
|
self.command_len += 1;
|
|
}
|
|
}
|
|
self.flush();
|
|
}
|
|
|
|
pub fn erase_byte(&mut self) {
|
|
self.buffer_pos -= 2;
|
|
let i = self.buffer_pos;
|
|
self.buffer[i] = b' ';
|
|
self.buffer[i + 1] = 0;
|
|
self.flush();
|
|
// flush!();
|
|
}
|
|
|
|
pub fn write_byte(&mut self, byte: u8) {
|
|
let i = self.buffer_pos;
|
|
|
|
match byte {
|
|
b'\n' => {
|
|
let current_line = self.buffer_pos / (BUFFER_COLS);
|
|
self.buffer_pos = (current_line + 1) * BUFFER_COLS;
|
|
}
|
|
byte => {
|
|
self.buffer[i] = byte;
|
|
self.buffer[i + 1] = self.color_code.0;
|
|
self.buffer_pos += 2;
|
|
}
|
|
}
|
|
|
|
if self.buffer_pos >= self.buffer.len() {
|
|
self.scroll();
|
|
}
|
|
}
|
|
|
|
fn write_str(&mut self, s: &str) {
|
|
for byte in s.bytes() {
|
|
self.write_byte(byte)
|
|
}
|
|
}
|
|
|
|
fn flush_cursor(&self) {
|
|
unsafe {
|
|
CURSOR.flush(self.buffer_pos / 2);
|
|
}
|
|
}
|
|
|
|
pub fn flush(&mut self) {
|
|
let slice = unsafe { core::slice::from_raw_parts_mut(0xb8000 as *mut u8, 4000) };
|
|
slice.as_mut().clone_from_slice(&self.buffer);
|
|
self.flush_cursor();
|
|
}
|
|
|
|
fn scroll(&mut self) {
|
|
for row in 1..BUFFER_ROWS {
|
|
for col in 0..BUFFER_COLS {
|
|
let prev_position = ((row - 1) * BUFFER_COLS) + col;
|
|
let current_position = (row * BUFFER_COLS) + col;
|
|
self.buffer[prev_position] = self.buffer[current_position];
|
|
}
|
|
}
|
|
|
|
for col in (0..BUFFER_COLS / 2).map(|x| x * 2) {
|
|
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col)] = b' ';
|
|
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col + 1)] =
|
|
ColorCode::new(Color::White, Color::Black).0;
|
|
}
|
|
|
|
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
|
|
}
|
|
}
|
|
|
|
// trait needed by formatting macros
|
|
use core::fmt;
|
|
impl fmt::Write for Writer {
|
|
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
|
|
for byte in s.bytes() {
|
|
self.write_byte(byte)
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn init() {
|
|
set_color!(Yellow, Red);
|
|
print!(
|
|
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
|
format_args!("{: ^80}", r#" ,--, "#),
|
|
format_args!("{: ^80}", r#" ,--.'| ,----, "#),
|
|
format_args!("{: ^80}", r#" ,--, | : .' .' \ "#),
|
|
format_args!("{: ^80}", r#",---.'| : ' ,----,' | "#),
|
|
format_args!("{: ^80}", r#"; : | | ; | : . ; "#),
|
|
format_args!("{: ^80}", r#"| | : _' | ; |.' / "#),
|
|
format_args!("{: ^80}", r#": : |.' | `----'/ ; "#),
|
|
format_args!("{: ^80}", r#"| ' ' ; : / ; / "#),
|
|
format_args!("{: ^80}", r#"\ \ .'. | ; / /-, "#),
|
|
format_args!("{: ^80}", r#" `---`: | ' / / /.`| "#),
|
|
format_args!("{: ^80}", r#" ' ; |./__; : "#),
|
|
format_args!("{: ^80}", r#" | : ;| : .' "#),
|
|
format_args!("{: ^80}", r#" ' ,/ ; | .' "#),
|
|
format_args!("{: ^80}", r#" '--' `---' "#)
|
|
);
|
|
unsafe {
|
|
VGA.prompt();
|
|
}
|
|
unsafe {
|
|
VGA.flush();
|
|
}
|
|
}
|