changed backspace functionality

backspace will now skip to the last real character on a line and skip over null characters
This commit is contained in:
FantasyPvP
2023-10-01 03:18:57 +01:00
parent ded4140f7c
commit f0ee584c87
7 changed files with 502 additions and 475 deletions
+290
View File
@@ -0,0 +1,290 @@
use core::fmt;
use lazy_static::lazy_static;
use spin::Mutex;
use volatile::Volatile;
use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ColorCode(u8);
impl ColorCode {
pub fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 5 | (foreground as u8))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
character: u8,
colour: ColorCode,
}
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct Buffer {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct BufferSwap {
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct CharGrid {
chars: Vec<[ScreenChar; BUFFER_WIDTH]>,
}
pub struct Renderer {
col_pos: usize,
pub col_code: ColorCode,
buffer: &'static mut Buffer,
userspace: BufferSwap,
upwards: CharGrid,
downwards: CharGrid,
pub sandbox: bool,
}
lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0,
col_code: ColorCode::new(Color::White, Color::Black),
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
userspace: BufferSwap {
chars: [[ScreenChar {
character: 178u8,
colour: ColorCode::new(Color::White, Color::Black),
}; BUFFER_WIDTH]; BUFFER_HEIGHT]
},
upwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
downwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
sandbox: false,
});
}
impl Renderer {
pub fn text_mode(&mut self) -> Result<(), ()> {
if !self.sandbox {
return Err(());
};
self.buffer_swap().unwrap();
self.sandbox = false;
Ok(())
}
pub fn sandbox_mode(&mut self) -> Result<(), ()> {
if self.sandbox {
return Err(());
};
self.buffer_swap().unwrap();
self.sandbox = true;
Ok(())
}
fn buffer_swap(&mut self) -> Result<(), ()> {
for (i, _) in self.userspace.chars.clone().iter().enumerate() {
let tmp = self.buffer.chars[i].clone();
for (j, col) in self.userspace.chars[i].clone().iter().enumerate() {
self.buffer.chars[i][j].write(col.to_owned())
}
for (j, _) in tmp.iter().enumerate() {
self.userspace.chars[i][j] = tmp[j].read().to_owned()
}
}
Ok(())
}
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) {
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
if let Some(c) = self.fancy_char(*col) {
self.buffer.chars[i][j].write(ScreenChar {
character: c,
colour: self.col_code,
});
} else {
self.buffer.chars[i][j].write(ScreenChar {
character: *col as u8,
colour: self.col_code,
});
}
}
}
}
pub fn write_string(&mut self, string: &str) {
for ch in string.chars() {
if let Some(x) = self.fancy_char(ch) {
self.write_byte(x)
} else {
match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8),
_ => self.write_byte(0xfe),
}
}
}
}
fn fancy_char(&self, ch: char) -> Option<u8> {
let res: u8 = match ch {
'│' => 179,
'─' => 196,
'┴' => 193,
'┤' => 180,
'═' => 205,
'║' => 186,
'╗' => 187,
'╝' => 188,
'╚' => 200,
'╔' => 201,
'»' => 175,
'┐' => 191,
'└' => 192,
'┘' => 217,
'┌' => 218,
'┼' => 197,
'░' => 176,
'▓' => 178,
'«' => 174,
'»' => 175,
_ => {
return None;
}
};
Some(res)
}
pub fn backspace(&mut self) -> Result<(), ()> {
if self.col_pos == 0 {
self.undonewline();
}
self.col_pos -= 1;
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
self.buffer.chars[row][col].write(blank);
Ok(())
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.newline(),
byte => {
if self.col_pos >= BUFFER_WIDTH {
self.newline();
}
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let col_code = self.col_code;
self.buffer.chars[row][col].write(ScreenChar {
character: byte,
colour: col_code,
});
self.col_pos += 1
}
}
}
fn newline(&mut self) {
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);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.col_pos = 0;
}
pub fn undonewline(&mut self) {
for row in (0..BUFFER_HEIGHT - 1).rev() {
for col in 0..BUFFER_WIDTH {
let character = self.buffer.chars[row][col].read();
self.buffer.chars[row + 1][col].write(character);
}
}
self.clear_row(0);
self.col_pos = BUFFER_WIDTH;
}
pub fn clear(&mut self) {
for row in (0..BUFFER_HEIGHT - 1).rev() {
self.clear_row(row);
}
}
fn clear_row(&mut self, row: usize) {
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row][col].write(blank);
}
}
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string);
Ok(())
}
}
pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(cols.0, cols.1);
writer.write_fmt(args).unwrap()
})
}
+1 -1
View File
@@ -8,4 +8,4 @@ pub mod serial;
pub mod tasks;
pub mod sysinit;
pub mod authenticator;
pub mod render2;
pub mod render;
+205 -171
View File
@@ -6,6 +6,7 @@ use volatile::Volatile;
use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
use crate::std::io::Screen;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -46,132 +47,232 @@ struct ScreenChar {
colour: ColorCode,
}
impl ScreenChar {
fn null() -> ScreenChar {
ScreenChar {
character: 0u8,
colour: ColorCode::new(Color::White, Color::Black),
}
}
fn white(character: u8) -> ScreenChar {
ScreenChar {
character,
colour: ColorCode::new(Color::White, Color::Black),
}
}
}
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct Buffer {
struct VGAOutput {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct BufferSwap {
chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
struct CharGrid {
chars: Vec<[ScreenChar; BUFFER_WIDTH]>,
}
pub struct Renderer {
col_pos: usize,
pub col_code: ColorCode,
buffer: &'static mut Buffer,
userspace: BufferSwap,
upwards: CharGrid,
downwards: CharGrid,
pub sandbox: bool,
screen_ref: &'static mut VGAOutput, // this should not be accessed unless the screen is rendering a new frame
term_buffer: Vec<[ScreenChar; BUFFER_WIDTH]>, // this is the standard terminal output view
app_buffer: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], // this is where applications render their frames to
application_mode: bool, // if false: term mode; if true: app mode
temp_colour: Option<ColorCode>,
}
lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0,
col_code: ColorCode::new(Color::White, Color::Black),
buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
userspace: BufferSwap {
chars: [[ScreenChar {
character: 178u8,
colour: ColorCode::new(Color::White, Color::Black),
}; BUFFER_WIDTH]; BUFFER_HEIGHT]
},
upwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
downwards: CharGrid {
chars: vec![
[ScreenChar {
character: 32u8,
colour: ColorCode::new(Color::White, Color::Black),
}; 80]
]
},
sandbox: false,
screen_ref: unsafe { &mut *(0xb8000 as *mut VGAOutput) },
term_buffer: vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
app_buffer: [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
application_mode: false,
temp_colour: None,
});
}
impl Renderer {
pub fn text_mode(&mut self) -> Result<(), ()> {
if !self.sandbox {
return Err(());
};
self.buffer_swap().unwrap();
self.sandbox = false;
Ok(())
}
// EXTERNAL API : for use by standard library and other parts of the kernel
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
pub fn sandbox_mode(&mut self) -> Result<(), ()> {
if self.sandbox {
return Err(());
};
self.buffer_swap().unwrap();
self.sandbox = true;
Ok(())
}
fn buffer_swap(&mut self) -> Result<(), ()> {
for (i, _) in self.userspace.chars.clone().iter().enumerate() {
let tmp = self.buffer.chars[i].clone();
for (j, col) in self.userspace.chars[i].clone().iter().enumerate() {
self.buffer.chars[i][j].write(col.to_owned())
}
for (j, _) in tmp.iter().enumerate() {
self.userspace.chars[i][j] = tmp[j].read().to_owned()
}
}
Ok(())
}
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) {
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
if let Some(c) = self.fancy_char(*col) {
self.buffer.chars[i][j].write(ScreenChar {
character: c,
colour: self.col_code,
});
} else {
self.buffer.chars[i][j].write(ScreenChar {
character: *col as u8,
colour: self.col_code,
});
}
processed_frame[i][j] = match self.special_char(*col) {
Some(c) => ScreenChar::white(c as u8),
None => ScreenChar::white(*col as u8)
};
}
}
self.app_buffer = processed_frame;
}
pub fn application_mode(&mut self) -> Result<(), ()> {
if self.application_mode {
return Err(());
} else {
self.application_mode = true;
self.internal_render();
Ok(())
}
}
pub fn write_string(&mut self, string: &str) {
pub fn terminal_mode(&mut self) -> Result<(), ()> {
if !self.application_mode {
return Err(());
} else {
self.application_mode = false;
self.internal_render();
Ok(())
}
}
pub fn mode_is_app(&self) -> bool {
self.application_mode
}
pub fn write_char(&mut self, ch: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_byte(ch, col);
self.internal_render();
}
pub fn write_string(&mut self, string: &str, col: Option<ColorCode>) {
for ch in string.chars() {
if let Some(x) = self.fancy_char(ch) {
self.write_byte(x)
} else {
match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8),
_ => self.write_byte(0xfe),
match self.special_char(ch) {
Some(c) => self.write_byte(c, col),
None => match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8, col),
_ => self.write_byte(0xfe, col),
}
}
}
self.internal_render();
}
pub fn backspace(&mut self) -> Result<(), ()> {
loop {
if self.internal_backspace()? {
break;
}
}
self.internal_render();
Ok(())
}
pub fn clear(&mut self) { // clears the screen and all scroll-back
if self.application_mode { return; };
self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
self.internal_render();
}
pub fn with_colour(&mut self, cols: ColorCode) {
self.temp_colour = Some(cols);
}
pub fn reset_colour(&mut self) {
self.temp_colour = None;
}
// INTERNAL API ONLY
fn set_cursor_position(&mut self, row: usize, col: usize) {
use x86_64::instructions::port::Port;
let cursor_position: u16 = (row as u16) * 80 + (col as u16);
unsafe {// Write the high byte of the cursor position to register 14
let mut control_port = Port::<u8>::new(0x3D4);
control_port.write(14);
// Write the high byte of the cursor position to register 15
let mut data_port = Port::<u8>::new(0x3D5);
data_port.write((cursor_position >> 8) as u8);
// Write the low byte of the cursor position to register 14
control_port.write(15);
// Write the low byte of the cursor position to register 15
data_port.write((cursor_position & 0xFF) as u8);
}
}
fn internal_backspace(&mut self) -> Result<bool, ()> {
let mut should_break = false;
if self.col_pos == 0 {
self.internal_lastline();
}
self.col_pos -= 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
if self.term_buffer[buff_len - 1][col].character != 0 {
should_break = true
}
self.term_buffer[buff_len - 1][col] = ScreenChar::null();
Ok(should_break)
}
fn internal_newline(&mut self) { // moves all content one line up the screen and creates new line
if self.application_mode { return; }; // only in terminal mode
self.term_buffer.push([ScreenChar::null(); BUFFER_WIDTH]);
self.col_pos = 0;
}
fn internal_lastline(&mut self) { // goes back to previous line and shifts all lines down
if self.application_mode { return; };
self.term_buffer.pop();
self.col_pos = BUFFER_WIDTH;
}
fn write_screen_char(&mut self, ch: ScreenChar) { // TODO: optimise so that screen is not fully re-rendered for every string written.
match ch.character as u8 {
b'\n' => self.internal_newline(),
_ => {
if self.col_pos >= BUFFER_WIDTH {
self.internal_newline();
}
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
self.term_buffer[buff_len - 1][col] = ch;
self.col_pos += 1;
}
}
}
fn fancy_char(&self, ch: char) -> Option<u8> {
fn write_byte(&mut self, byte: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_screen_char(ScreenChar {
character: byte,
colour: match col {
Some(c) => c,
None => match self.temp_colour {
Some(c) => c,
None => ColorCode::new(Color::White, Color::Black),
}
},
});
}
fn internal_render(&mut self) { // private function that can only be used from within this struct.
if self.application_mode {
for (i, row) in self.app_buffer.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
} else {
let buff_len = self.term_buffer.len();
for (i, row) in self.term_buffer[buff_len - BUFFER_HEIGHT..buff_len].iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
}
self.set_cursor_position(BUFFER_HEIGHT - 1, self.col_pos);
}
fn special_char(&self, ch: char) -> Option<u8> {
let res: u8 = match ch {
'│' => 179,
'─' => 196,
@@ -192,89 +293,17 @@ impl Renderer {
'░' => 176,
'▓' => 178,
'«' => 174,
'»' => 175,
_ => {
return None;
}
};
Some(res)
}
pub fn backspace(&mut self) -> Result<(), ()> {
if self.col_pos == 0 {
self.undonewline();
}
self.col_pos -= 1;
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
self.buffer.chars[row][col].write(blank);
Ok(())
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.newline(),
byte => {
if self.col_pos >= BUFFER_WIDTH {
self.newline();
}
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let col_code = self.col_code;
self.buffer.chars[row][col].write(ScreenChar {
character: byte,
colour: col_code,
});
self.col_pos += 1
}
}
}
fn newline(&mut self) {
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);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.col_pos = 0;
}
pub fn undonewline(&mut self) {
for row in (0..BUFFER_HEIGHT - 1).rev() {
for col in 0..BUFFER_WIDTH {
let character = self.buffer.chars[row][col].read();
self.buffer.chars[row + 1][col].write(character);
}
}
self.clear_row(0);
self.col_pos = BUFFER_WIDTH;
}
pub fn clear(&mut self) {
for row in (0..BUFFER_HEIGHT - 1).rev() {
self.clear_row(row);
}
}
fn clear_row(&mut self, row: usize) {
let blank = ScreenChar {
character: b' ',
colour: self.col_code,
};
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row][col].write(blank);
}
}
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string);
self.write_string(string, None);
Ok(())
}
}
@@ -282,9 +311,14 @@ impl fmt::Write for Renderer {
pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
let colour_code = ColorCode::new(cols.0, cols.1);
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(cols.0, cols.1);
writer.write_fmt(args).unwrap()
writer.with_colour(colour_code);
writer.write_fmt(args).unwrap();
writer.reset_colour();
})
}
}
-298
View File
@@ -1,298 +0,0 @@
use core::fmt;
use lazy_static::lazy_static;
use spin::Mutex;
use volatile::Volatile;
use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
use crate::std::io::Screen;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ColorCode(u8);
impl ColorCode {
pub fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 5 | (foreground as u8))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
character: u8,
colour: ColorCode,
}
impl ScreenChar {
fn null() -> ScreenChar {
ScreenChar {
character: 0u8,
colour: ColorCode::new(Color::White, Color::Black),
}
}
fn white(character: u8) -> ScreenChar {
ScreenChar {
character,
colour: ColorCode::new(Color::White, Color::Black),
}
}
}
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct VGAOutput {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
pub struct Renderer {
col_pos: usize,
//col_code: ColorCode, // TODO: fully replace this with a colour code used in the fmt::Write function
screen_ref: &'static mut VGAOutput, // this should not be accessed unless the screen is rendering a new frame
term_buffer: Vec<[ScreenChar; BUFFER_WIDTH]>, // this is the standard terminal output view
app_buffer: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], // this is where applications render their frames to
application_mode: bool, // if false: term mode; if true: app mode
}
lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0,
screen_ref: unsafe { &mut *(0xb8000 as *mut VGAOutput) },
term_buffer: vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
app_buffer: [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
application_mode: false,
});
}
impl Renderer {
// EXTERNAL API : for use by standard library and other parts of the kernel
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
processed_frame[i][j] = match self.special_char(*col) {
Some(c) => ScreenChar::white(c as u8),
None => ScreenChar::white(*col as u8)
};
}
}
self.app_buffer = processed_frame;
}
// TODO: change standard library for alternative to these functions
pub fn application_mode(&mut self) -> Result<(), ()> {
if self.application_mode {
return Err(());
} else {
self.application_mode = true;
self.internal_render();
Ok(())
}
}
pub fn terminal_mode(&mut self) -> Result<(), ()> {
if !self.application_mode {
return Err(());
} else {
self.application_mode = false;
self.internal_render();
Ok(())
}
}
pub fn mode_is_app(&self) -> bool {
self.application_mode
}
pub fn write_char(&mut self, ch: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_byte(ch, col);
self.internal_render();
}
pub fn write_string(&mut self, string: &str, col: Option<ColorCode>) {
for ch in string.chars() {
match self.special_char(ch) {
Some(c) => self.write_byte(c, col),
None => match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8, col),
_ => self.write_byte(0xfe, col),
}
}
}
self.internal_render();
}
pub fn backspace(&mut self) -> Result<(), ()> {
self.internal_backspace()?;
self.internal_render();
Ok(())
}
pub fn clear(&mut self) { // clears the screen and all scroll-back
if self.application_mode { return; };
self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
self.internal_render();
}
// INTERNAL API ONLY
fn set_cursor_position(&mut self, row: usize, col: usize) {
use x86_64::instructions::port::Port;
let cursor_position: u16 = (row as u16) * 80 + (col as u16);
unsafe {// Write the high byte of the cursor position to register 14
let mut control_port = Port::<u8>::new(0x3D4);
control_port.write(14);
// Write the high byte of the cursor position to register 15
let mut data_port = Port::<u8>::new(0x3D5);
data_port.write((cursor_position >> 8) as u8);
// Write the low byte of the cursor position to register 14
control_port.write(15);
// Write the low byte of the cursor position to register 15
data_port.write((cursor_position & 0xFF) as u8);
}
}
fn internal_backspace(&mut self) -> Result<(), ()> {
if self.col_pos == 0 {
self.internal_lastline();
}
self.col_pos -= 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
self.term_buffer[buff_len - 1][col] = ScreenChar::null();
Ok(())
}
fn internal_newline(&mut self) { // moves all content one line up the screen and creates new line
if self.application_mode { return; }; // only in terminal mode
self.term_buffer.push([ScreenChar::null(); BUFFER_WIDTH]);
self.col_pos = 0;
}
fn internal_lastline(&mut self) { // goes back to previous line and shifts all lines down
if self.application_mode { return; };
self.term_buffer.pop();
self.col_pos = BUFFER_WIDTH;
}
fn write_screen_char(&mut self, ch: ScreenChar) { // TODO: optimise so that screen is not fully re-rendered for every string written.
match ch.character as u8 {
b'\n' => self.internal_newline(),
_ => {
if self.col_pos >= BUFFER_WIDTH {
self.internal_newline();
}
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
self.term_buffer[buff_len - 1][col] = ch;
self.col_pos += 1;
}
}
}
fn write_byte(&mut self, byte: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_screen_char(ScreenChar {
character: byte,
colour: match col {
Some(c) => c,
None => ColorCode::new(Color::White, Color::Black),
},
});
}
fn internal_render(&mut self) { // private function that can only be used from within this struct.
if self.application_mode {
for (i, row) in self.app_buffer.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
} else {
let buff_len = self.term_buffer.len();
for (i, row) in self.term_buffer[buff_len - BUFFER_HEIGHT..buff_len].iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
}
self.set_cursor_position(BUFFER_HEIGHT - 1, self.col_pos);
}
fn special_char(&self, ch: char) -> Option<u8> {
let res: u8 = match ch {
'│' => 179,
'─' => 196,
'┴' => 193,
'┤' => 180,
'═' => 205,
'║' => 186,
'╗' => 187,
'╝' => 188,
'╚' => 200,
'╔' => 201,
'»' => 175,
'┐' => 191,
'└' => 192,
'┘' => 217,
'┌' => 218,
'┼' => 197,
'░' => 176,
'▓' => 178,
'«' => 174,
_ => {
return None;
}
};
Some(res)
}
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string, None);
Ok(())
}
}
pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.write_fmt(args).unwrap()
})
}
+1 -1
View File
@@ -13,7 +13,7 @@ use futures_util::task::AtomicWaker;
use futures_util::stream::StreamExt;
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use crate::print;
use crate::kernel::render2::RENDERER;
use crate::kernel::render::RENDERER;
use alloc::{string::String};
static WAKER: AtomicWaker = AtomicWaker::new();
+4 -3
View File
@@ -1,11 +1,12 @@
use crate::{
kernel::render2::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode},
kernel::render::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode},
kernel::tasks::keyboard::KEYBOARD,
};
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec};
pub use crate::{print, println, serial_print, serial_println};
pub use crate::kernel::render::Color;
use lazy_static::lazy_static;
use spin::Mutex;
@@ -201,10 +202,10 @@ pub fn _log(args: core::fmt::Arguments) {
});
}
pub use crate::kernel::render2::Color;
pub fn write(args: core::fmt::Arguments, cols: (Color, Color)) {
crate::kernel::render2::write(args, cols);
crate::kernel::render::write(args, cols);
}
pub fn mkfs() {
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::kernel::render2::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER};
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER};
use crate::std::io::Frame;
use crate::{print, println};
use alloc::{