diff options
Diffstat (limited to 'src/shell/history/entry.rs')
-rw-r--r-- | src/shell/history/entry.rs | 160 |
1 files changed, 56 insertions, 104 deletions
diff --git a/src/shell/history/entry.rs b/src/shell/history/entry.rs index 90509d3..24b90cf 100644 --- a/src/shell/history/entry.rs +++ b/src/shell/history/entry.rs @@ -1,20 +1,11 @@ use crate::shell::prelude::*; -enum State { - Running((usize, usize)), - Exited(ExitInfo), -} - pub struct Entry { cmdline: String, env: Env, - state: State, - vt: super::vt::Vt, + pty: super::pty::Pty, + job: super::job::Job, fullscreen: Option<bool>, - input: tokio::sync::mpsc::UnboundedSender<Vec<u8>>, - resize: tokio::sync::mpsc::UnboundedSender<(u16, u16)>, - start_time: time::OffsetDateTime, - start_instant: std::time::Instant, } impl Entry { @@ -22,51 +13,56 @@ impl Entry { cmdline: String, env: Env, size: (u16, u16), - input: tokio::sync::mpsc::UnboundedSender<Vec<u8>>, - resize: tokio::sync::mpsc::UnboundedSender<(u16, u16)>, + event_w: crate::shell::event::Writer, ) -> Self { - let span = (0, cmdline.len()); + let (pty, pts) = super::pty::Pty::new(size, event_w.clone()).unwrap(); + let job = super::job::Job::new(&cmdline, env.clone(), &pts, event_w) + .unwrap(); Self { cmdline, env, - state: State::Running(span), - vt: super::vt::Vt::new(size), - input, - resize, + pty, + job, fullscreen: None, - start_time: time::OffsetDateTime::now_utc(), - start_instant: std::time::Instant::now(), } } pub fn render( - &mut self, + &self, out: &mut impl textmode::Textmode, idx: usize, entry_count: usize, + state: &super::job::State, + vt: &mut super::pty::Vt, size: (u16, u16), focused: bool, scrolling: bool, offset: time::UtcOffset, ) { - let time = self.exit_info().map_or_else( + let time = state.exit_info().map_or_else( || { format!( "[{}]", - crate::format::time(self.start_time.to_offset(offset)) + crate::format::time( + self.job.start_time().to_offset(offset) + ) ) }, |info| { format!( "({}) [{}]", crate::format::duration( - info.instant - self.start_instant + *info.instant() - *self.job.start_instant() + ), + crate::format::time( + self.job.start_time().to_offset(offset) ), - crate::format::time(self.start_time.to_offset(offset)), ) }, ); + vt.bell(out, focused); + set_bgcolor(out, idx, focused); out.set_fgcolor(textmode::color::YELLOW); let entry_count_width = format!("{}", entry_count + 1).len(); @@ -77,24 +73,21 @@ impl Entry { out.reset_attributes(); set_bgcolor(out, idx, focused); - if let Some(info) = self.exit_info() { - if info.status.signal().is_some() { + if let Some(info) = state.exit_info() { + let status = info.status(); + if status.signal().is_some() { out.set_fgcolor(textmode::color::MAGENTA); - } else if info.status.success() { + } else if status.success() { out.set_fgcolor(textmode::color::DARKGREY); } else { out.set_fgcolor(textmode::color::RED); } - out.write_str(&crate::format::exit_status(info.status)); + out.write_str(&crate::format::exit_status(status)); } else { out.write_str(" "); } out.reset_attributes(); - self.vt.bell(out, focused); - - let vt = &self.vt; - if vt.is_bell() { out.set_bgcolor(textmode::Color::Rgb(64, 16, 16)); } else { @@ -110,7 +103,7 @@ impl Entry { } else { self.cmd() }; - if let State::Running(span) = self.state { + if let super::job::State::Running(span) = state { let span = (span.0.min(cmd.len()), span.1.min(cmd.len())); if !cmd[..span.0].is_empty() { out.write_str(&cmd[..span.0]); @@ -127,13 +120,13 @@ impl Entry { out.write_str(cmd); } if self.cmd().len() > max_len { - if let State::Running(span) = self.state { + if let super::job::State::Running(span) = state { if span.0 < cmd.len() && span.1 > cmd.len() { out.set_bgcolor(textmode::Color::Rgb(16, 64, 16)); } } out.write_str(" "); - if let State::Running(span) = self.state { + if let super::job::State::Running(span) = state { if span.1 > cmd.len() { out.set_bgcolor(textmode::Color::Rgb(16, 64, 16)); } @@ -164,7 +157,7 @@ impl Entry { out.hide_cursor(true); } else { let last_row = - vt.output_lines(focused && !scrolling, self.running()); + vt.output_lines(focused && !scrolling, state.running()); let mut max_lines = self.max_lines(entry_count); if last_row > max_lines { out.write(b"\r\n"); @@ -209,47 +202,31 @@ impl Entry { out.reset_attributes(); } - pub fn render_fullscreen(&mut self, out: &mut impl textmode::Textmode) { - let vt = &mut self.vt; - out.write(&vt.screen().state_formatted()); - vt.bell(out, true); - out.reset_attributes(); - } - - pub fn send_input(&self, bytes: Vec<u8>) { - if self.running() { - self.input.send(bytes).unwrap(); - } + pub fn render_fullscreen(&self, out: &mut impl textmode::Textmode) { + self.pty.with_vt_mut(|vt| { + out.write(&vt.screen().state_formatted()); + vt.bell(out, true); + out.reset_attributes(); + }); } - pub fn resize(&mut self, size: (u16, u16)) { - if self.running() { - self.resize.send(size).unwrap(); - self.vt.set_size(size); - } + pub fn input(&self, bytes: Vec<u8>) { + self.pty.input(bytes); } - pub fn size(&self) -> (u16, u16) { - self.vt.size() - } - - pub fn process(&mut self, input: &[u8]) { - self.vt.process(input); + pub fn resize(&self, size: (u16, u16)) { + self.pty.resize(size); } pub fn cmd(&self) -> &str { &self.cmdline } - pub fn env(&self) -> &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()); + self.fullscreen = Some(!self.pty.fullscreen()); } } @@ -258,63 +235,38 @@ impl Entry { } pub fn running(&self) -> bool { - matches!(self.state, State::Running(_)) + self.job.running() } pub fn lines(&self, entry_count: usize, focused: bool) -> usize { + let running = self.running(); 1 + std::cmp::min( - self.vt.output_lines(focused, self.running()), + self.pty.with_vt(|vt| vt.output_lines(focused, running)), self.max_lines(entry_count), ) } - fn max_lines(&self, entry_count: usize) -> usize { - if self.env.idx() == entry_count - 1 { - 15 - } else { - 5 - } - } - pub fn should_fullscreen(&self) -> bool { - self.fullscreen - .unwrap_or_else(|| self.vt.screen().alternate_screen()) + self.fullscreen.unwrap_or_else(|| self.pty.fullscreen()) } - pub fn set_span(&mut self, span: (usize, usize)) { - if matches!(self.state, State::Running(_)) { - self.state = State::Running(span); - } + pub fn lock_vt(&self) -> std::sync::MutexGuard<super::pty::Vt> { + self.pty.lock_vt() } - pub fn finish( - &mut self, - env: Env, - event_w: &crate::shell::event::Writer, - ) { - self.state = State::Exited(ExitInfo::new(env.latest_status())); - self.env = env; - event_w.send(Event::PtyClose); + pub fn lock_state(&self) -> std::sync::MutexGuard<super::job::State> { + self.job.lock_state() } - fn exit_info(&self) -> Option<&ExitInfo> { - match &self.state { - State::Running(..) => None, - State::Exited(exit_info) => Some(exit_info), - } + pub fn set_span(&self, span: (usize, usize)) { + self.job.set_span(span); } -} - -struct ExitInfo { - status: std::process::ExitStatus, - instant: std::time::Instant, -} -impl ExitInfo { - fn new(status: std::process::ExitStatus) -> Self { - Self { - status, - instant: std::time::Instant::now(), + fn max_lines(&self, entry_count: usize) -> usize { + if self.env.idx() == entry_count - 1 { + 15 + } else { + 5 } } } |