diff options
author | Tim Oram <dev@mitmaro.ca> | 2021-05-17 09:20:08 -0230 |
---|---|---|
committer | Tim Oram <dev@mitmaro.ca> | 2021-06-12 11:06:54 -0230 |
commit | 92f0349f8518855276d6c314c59bd0b3e08bad98 (patch) | |
tree | 3eae4d5ef261c0fa2e122b1ecbec968e2b2d085e /src/process | |
parent | 4242e8d01adc0ab8b5fe2fbd437026eb760abbdb (diff) |
Move the render stage to a separate thread
This decouples the render of the view from the process loop and renders
the view in a separate thread.
Diffstat (limited to 'src/process')
-rw-r--r-- | src/process/error.rs | 19 | ||||
-rw-r--r-- | src/process/mod.rs | 59 | ||||
-rw-r--r-- | src/process/modules.rs | 9 | ||||
-rw-r--r-- | src/process/process_module.rs | 11 | ||||
-rw-r--r-- | src/process/testutil.rs | 31 | ||||
-rw-r--r-- | src/process/window_size_error.rs | 6 |
6 files changed, 93 insertions, 42 deletions
diff --git a/src/process/error.rs b/src/process/error.rs index f5920bb..5b66a3a 100644 --- a/src/process/error.rs +++ b/src/process/error.rs @@ -11,6 +11,7 @@ use crate::{ render_context::RenderContext, view_data::ViewData, view_line::ViewLine, + ViewSender, }, }; @@ -29,14 +30,19 @@ impl ProcessModule for Error { ProcessResult::new() } - fn build_view_data(&mut self, _: &RenderContext, _: &TodoFile) -> &mut ViewData { - &mut self.view_data + fn build_view_data(&mut self, _: &RenderContext, _: &TodoFile) -> &ViewData { + &self.view_data } - fn handle_events(&mut self, event_handler: &EventHandler, _: &mut TodoFile) -> ProcessResult { + fn handle_events( + &mut self, + event_handler: &EventHandler, + view_sender: &ViewSender, + _: &mut TodoFile, + ) -> ProcessResult { let event = event_handler.read_event(&INPUT_OPTIONS, |event, _| event); let mut result = ProcessResult::from(event); - if handle_view_data_scroll(event, &mut self.view_data).is_none() { + if handle_view_data_scroll(event, view_sender).is_none() { if let Event::Key(_) = event { result = result.state(self.return_state); } @@ -49,7 +55,10 @@ impl Error { pub fn new() -> Self { Self { return_state: State::List, - view_data: ViewData::new(|updater| updater.set_show_title(true)), + view_data: ViewData::new(|updater| { + updater.set_show_title(true); + updater.set_retain_scroll_position(false); + }), } } diff --git a/src/process/mod.rs b/src/process/mod.rs index 3b915d2..cb63418 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -11,7 +11,7 @@ mod tests; #[cfg(test)] pub mod testutil; -use std::process::Command; +use std::{process::Command, thread}; use anyhow::{anyhow, Result}; @@ -19,35 +19,44 @@ use crate::{ input::{Event, EventHandler, MetaEvent}, process::{exit_status::ExitStatus, modules::Modules, process_result::ProcessResult, state::State}, todo_file::TodoFile, - view::{render_context::RenderContext, View}, + view::{render_context::RenderContext, spawn_view_thread, View, ViewSender}, }; pub struct Process { - exit_status: Option<ExitStatus>, event_handler: EventHandler, + exit_status: Option<ExitStatus>, rebase_todo: TodoFile, render_context: RenderContext, state: State, - view: View, + threads: Vec<thread::JoinHandle<()>>, + view_sender: ViewSender, } impl Process { pub(crate) fn new(rebase_todo: TodoFile, event_handler: EventHandler, view: View) -> Self { let view_size = view.get_view_size(); + let mut threads = vec![]; + + let (view_sender, view_thread) = spawn_view_thread(view); + threads.push(view_thread); + Self { - render_context: RenderContext::new(view_size.width() as u16, view_size.height() as u16), - exit_status: None, event_handler, + exit_status: None, rebase_todo, + render_context: RenderContext::new(view_size.width() as u16, view_size.height() as u16), state: State::List, - view, + threads, + view_sender, } } pub(crate) fn run(&mut self, mut modules: Modules<'_>) -> Result<Option<ExitStatus>> { - if self.view.start().is_err() { - return Ok(Some(ExitStatus::StateError)); + if self.view_sender.start().is_err() { + self.exit_status = Some(ExitStatus::StateError); + return Ok(self.exit_status); } + self.handle_process_result( &mut modules, &ProcessResult::new().event(Event::Resize( @@ -58,13 +67,21 @@ impl Process { self.activate(&mut modules, State::List); while self.exit_status.is_none() { let view_data = modules.build_view_data(self.state, &self.render_context, &self.rebase_todo); - if self.view.render(view_data).is_err() { + if self.view_sender.render(view_data).is_err() { self.exit_status = Some(ExitStatus::StateError); continue; } - loop { - let result = modules.handle_input(self.state, &self.event_handler, &mut self.rebase_todo); + if self.view_sender.is_poisoned() { + self.exit_status = Some(ExitStatus::StateError); + break; + } + let result = modules.handle_input( + self.state, + &self.event_handler, + &self.view_sender, + &mut self.rebase_todo, + ); if let Some(event) = result.event { if event != Event::None { @@ -74,7 +91,7 @@ impl Process { } } } - if self.view.end().is_err() { + if self.view_sender.stop().is_err() { return Ok(Some(ExitStatus::StateError)); } if let Some(status) = self.exit_status { @@ -82,6 +99,17 @@ impl Process { self.rebase_todo.write_file()?; } } + + if self.view_sender.end().is_err() { + return Ok(Some(ExitStatus::StateError)); + } + + while let Some(handle) = self.threads.pop() { + if handle.join().is_err() { + return Ok(Some(ExitStatus::StateError)); + } + } + Ok(self.exit_status) } @@ -113,6 +141,7 @@ impl Process { self.exit_status = Some(ExitStatus::Kill); }, Some(Event::Resize(width, height)) => { + self.view_sender.resize(width, height); self.render_context.update(width, height); if self.state != State::WindowSizeError && self.render_context.is_window_too_small() { self.state = State::WindowSizeError; @@ -140,7 +169,7 @@ impl Process { } fn run_command(&mut self, external_command: &(String, Vec<String>)) -> Result<MetaEvent> { - self.view.end()?; + self.view_sender.stop()?; let mut cmd = Command::new(external_command.0.clone()); cmd.args(external_command.1.clone()); @@ -157,7 +186,7 @@ impl Process { }) .map_err(|err| anyhow!(err)); - self.view.start()?; + self.view_sender.stop()?; result } diff --git a/src/process/modules.rs b/src/process/modules.rs index 057d54b..790cace 100644 --- a/src/process/modules.rs +++ b/src/process/modules.rs @@ -15,7 +15,7 @@ use crate::{ }, show_commit::ShowCommit, todo_file::TodoFile, - view::{render_context::RenderContext, view_data::ViewData}, + view::{render_context::RenderContext, view_data::ViewData, ViewSender}, }; pub struct Modules<'m> { @@ -69,7 +69,7 @@ impl<'m> Modules<'m> { state: State, render_context: &RenderContext, rebase_todo: &TodoFile, - ) -> &mut ViewData { + ) -> &ViewData { self.get_mut_module(state).build_view_data(render_context, rebase_todo) } @@ -77,9 +77,11 @@ impl<'m> Modules<'m> { &mut self, state: State, event_handler: &EventHandler, + view_sender: &ViewSender, rebase_todo: &mut TodoFile, ) -> ProcessResult { - self.get_mut_module(state).handle_events(event_handler, rebase_todo) + self.get_mut_module(state) + .handle_events(event_handler, view_sender, rebase_todo) } pub fn set_error_message(&mut self, error: &anyhow::Error) { @@ -125,6 +127,7 @@ mod tests { modules.handle_input( state, &test_context.event_handler_context.event_handler, + &test_context.event_handler_context.view_sender, &mut test_context.rebase_todo_file, ); modules.build_view_data(state, &test_context.render_context, &test_context.rebase_todo_file); diff --git a/src/process/process_module.rs b/src/process/process_module.rs index 736185c..37fdcd4 100644 --- a/src/process/process_module.rs +++ b/src/process/process_module.rs @@ -2,7 +2,7 @@ use crate::{ input::EventHandler, process::{process_result::ProcessResult, state::State}, todo_file::TodoFile, - view::{render_context::RenderContext, view_data::ViewData}, + view::{render_context::RenderContext, view_data::ViewData, ViewSender}, }; pub trait ProcessModule { @@ -12,7 +12,12 @@ pub trait ProcessModule { fn deactivate(&mut self) {} - fn build_view_data(&mut self, _render_context: &RenderContext, _rebase_todo: &TodoFile) -> &mut ViewData; + fn build_view_data(&mut self, _render_context: &RenderContext, _rebase_todo: &TodoFile) -> &ViewData; - fn handle_events(&mut self, _event_handler: &EventHandler, _rebase_todo: &mut TodoFile) -> ProcessResult; + fn handle_events( + &mut self, + _event_handler: &EventHandler, + _view_sender: &ViewSender, + _rebase_todo: &mut TodoFile, + ) -> ProcessResult; } diff --git a/src/process/testutil.rs b/src/process/testutil.rs index 4b99014..25e83b0 100644 --- a/src/process/testutil.rs +++ b/src/process/testutil.rs @@ -26,7 +26,7 @@ pub struct TestContext<'t> { } impl<'t> TestContext<'t> { - fn get_build_data<'tc>(&self, module: &'tc mut dyn ProcessModule) -> &'tc mut ViewData { + fn get_build_data<'tc>(&self, module: &'tc mut dyn ProcessModule) -> &'tc ViewData { module.build_view_data(&self.render_context, &self.rebase_todo_file) } @@ -39,25 +39,26 @@ impl<'t> TestContext<'t> { module.deactivate(); } - pub fn update_view_data_size(&self, module: &'_ mut dyn ProcessModule) { - let view_data = self.get_build_data(module); - view_data.set_view_size(self.render_context.width(), self.render_context.height()); - } - - pub fn build_view_data<'tc>(&self, module: &'tc mut dyn ProcessModule) -> &'tc mut ViewData { - let view_data = self.get_build_data(module); - view_data.set_view_size(self.render_context.width(), self.render_context.height()); - view_data + pub fn build_view_data<'tc>(&self, module: &'tc mut dyn ProcessModule) -> &'tc ViewData { + self.get_build_data(module) } pub fn handle_event(&mut self, module: &'_ mut dyn ProcessModule) -> ProcessResult { - module.handle_events(&self.event_handler_context.event_handler, &mut self.rebase_todo_file) + module.handle_events( + &self.event_handler_context.event_handler, + &self.event_handler_context.view_sender, + &mut self.rebase_todo_file, + ) } pub fn handle_n_events(&mut self, module: &'_ mut dyn ProcessModule, n: usize) -> Vec<ProcessResult> { let mut results = vec![]; for _ in 0..n { - results.push(module.handle_events(&self.event_handler_context.event_handler, &mut self.rebase_todo_file)); + results.push(module.handle_events( + &self.event_handler_context.event_handler, + &self.event_handler_context.view_sender, + &mut self.rebase_todo_file, + )); } results } @@ -65,7 +66,11 @@ impl<'t> TestContext<'t> { pub fn handle_all_events(&mut self, module: &'_ mut dyn ProcessModule) -> Vec<ProcessResult> { let mut results = vec![]; for _ in 0..self.event_handler_context.number_events { - results.push(module.handle_events(&self.event_handler_context.event_handler, &mut self.rebase_todo_file)); + results.push(module.handle_events( + &self.event_handler_context.event_handler, + &self.event_handler_context.view_sender, + &mut self.rebase_todo_file, + )); } results } diff --git a/src/process/window_size_error.rs b/src/process/window_size_error.rs index 19249e1..c519ce2 100644 --- a/src/process/window_size_error.rs +++ b/src/process/window_size_error.rs @@ -4,7 +4,7 @@ use crate::{ input::{Event, EventHandler, InputOptions}, process::{process_module::ProcessModule, process_result::ProcessResult, state::State}, todo_file::TodoFile, - view::{render_context::RenderContext, view_data::ViewData, view_line::ViewLine}, + view::{render_context::RenderContext, view_data::ViewData, view_line::ViewLine, ViewSender}, }; const HEIGHT_ERROR_MESSAGE: &str = "Window too small, increase height to continue"; @@ -26,7 +26,7 @@ impl ProcessModule for WindowSizeError { ProcessResult::new() } - fn build_view_data(&mut self, context: &RenderContext, _: &TodoFile) -> &mut ViewData { + fn build_view_data(&mut self, context: &RenderContext, _: &TodoFile) -> &ViewData { let view_width = context.width(); let message = if !context.is_minimum_view_width() { if view_width >= SHORT_ERROR_MESSAGE.len() { @@ -52,7 +52,7 @@ impl ProcessModule for WindowSizeError { &mut self.view_data } - fn handle_events(&mut self, event_handler: &EventHandler, _: &mut TodoFile) -> ProcessResult { + fn handle_events(&mut self, event_handler: &EventHandler, _: &ViewSender, _: &mut TodoFile) -> ProcessResult { let event = event_handler.read_event(&INPUT_OPTIONS, |event, _| event); let mut result = ProcessResult::from(event); |