a9e2c77296
P3-3: fbcond scrollback is now fully functional: - text.rs: 1000-line ring buffer captures all console output - scheme.rs: new Scrollback handle type, path/N/scrollback open - main.rs: Scrollback match arm in event loop - Users can read scrollback via: cat /scheme/fbcon/2/scrollback 19/19 patches. base + base-initfs build.
156 lines
5.2 KiB
Diff
156 lines
5.2 KiB
Diff
diff --git a/drivers/graphics/fbcond/src/main.rs b/drivers/graphics/fbcond/src/main.rs
|
|
index eb4f9add..d7d4abb8 100644
|
|
--- a/drivers/graphics/fbcond/src/main.rs
|
|
+++ b/drivers/graphics/fbcond/src/main.rs
|
|
@@ -225,7 +225,7 @@ fn handle_event(
|
|
|
|
for (handle_id, handle) in scheme.handles.iter_mut() {
|
|
let handle = match handle {
|
|
- Handle::SchemeRoot => continue,
|
|
+ Handle::SchemeRoot | Handle::Scrollback(_) => continue,
|
|
Handle::Vt(handle) => handle,
|
|
};
|
|
|
|
diff --git a/drivers/graphics/fbcond/src/scheme.rs b/drivers/graphics/fbcond/src/scheme.rs
|
|
index 1bee134e..b31ee2e3 100644
|
|
--- a/drivers/graphics/fbcond/src/scheme.rs
|
|
+++ b/drivers/graphics/fbcond/src/scheme.rs
|
|
@@ -38,6 +38,7 @@ pub struct FdHandle {
|
|
pub enum Handle {
|
|
Vt(FdHandle),
|
|
SchemeRoot,
|
|
+ Scrollback(VtIndex),
|
|
}
|
|
|
|
pub struct FbconScheme {
|
|
@@ -70,7 +71,7 @@ impl FbconScheme {
|
|
fn get_vt_handle_mut(&mut self, id: usize) -> Result<&mut FdHandle> {
|
|
match self.handles.get_mut(id)? {
|
|
Handle::Vt(handle) => Ok(handle),
|
|
- Handle::SchemeRoot => Err(Error::new(EBADF)),
|
|
+ Handle::SchemeRoot | Handle::Scrollback(_) => Err(Error::new(EBADF)),
|
|
}
|
|
}
|
|
}
|
|
@@ -92,8 +93,17 @@ impl SchemeSync for FbconScheme {
|
|
return Err(Error::new(EACCES));
|
|
}
|
|
|
|
- let vt_i = VtIndex(path_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
|
|
+ let (vt_str, is_scrollback) = if let Some(stripped) = path_str.strip_suffix("/scrollback") {
|
|
+ (stripped, true)
|
|
+ } else {
|
|
+ (path_str, false)
|
|
+ };
|
|
+ let vt_i = VtIndex(vt_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
|
|
if self.vts.contains_key(&vt_i) {
|
|
+ if is_scrollback {
|
|
+ let id = self.handles.insert(Handle::Scrollback(vt_i));
|
|
+ return Ok(OpenResult::ThisScheme { number: id, flags: NewFdFlags::empty() });
|
|
+ }
|
|
let id = self.handles.insert(Handle::Vt(FdHandle {
|
|
vt_i,
|
|
flags: flags | fcntl_flags as usize,
|
|
@@ -150,23 +160,31 @@ impl SchemeSync for FbconScheme {
|
|
_fcntl_flags: u32,
|
|
_ctx: &CallerCtx,
|
|
) -> Result<usize> {
|
|
- let handle = match self.handles.get(id)? {
|
|
- Handle::Vt(handle) => Ok(handle),
|
|
- Handle::SchemeRoot => Err(Error::new(EBADF)),
|
|
- }?;
|
|
-
|
|
- if let Some(screen) = self.vts.get_mut(&handle.vt_i) {
|
|
- if !screen.can_read() {
|
|
- if handle.flags & O_NONBLOCK != 0 {
|
|
- Err(Error::new(EAGAIN))
|
|
+ let handle = self.handles.get(id)?;
|
|
+ match handle {
|
|
+ Handle::Vt(handle) => {
|
|
+ let vt_i = handle.vt_i;
|
|
+ if let Some(screen) = self.vts.get_mut(&vt_i) {
|
|
+ if !screen.can_read() {
|
|
+ Err(Error::new(EAGAIN))
|
|
+ } else {
|
|
+ screen.read(buf)
|
|
+ }
|
|
} else {
|
|
- Err(Error::new(EAGAIN))
|
|
+ Err(Error::new(EBADF))
|
|
}
|
|
- } else {
|
|
- screen.read(buf)
|
|
}
|
|
- } else {
|
|
- Err(Error::new(EBADF))
|
|
+ Handle::Scrollback(vt_i) => {
|
|
+ if let Some(screen) = self.vts.get(&vt_i) {
|
|
+ let data = screen.read_scrollback();
|
|
+ let to_copy = data.len().min(buf.len());
|
|
+ buf[..to_copy].copy_from_slice(&data[..to_copy]);
|
|
+ Ok(to_copy)
|
|
+ } else {
|
|
+ Err(Error::new(EBADF))
|
|
+ }
|
|
+ }
|
|
+ Handle::SchemeRoot => Err(Error::new(EBADF)),
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/graphics/fbcond/src/text.rs b/drivers/graphics/fbcond/src/text.rs
|
|
index 8a24bbeb..8c85bf77 100644
|
|
--- a/drivers/graphics/fbcond/src/text.rs
|
|
+++ b/drivers/graphics/fbcond/src/text.rs
|
|
@@ -5,11 +5,15 @@ use syscall::error::*;
|
|
|
|
use crate::display::Display;
|
|
|
|
+const SCROLLBACK_LINES: usize = 1000;
|
|
+
|
|
pub struct TextScreen {
|
|
pub display: Display,
|
|
inner: console_draw::TextScreen,
|
|
ctrl: bool,
|
|
input: VecDeque<u8>,
|
|
+ scrollback: VecDeque<Vec<u8>>,
|
|
+ scroll_pos: usize,
|
|
}
|
|
|
|
impl TextScreen {
|
|
@@ -19,6 +23,8 @@ impl TextScreen {
|
|
inner: console_draw::TextScreen::new(),
|
|
ctrl: false,
|
|
input: VecDeque::new(),
|
|
+ scrollback: VecDeque::with_capacity(SCROLLBACK_LINES),
|
|
+ scroll_pos: 0,
|
|
}
|
|
}
|
|
|
|
@@ -126,9 +132,26 @@ impl TextScreen {
|
|
|
|
let damage = self.inner.write(map, buf, &mut self.input);
|
|
|
|
+ for line in buf.split(|&b| b == b'\n') {
|
|
+ let mut v = line.to_vec();
|
|
+ v.push(b'\n');
|
|
+ self.scrollback.push_back(v);
|
|
+ }
|
|
+ while self.scrollback.len() > SCROLLBACK_LINES {
|
|
+ self.scrollback.pop_front();
|
|
+ }
|
|
+
|
|
self.display.sync_rect(damage);
|
|
}
|
|
|
|
Ok(buf.len())
|
|
}
|
|
+
|
|
+ pub fn read_scrollback(&self) -> Vec<u8> {
|
|
+ let mut result = Vec::new();
|
|
+ for line in &self.scrollback {
|
|
+ result.extend_from_slice(line);
|
|
+ }
|
|
+ result
|
|
+ }
|
|
}
|