80 lines
2.4 KiB
Rust
80 lines
2.4 KiB
Rust
use std::{collections::VecDeque, sync::mpsc};
|
|
|
|
use egui::{
|
|
Align, CentralPanel, Context, FontFamily, Label, RichText, ScrollArea, ViewportBuilder,
|
|
ViewportId,
|
|
};
|
|
|
|
use crate::emulator::{EmulatorClient, EmulatorCommand, SimId};
|
|
|
|
use super::AppWindow;
|
|
|
|
const SCROLLBACK: usize = 1000;
|
|
|
|
pub struct TerminalWindow {
|
|
sim_id: SimId,
|
|
receiver: mpsc::Receiver<String>,
|
|
lines: VecDeque<String>,
|
|
}
|
|
|
|
impl TerminalWindow {
|
|
pub fn new(sim_id: SimId, client: &EmulatorClient) -> Self {
|
|
let (sender, receiver) = mpsc::channel();
|
|
client.send_command(EmulatorCommand::WatchStdout(sim_id, sender));
|
|
let mut lines = VecDeque::new();
|
|
lines.push_back(String::new());
|
|
Self {
|
|
sim_id,
|
|
receiver,
|
|
lines,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AppWindow for TerminalWindow {
|
|
fn viewport_id(&self) -> ViewportId {
|
|
ViewportId::from_hash_of(format!("terminal-{}", self.sim_id))
|
|
}
|
|
|
|
fn sim_id(&self) -> SimId {
|
|
self.sim_id
|
|
}
|
|
|
|
fn initial_viewport(&self) -> ViewportBuilder {
|
|
ViewportBuilder::default()
|
|
.with_title(format!("Terminal ({})", self.sim_id))
|
|
.with_inner_size((640.0, 480.0))
|
|
}
|
|
|
|
fn show(&mut self, ctx: &Context) {
|
|
if let Ok(text) = self.receiver.try_recv() {
|
|
let mut rest = text.as_str();
|
|
while let Some(index) = rest.find('\n') {
|
|
let (line, lines) = rest.split_at(index);
|
|
let current = self.lines.back_mut().unwrap();
|
|
current.push_str(line);
|
|
self.lines.push_back(String::new());
|
|
if self.lines.len() > SCROLLBACK {
|
|
self.lines.pop_front();
|
|
}
|
|
rest = &lines[1..];
|
|
}
|
|
self.lines.back_mut().unwrap().push_str(rest);
|
|
}
|
|
CentralPanel::default().show(ctx, |ui| {
|
|
ScrollArea::vertical()
|
|
.stick_to_bottom(true)
|
|
.auto_shrink([false, false])
|
|
.animated(false)
|
|
.show(ui, |ui| {
|
|
for line in &self.lines {
|
|
let label = Label::new(RichText::new(line).family(FontFamily::Monospace))
|
|
.halign(Align::LEFT)
|
|
.wrap();
|
|
ui.add(label);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|