From 53193c426d19d529382e75e8af4ab9266b992557 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 5 Jan 2022 06:22:35 -0500 Subject: split out more --- src/state/history/mod.rs | 304 +---------------------------------------------- 1 file changed, 5 insertions(+), 299 deletions(-) (limited to 'src/state/history/mod.rs') diff --git a/src/state/history/mod.rs b/src/state/history/mod.rs index 8b15916..9df3103 100644 --- a/src/state/history/mod.rs +++ b/src/state/history/mod.rs @@ -3,6 +3,8 @@ use futures_lite::future::FutureExt as _; use std::os::unix::io::{FromRawFd as _, IntoRawFd as _}; use std::os::unix::process::ExitStatusExt as _; +mod entry; +pub use entry::Entry; mod pty; pub struct History { @@ -144,7 +146,7 @@ impl History { self.entries.push(async_std::sync::Arc::clone(&entry)); let mut entry = entry.lock_arc().await; - entry.vt.process(err_str.replace('\n', "\r\n").as_bytes()); + entry.process(err_str.replace('\n', "\r\n").as_bytes()); let mut env = env.clone(); env.set_status(async_std::process::ExitStatus::from_raw(1 << 8)); entry.finish(env, event_w).await; @@ -267,291 +269,6 @@ impl std::iter::DoubleEndedIterator for VisibleEntries { } } -pub struct Entry { - cmdline: String, - env: crate::env::Env, - vt: vt100::Parser, - audible_bell_state: usize, - visual_bell_state: usize, - fullscreen: Option, - input: async_std::channel::Sender>, - resize: async_std::channel::Sender<(u16, u16)>, - start_time: time::OffsetDateTime, - start_instant: std::time::Instant, - exit_info: Option, -} - -impl Entry { - fn new( - cmdline: String, - env: crate::env::Env, - size: (u16, u16), - input: async_std::channel::Sender>, - resize: async_std::channel::Sender<(u16, u16)>, - ) -> Self { - Self { - cmdline, - env, - vt: vt100::Parser::new(size.0, size.1, 0), - audible_bell_state: 0, - visual_bell_state: 0, - input, - resize, - fullscreen: None, - start_time: time::OffsetDateTime::now_utc(), - start_instant: std::time::Instant::now(), - exit_info: None, - } - } - - fn render( - &self, - out: &mut impl textmode::Textmode, - idx: usize, - entry_count: usize, - width: u16, - focused: bool, - scrolling: bool, - offset: time::UtcOffset, - ) { - let time = self.exit_info.as_ref().map_or_else( - || { - format!( - "[{}]", - crate::format::time(self.start_time.to_offset(offset)) - ) - }, - |info| { - format!( - "({}) [{}]", - crate::format::duration( - info.instant - self.start_instant - ), - crate::format::time(self.start_time.to_offset(offset)), - ) - }, - ); - - set_bgcolor(out, idx, focused); - out.set_fgcolor(textmode::color::YELLOW); - let entry_count_width = format!("{}", entry_count + 1).len(); - let idx_str = format!("{}", idx + 1); - out.write_str(&" ".repeat(entry_count_width - idx_str.len())); - out.write_str(&idx_str); - out.write_str(" "); - out.reset_attributes(); - - set_bgcolor(out, idx, focused); - if let Some(info) = &self.exit_info { - if info.status.signal().is_some() { - out.set_fgcolor(textmode::color::MAGENTA); - } else if info.status.success() { - out.set_fgcolor(textmode::color::DARKGREY); - } else { - out.set_fgcolor(textmode::color::RED); - } - out.write_str(&crate::format::exit_status(info.status)); - } else { - out.write_str(" "); - } - out.reset_attributes(); - - set_bgcolor(out, idx, focused); - out.write_str("$ "); - if self.running() { - out.set_bgcolor(textmode::Color::Rgb(16, 64, 16)); - } - let cmd = self.cmd(); - let start = usize::from(out.screen().cursor_position().1); - let end = usize::from(width) - time.len() - 2; - let max_len = end - start; - if cmd.len() > max_len { - out.write_str(&cmd[..(max_len - 4)]); - out.set_fgcolor(textmode::color::BLUE); - out.write_str(" ..."); - } else { - out.write_str(cmd); - } - out.reset_attributes(); - - set_bgcolor(out, idx, focused); - let cur_pos = out.screen().cursor_position(); - out.write_str(&" ".repeat( - usize::from(width) - time.len() - 1 - usize::from(cur_pos.1), - )); - out.write_str(&time); - out.write_str(" "); - out.reset_attributes(); - - if self.binary() { - let msg = "This appears to be binary data. Fullscreen this entry to view anyway."; - let len: u16 = msg.len().try_into().unwrap(); - out.move_to( - out.screen().cursor_position().0 + 1, - (width - len) / 2, - ); - out.set_fgcolor(textmode::color::RED); - out.write_str(msg); - out.hide_cursor(true); - } else { - let last_row = self.output_lines(width, focused && !scrolling); - if last_row > 5 { - out.write(b"\r\n"); - out.set_fgcolor(textmode::color::BLUE); - out.write_str("..."); - out.reset_attributes(); - } - let mut out_row = out.screen().cursor_position().0 + 1; - let screen = self.vt.screen(); - let pos = screen.cursor_position(); - let mut wrapped = false; - let mut cursor_found = None; - for (idx, row) in screen - .rows_formatted(0, width) - .enumerate() - .take(last_row) - .skip(last_row.saturating_sub(5)) - { - let idx: u16 = idx.try_into().unwrap(); - out.reset_attributes(); - if !wrapped { - out.move_to(out_row, 0); - } - out.write(&row); - wrapped = screen.row_wrapped(idx); - if pos.0 == idx { - cursor_found = Some(out_row); - } - out_row += 1; - } - if focused && !scrolling { - if let Some(row) = cursor_found { - out.hide_cursor(screen.hide_cursor()); - out.move_to(row, pos.1); - } else { - out.hide_cursor(true); - } - } - } - out.reset_attributes(); - } - - fn render_fullscreen(&mut self, out: &mut impl textmode::Textmode) { - let screen = self.vt.screen(); - let new_audible_bell_state = screen.audible_bell_count(); - let new_visual_bell_state = screen.visual_bell_count(); - - out.write(&screen.state_formatted()); - - if self.audible_bell_state != new_audible_bell_state { - out.write(b"\x07"); - self.audible_bell_state = new_audible_bell_state; - } - - if self.visual_bell_state != new_visual_bell_state { - out.write(b"\x1bg"); - self.visual_bell_state = new_visual_bell_state; - } - - out.reset_attributes(); - } - - pub async fn send_input(&self, bytes: Vec) { - if self.running() { - self.input.send(bytes).await.unwrap(); - } - } - - pub async fn resize(&self, size: (u16, u16)) { - if self.running() { - self.resize.send(size).await.unwrap(); - } - } - - pub fn cmd(&self) -> &str { - &self.cmdline - } - - pub fn env(&self) -> &crate::env::Env { - &self.env - } - - pub fn toggle_fullscreen(&mut self) { - if let Some(fullscreen) = self.fullscreen { - self.fullscreen = Some(!fullscreen); - } else { - self.fullscreen = Some(!self.vt.screen().alternate_screen()); - } - } - - pub fn set_fullscreen(&mut self, fullscreen: bool) { - self.fullscreen = Some(fullscreen); - } - - pub fn running(&self) -> bool { - self.exit_info.is_none() - } - - pub fn binary(&self) -> bool { - self.vt.screen().errors() > 5 - } - - pub fn lines(&self, width: u16, focused: bool) -> usize { - let lines = self.output_lines(width, focused); - 1 + std::cmp::min(6, lines) - } - - pub fn output_lines(&self, width: u16, focused: bool) -> usize { - if self.binary() { - return 1; - } - - let screen = self.vt.screen(); - let mut last_row = 0; - for (idx, row) in screen.rows(0, width).enumerate() { - if !row.is_empty() { - last_row = idx + 1; - } - } - if focused && self.running() { - last_row = std::cmp::max( - last_row, - usize::from(screen.cursor_position().0) + 1, - ); - } - last_row - } - - pub fn should_fullscreen(&self) -> bool { - self.fullscreen - .unwrap_or_else(|| self.vt.screen().alternate_screen()) - } - - async fn finish( - &mut self, - env: crate::env::Env, - event_w: async_std::channel::Sender, - ) { - self.exit_info = Some(ExitInfo::new(*env.latest_status())); - self.env = env; - event_w.send(crate::event::Event::PtyClose).await.unwrap(); - } -} - -struct ExitInfo { - status: async_std::process::ExitStatus, - instant: std::time::Instant, -} - -impl ExitInfo { - fn new(status: async_std::process::ExitStatus) -> Self { - Self { - status, - instant: std::time::Instant::now(), - } - } -} - fn run_commands( ast: crate::parse::Commands, entry: async_std::sync::Arc>, @@ -562,7 +279,7 @@ fn run_commands( ) { async_std::task::spawn(async move { let pty = match pty::Pty::new( - entry.lock_arc().await.vt.screen().size(), + entry.lock_arc().await.size(), &entry, input_r, resize_r, @@ -571,7 +288,7 @@ fn run_commands( Ok(pty) => pty, Err(e) => { let mut entry = entry.lock_arc().await; - entry.vt.process( + entry.process( format!("nbsh: failed to allocate pty: {}\r\n", e) .as_bytes(), ); @@ -596,7 +313,6 @@ fn run_commands( entry .lock_arc() .await - .vt .process(format!("nbsh: {}\r\n", e).as_bytes()); env.set_status(async_std::process::ExitStatus::from_raw( 1 << 8, @@ -696,13 +412,3 @@ async fn run_pipeline( } } } - -fn set_bgcolor(out: &mut impl textmode::Textmode, idx: usize, focus: bool) { - if focus { - out.set_bgcolor(textmode::Color::Rgb(0x56, 0x1b, 0x8b)); - } else if idx % 2 == 0 { - out.set_bgcolor(textmode::Color::Rgb(0x24, 0x21, 0x00)); - } else { - out.set_bgcolor(textmode::Color::Rgb(0x20, 0x20, 0x20)); - } -} -- cgit v1.2.3-54-g00ecf