bootproof/src/driver/tty/text_display.rs

90 lines
2.9 KiB
Rust

use alloc::string::{String, ToString};
use alloc::vec::Vec;
use crate::driver::text_display::TextDisplay;
use crate::driver::tty::Tty;
/// A buffered virtual TTY implemented over a textual display.
pub struct TextDisplayTty<'display> {
term: &'display mut (dyn TextDisplay + 'display),
history: Vec<String>,
}
impl TextDisplayTty<'_> {
pub fn new<'a>(term: &'a mut dyn TextDisplay) -> TextDisplayTty<'a> {
TextDisplayTty {
term: term,
history: {
let mut vec = Vec::new();
vec.push("".to_string());
vec
},
}
}
}
impl Tty for TextDisplayTty<'_> {
fn putc(&mut self, c: char) {
if c == '\n' {
self.history.push("".to_string());
return;
}
let i = self.history.len() - 1;
self.history[i].push(c);
}
fn puts(&mut self, s: &str) {
for c in s.chars() {
self.putc(c);
}
}
fn clear(&mut self) {
self.history.clear();
self.history.push("".to_string());
}
fn flush(&mut self) {
// Each line of the history represents a virtual line of output.
// However, a line of output may be longer than the physical width of the display,
// in which case we may need to wrap the line so that it takes up two physical lines.
let mut physical_lines = Vec::new();
for line in &self.history {
let mut chars = line.chars().collect::<Vec<_>>().into_iter();
// We iterate over all of the characters in a virtual line
// until every character has been added to a physical line.
while chars.len() > 0 {
let mut physical_line = String::new();
// The width of a physical line may be no more than the width of the frame.
let width = chars.len().min(self.term.borrow_frame().width());
for _ in 0..width {
physical_line.push(chars.next().unwrap());
}
physical_lines.push(physical_line);
}
}
// This is how many lines on the display we'll need for all of our physical lines.
// We cannot have more lines than allowed by the display.
let mut y = physical_lines.len().min(self.term.borrow_frame().height() - 1);
let frame = self.term.borrow_mut_frame();
// We start from the lowest line and display each line until we reach the top of the screen.
// We cannot run out of physical lines because the lowest line
// is at lowest the number of physical lines necessary to display all lines.
for line in physical_lines.into_iter().rev() {
let mut x = 0;
for c in line.chars() {
frame.set(x, y, c);
x += 1;
}
if y == 0 {
break;
}
y -= 1;
}
self.term.refresh();
}
}