broken :(

This commit is contained in:
nora 2021-12-20 00:05:48 +01:00
parent 2910482b03
commit b52292f667
3 changed files with 62 additions and 17 deletions

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::io::{ErrorKind, Write}; use std::io::{ErrorKind, Write};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::sync::{mpsc, Arc, Mutex}; use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration; use std::time::{Duration, Instant};
use std::{io, thread}; use std::{io, thread};
use tracing::{error, info}; use tracing::{error, info};
use tui::backend::Backend; use tui::backend::Backend;
@ -27,9 +27,7 @@ pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> SmResult
loop { loop {
terminal.draw(|f| view::render_ui(f, &mut app))?; terminal.draw(|f| view::render_ui(f, &mut app))?;
app.recv_stdouts(); if event::poll(Duration::from_secs(0))? {
if event::poll(Duration::from_millis(10))? {
if let Event::Key(key) = event::read()? { if let Event::Key(key) = event::read()? {
match key.code { match key.code {
KeyCode::Char('q') => match app.selected { KeyCode::Char('q') => match app.selected {
@ -40,14 +38,22 @@ pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> SmResult
}, },
KeyCode::Char('r') => app.run_service()?, KeyCode::Char('r') => app.run_service()?,
KeyCode::Char('k') => app.kill_service()?, KeyCode::Char('k') => app.kill_service()?,
KeyCode::Down => app.next(), KeyCode::Down => match app.selected {
KeyCode::Up => app.previous(), Some(_) => app.scroll_down(),
None => app.next(),
},
KeyCode::Up => match app.selected {
Some(_) => app.scroll_up(),
None => app.previous(),
},
KeyCode::Enter => app.select_service(), KeyCode::Enter => app.select_service(),
KeyCode::Esc => app.leave_service(), KeyCode::Esc => app.leave_service(),
_ => {} _ => {}
} }
} }
} }
app.recv_stdouts(Duration::from_millis(10));
} }
// terminate the child processes // terminate the child processes
@ -80,6 +86,7 @@ impl App {
env: service.env.unwrap_or_else(HashMap::new), env: service.env.unwrap_or_else(HashMap::new),
status: Arc::new(Mutex::new(ServiceStatus::NotStarted)), status: Arc::new(Mutex::new(ServiceStatus::NotStarted)),
std_io_buf: Vec::new(), std_io_buf: Vec::new(),
std_io_line_cache: Vec::new(),
stdout: StdIoStream { stdout: StdIoStream {
recv: stdout_recv, recv: stdout_recv,
send: stdout_send, send: stdout_send,
@ -89,6 +96,7 @@ impl App {
.collect::<io::Result<_>>()?, .collect::<io::Result<_>>()?,
}, },
selected: None, selected: None,
scroll_pos: None,
thread_terminates: HashMap::new(), thread_terminates: HashMap::new(),
}) })
} }
@ -97,13 +105,30 @@ impl App {
self.selected.is_none() self.selected.is_none()
} }
fn recv_stdouts(&mut self) { fn recv_stdouts(&mut self, duration: Duration) {
for service in self.table.services.iter_mut() { for service in self.table.services.iter_mut() {
while let Ok((buf, n)) = service.stdout.recv.try_recv() { let start = Instant::now();
service.std_io_buf.extend(&buf[0..n]); let buf = &mut service.std_io_buf;
if service.std_io_buf.len() > 2_000_000 { while let Ok((new_buf, n)) = service.stdout.recv.try_recv() {
service.std_io_buf.clear(); // todo don't let len_before = buf.len();
buf.extend(&new_buf[0..n]);
let new_newline_positions = new_buf
.iter()
.enumerate()
.filter(|(_, &byte)| byte == b'\n')
.map(|(position, _)| position + len_before);
service.std_io_line_cache.extend(new_newline_positions);
if buf.len() > 2_000_000 {
buf.clear(); // todo don't
service.std_io_line_cache.clear();
}
if start.elapsed() > duration {
break;
} }
} }
} }
@ -149,6 +174,14 @@ impl App {
self.table.table_state.select(Some(i)); self.table.table_state.select(Some(i));
} }
fn scroll_up(&mut self) {
self.scroll_pos = self.scroll_pos.map(|pos| pos + 1);
}
fn scroll_down(&mut self) {
self.scroll_pos = self.scroll_pos.map(|pos| pos - 1);
}
fn run_service(&mut self) -> SmResult { fn run_service(&mut self) -> SmResult {
let index = self.selected.or_else(|| self.table.table_state.selected()); let index = self.selected.or_else(|| self.table.table_state.selected());

View file

@ -10,6 +10,7 @@ pub use error::{SmError, SmResult};
pub struct App { pub struct App {
pub table: AppState, pub table: AppState,
pub selected: Option<usize>, pub selected: Option<usize>,
pub scroll_pos: Option<usize>,
pub thread_terminates: HashMap<usize, mpsc::Sender<()>>, pub thread_terminates: HashMap<usize, mpsc::Sender<()>>,
} }
@ -27,6 +28,8 @@ pub struct Service {
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub status: Arc<Mutex<ServiceStatus>>, pub status: Arc<Mutex<ServiceStatus>>,
pub std_io_buf: Vec<u8>, pub std_io_buf: Vec<u8>,
/// The start position of every line number
pub std_io_line_cache: Vec<usize>,
pub stdout: StdIoStream, pub stdout: StdIoStream,
} }

View file

@ -41,12 +41,21 @@ fn render_full_view<B: Backend>(f: &mut Frame<B>, state: &mut AppState, index: u
.borders(Borders::ALL) .borders(Borders::ALL)
.title("service".as_ref()); .title("service".as_ref());
let len = service.std_io_buf.len(); let height = area.height - 2; // the block takes up 2 lines
let stdout = if len > 10000 { let buf_len = service.std_io_buf.len();
String::from_utf8_lossy(&service.std_io_buf[len - 10000..len])
} else { let display_start_pos = service
String::from_utf8_lossy(&service.std_io_buf) .std_io_line_cache
}; .get(
service
.std_io_line_cache
.len()
.saturating_sub(usize::from(height)),
)
.cloned()
.unwrap_or(0);
let stdout = String::from_utf8_lossy(&service.std_io_buf[display_start_pos..buf_len]);
let paragraph = Paragraph::new(stdout.as_ref()).block(block.clone()); let paragraph = Paragraph::new(stdout.as_ref()).block(block.clone());