Merge branch 'bootlog-scroll' into 'master'
Add scrollback into fbbootlogd See merge request redox-os/drivers!294
This commit is contained in:
@@ -260,3 +260,37 @@ impl TextScreen {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextBuffer {
|
||||
pub lines: VecDeque<Vec<u8>>,
|
||||
pub lines_max: usize,
|
||||
}
|
||||
|
||||
impl TextBuffer {
|
||||
pub fn new(max: usize) -> Self {
|
||||
let mut lines = VecDeque::new();
|
||||
lines.push_back(Vec::new());
|
||||
Self {
|
||||
lines,
|
||||
lines_max: max,
|
||||
}
|
||||
}
|
||||
pub fn write(&mut self, buf: &[u8]) {
|
||||
if buf.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for &byte in buf {
|
||||
self.lines.back_mut().unwrap().push(byte);
|
||||
|
||||
if byte == b'\n' {
|
||||
self.lines.push_back(Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
let max_len = self.lines_max;
|
||||
while self.lines.len() > max_len {
|
||||
self.lines.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,11 @@ fn inner(daemon: redox_daemon::Daemon) -> ! {
|
||||
.expect("fbbootlogd: error while reading events")
|
||||
{
|
||||
ConsumerHandleEvent::Events(&[]) => break,
|
||||
ConsumerHandleEvent::Events(_) => {}
|
||||
ConsumerHandleEvent::Events(events) => {
|
||||
for event in events {
|
||||
scheme.handle_input(&event);
|
||||
}
|
||||
}
|
||||
ConsumerHandleEvent::Handoff => {
|
||||
eprintln!("fbbootlogd: handoff requested");
|
||||
scheme.handle_handoff();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::ptr;
|
||||
use std::{cmp, ptr};
|
||||
|
||||
use console_draw::TextScreen;
|
||||
use graphics_ipc::v2::V2GraphicsHandle;
|
||||
use inputd::ConsumerHandle;
|
||||
use orbclient::{Event, EventOption};
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
@@ -19,6 +20,10 @@ pub struct FbbootlogScheme {
|
||||
pub input_handle: ConsumerHandle,
|
||||
display_map: Option<DisplayMap>,
|
||||
text_screen: console_draw::TextScreen,
|
||||
text_buffer: console_draw::TextBuffer,
|
||||
is_scrollback: bool,
|
||||
scrollback_offset: usize,
|
||||
shift: bool,
|
||||
}
|
||||
|
||||
impl FbbootlogScheme {
|
||||
@@ -27,6 +32,10 @@ impl FbbootlogScheme {
|
||||
input_handle: ConsumerHandle::new_vt().expect("fbbootlogd: Failed to open vt"),
|
||||
display_map: None,
|
||||
text_screen: console_draw::TextScreen::new(),
|
||||
text_buffer: console_draw::TextBuffer::new(1000),
|
||||
is_scrollback: false,
|
||||
scrollback_offset: 1000,
|
||||
shift: false,
|
||||
};
|
||||
|
||||
scheme.handle_handoff();
|
||||
@@ -64,6 +73,91 @@ impl FbbootlogScheme {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(&mut self, ev: &Event) {
|
||||
match ev.to_option() {
|
||||
EventOption::Key(key_event) => {
|
||||
if key_event.scancode == 0x2A || key_event.scancode == 0x36 {
|
||||
self.shift = key_event.pressed;
|
||||
} else if !key_event.pressed || !self.shift {
|
||||
return;
|
||||
}
|
||||
match key_event.scancode {
|
||||
0x48 => {
|
||||
// Up
|
||||
if self.scrollback_offset >= 1 {
|
||||
self.scrollback_offset -= 1;
|
||||
}
|
||||
}
|
||||
0x49 => {
|
||||
// Page up
|
||||
if self.scrollback_offset >= 10 {
|
||||
self.scrollback_offset -= 10;
|
||||
} else {
|
||||
self.scrollback_offset = 0;
|
||||
}
|
||||
}
|
||||
0x50 => {
|
||||
// Down
|
||||
self.scrollback_offset += 1;
|
||||
}
|
||||
0x51 => {
|
||||
// Page down
|
||||
self.scrollback_offset += 10;
|
||||
}
|
||||
0x47 => {
|
||||
// Home
|
||||
self.scrollback_offset = 0;
|
||||
}
|
||||
0x4F => {
|
||||
// End
|
||||
self.scrollback_offset = self.text_buffer.lines_max;
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
self.handle_scrollback_render();
|
||||
}
|
||||
|
||||
fn handle_scrollback_render(&mut self) {
|
||||
let Some(map) = &mut self.display_map else {
|
||||
return;
|
||||
};
|
||||
let buffer_len = self.text_buffer.lines.len();
|
||||
let dmap = &mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
width: map.inner.width(),
|
||||
height: map.inner.height(),
|
||||
};
|
||||
// for both extra space on wrapping text and a scrollback indicator
|
||||
let spare_lines = 3;
|
||||
self.is_scrollback = true;
|
||||
self.scrollback_offset = cmp::min(
|
||||
self.scrollback_offset,
|
||||
buffer_len - dmap.height / 16 + spare_lines,
|
||||
);
|
||||
let mut i = self.scrollback_offset;
|
||||
self.text_screen
|
||||
.write(dmap, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new());
|
||||
while i < buffer_len {
|
||||
let mut damage =
|
||||
self.text_screen
|
||||
.write(dmap, &self.text_buffer.lines[i][..], &mut VecDeque::new());
|
||||
i += 1;
|
||||
let yd = (damage.y + damage.height) as usize;
|
||||
if i == buffer_len || yd + spare_lines * 16 > dmap.height {
|
||||
// render until end of screen
|
||||
damage.height = (dmap.height as u32) - damage.y;
|
||||
map.display_handle.update_plane(0, map.fb, damage).unwrap();
|
||||
self.is_scrollback = i < buffer_len;
|
||||
break;
|
||||
} else {
|
||||
map.display_handle.update_plane(0, map.fb, damage).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) {
|
||||
let (width, height) = match map.display_handle.display_size(0) {
|
||||
Ok((width, height)) => (width, height),
|
||||
@@ -163,19 +257,22 @@ impl SchemeSync for FbbootlogScheme {
|
||||
) -> Result<usize> {
|
||||
if let Some(map) = &mut self.display_map {
|
||||
Self::handle_resize(map, &mut self.text_screen);
|
||||
self.text_buffer.write(buf);
|
||||
|
||||
let damage = self.text_screen.write(
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
width: map.inner.width(),
|
||||
height: map.inner.height(),
|
||||
},
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
if !self.is_scrollback {
|
||||
let damage = self.text_screen.write(
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
width: map.inner.width(),
|
||||
height: map.inner.height(),
|
||||
},
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
|
||||
if let Some(map) = &self.display_map {
|
||||
map.display_handle.update_plane(0, map.fb, damage).unwrap();
|
||||
if let Some(map) = &self.display_map {
|
||||
map.display_handle.update_plane(0, map.fb, damage).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,23 +182,24 @@ impl HbaPort {
|
||||
) -> Result<u64> {
|
||||
let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap();
|
||||
|
||||
let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
|
||||
cmdheader.prdtl.write(1);
|
||||
let slot = self
|
||||
.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| {
|
||||
cmdheader.prdtl.write(1);
|
||||
|
||||
let prdt_entry = &mut prdt_entries[0];
|
||||
prdt_entry.dba_low.write(dest.physical() as u32);
|
||||
prdt_entry
|
||||
.dba_high
|
||||
.write((dest.physical() as u64 >> 32) as u32);
|
||||
prdt_entry.dbc.write(512 | 1);
|
||||
let prdt_entry = &mut prdt_entries[0];
|
||||
prdt_entry.dba_low.write(dest.physical() as u32);
|
||||
prdt_entry
|
||||
.dba_high
|
||||
.write((dest.physical() as u64 >> 32) as u32);
|
||||
prdt_entry.dbc.write(512 | 1);
|
||||
|
||||
cmdfis.pm.write(1 << 7);
|
||||
cmdfis.command.write(cmd);
|
||||
cmdfis.device.write(0);
|
||||
cmdfis.countl.write(1);
|
||||
cmdfis.counth.write(0);
|
||||
})?
|
||||
.ok_or(Error::new(EIO))?;
|
||||
cmdfis.pm.write(1 << 7);
|
||||
cmdfis.command.write(cmd);
|
||||
cmdfis.device.write(0);
|
||||
cmdfis.countl.write(1);
|
||||
cmdfis.counth.write(0);
|
||||
})?
|
||||
.ok_or(Error::new(EIO))?;
|
||||
|
||||
self.ata_stop(slot)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user