diff options
author | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-06-22 22:34:42 -0400 |
---|---|---|
committer | Jeff Zhao <jeff.no.zhao@gmail.com> | 2021-06-22 22:34:42 -0400 |
commit | a11ed197df4fc3830387931c684346975333baf3 (patch) | |
tree | c11b81c58ff0ac52415684e1e383ebac92b94696 | |
parent | 72aaf0c5d10db0004d48e27c58d18d8f2c568f8f (diff) |
rudimentary file preview support
- this currently has only been tested with text files
- no line formatting is done yet
- only prints the preview as a single line
- folder previews can now be pushed onto a separate thread if needed
-rw-r--r-- | src/context/app_context.rs | 19 | ||||
-rw-r--r-- | src/context/mod.rs | 2 | ||||
-rw-r--r-- | src/context/preview_context.rs | 27 | ||||
-rw-r--r-- | src/context/worker_context.rs | 10 | ||||
-rw-r--r-- | src/event.rs | 6 | ||||
-rw-r--r-- | src/fs/dirlist.rs | 2 | ||||
-rw-r--r-- | src/preview/preview_default.rs | 2 | ||||
-rw-r--r-- | src/preview/preview_dir.rs | 60 | ||||
-rw-r--r-- | src/preview/preview_file.rs | 190 | ||||
-rw-r--r-- | src/ui/tui_backend.rs | 52 | ||||
-rw-r--r-- | src/ui/views/tui_folder_view.rs | 44 | ||||
-rw-r--r-- | src/ui/widgets/mod.rs | 2 | ||||
-rw-r--r-- | src/ui/widgets/tui_file_preview.rs | 35 | ||||
-rw-r--r-- | src/util/input.rs | 125 |
14 files changed, 406 insertions, 170 deletions
diff --git a/src/context/app_context.rs b/src/context/app_context.rs index e03079a..5c206e5 100644 --- a/src/context/app_context.rs +++ b/src/context/app_context.rs @@ -2,16 +2,16 @@ use std::collections::VecDeque; use std::sync::mpsc; use crate::config; -use crate::context::{LocalStateContext, TabContext, WorkerContext}; +use crate::context::{LocalStateContext, PreviewContext, TabContext, WorkerContext}; use crate::event::{AppEvent, Events}; use crate::util::search::SearchPattern; pub struct AppContext { pub exit: bool, - // app config - config: config::AppConfig, // event loop querying pub events: Events, + // app config + config: config::AppConfig, // context related to tabs tab_context: TabContext, // context related to local file state @@ -22,6 +22,8 @@ pub struct AppContext { message_queue: VecDeque<String>, // context related to io workers worker_context: WorkerContext, + // context related to previews + preview_context: PreviewContext, } impl AppContext { @@ -36,6 +38,7 @@ impl AppContext { search_context: None, message_queue: VecDeque::with_capacity(4), worker_context: WorkerContext::new(event_tx), + preview_context: PreviewContext::new(), config, } } @@ -47,6 +50,9 @@ impl AppContext { pub fn flush_event(&self) { self.events.flush(); } + pub fn clone_event_tx(&self) -> mpsc::Sender<AppEvent> { + self.events.event_tx.clone() + } pub fn config_ref(&self) -> &config::AppConfig { &self.config @@ -87,6 +93,13 @@ impl AppContext { self.search_context = Some(pattern); } + pub fn preview_context_ref(&self) -> &PreviewContext { + &self.preview_context + } + pub fn preview_context_mut(&mut self) -> &mut PreviewContext { + &mut self.preview_context + } + pub fn worker_context_ref(&self) -> &WorkerContext { &self.worker_context } diff --git a/src/context/mod.rs b/src/context/mod.rs index a1b8ed9..0a5f6c2 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -1,9 +1,11 @@ mod app_context; mod local_state; +mod preview_context; mod tab_context; mod worker_context; pub use self::app_context::AppContext; pub use self::local_state::LocalStateContext; +pub use self::preview_context::PreviewContext; pub use self::tab_context::TabContext; pub use self::worker_context::WorkerContext; diff --git a/src/context/preview_context.rs b/src/context/preview_context.rs new file mode 100644 index 0000000..d344323 --- /dev/null +++ b/src/context/preview_context.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; +use std::io; +use std::path; +use std::process; + +use crate::event::AppEvent; +use crate::preview::preview_file::FilePreview; + +pub struct PreviewContext { + pub previews: HashMap<path::PathBuf, FilePreview>, +} + +impl PreviewContext { + pub fn new() -> Self { + Self { + previews: HashMap::new(), + } + } + + pub fn get_preview(&self, p: &path::Path) -> Option<&FilePreview> { + self.previews.get(p) + } + + pub fn insert_preview(&mut self, p: path::PathBuf, file_preview: FilePreview) { + self.previews.insert(p, file_preview); + } +} diff --git a/src/context/worker_context.rs b/src/context/worker_context.rs index bd0802c..10b464b 100644 --- a/src/context/worker_context.rs +++ b/src/context/worker_context.rs @@ -7,23 +7,23 @@ use crate::event::AppEvent; use crate::io::{IoWorkerObserver, IoWorkerProgress, IoWorkerThread}; pub struct WorkerContext { + // to send info + event_tx: mpsc::Sender<AppEvent>, // queue of IO workers worker_queue: VecDeque<IoWorkerThread>, // current worker worker: Option<IoWorkerObserver>, - // to send info - event_tx: mpsc::Sender<AppEvent>, } impl WorkerContext { pub fn new(event_tx: mpsc::Sender<AppEvent>) -> Self { Self { + event_tx, worker_queue: VecDeque::new(), worker: None, - event_tx, } } - pub fn get_event_tx(&self) -> mpsc::Sender<AppEvent> { + pub fn clone_event_tx(&self) -> mpsc::Sender<AppEvent> { self.event_tx.clone() } // worker related @@ -61,7 +61,7 @@ impl WorkerContext { } pub fn start_next_job(&mut self) { - let tx = self.get_event_tx(); + let tx = self.clone_event_tx(); if let Some(worker) = self.worker_queue.pop_front() { let src = worker.paths[0].parent().unwrap().to_path_buf(); diff --git a/src/event.rs b/src/event.rs index da9330e..f8c8692 100644 --- a/src/event.rs +++ b/src/event.rs @@ -11,15 +11,17 @@ use signal_hook::iterator::SignalsInfo; use termion::event::Event; use termion::input::TermRead; +use crate::fs::JoshutoDirList; use crate::io::IoWorkerProgress; +use crate::preview::preview_file::FilePreview; #[derive(Debug)] pub enum AppEvent { Termion(Event), IoWorkerProgress(IoWorkerProgress), IoWorkerResult(io::Result<IoWorkerProgress>), - PreviewDir(io::Result<path::PathBuf>), - PreviewFile(process::Output), + PreviewDir(io::Result<JoshutoDirList>), + PreviewFile(FilePreview), Signal(i32), // Filesystem(notify::Result), } diff --git a/src/fs/dirlist.rs b/src/fs/dirlist.rs index e8dc90b..1414531 100644 --- a/src/fs/dirlist.rs +++ b/src/fs/dirlist.rs @@ -4,7 +4,7 @@ use std::{fs, path}; use crate::fs::{JoshutoDirEntry, JoshutoMetadata}; use crate::util::display::DisplayOption; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct JoshutoDirList { pub index: Option<usize>, path: path::PathBuf, diff --git a/src/preview/preview_default.rs b/src/preview/preview_default.rs index 9601800..691cf72 100644 --- a/src/preview/preview_default.rs +++ b/src/preview/preview_default.rs @@ -8,7 +8,7 @@ pub fn load_preview_path(context: &mut AppContext, backend: &mut TuiBackend, p: if p.is_dir() { preview_dir::load_preview(context, p); } else if p.is_file() { - preview_file::preview_path_with_script(context, backend, p); + preview_file::Background::preview_path_with_script(context, backend, p); } } diff --git a/src/preview/preview_dir.rs b/src/preview/preview_dir.rs index bf1d151..03ae189 100644 --- a/src/preview/preview_dir.rs +++ b/src/preview/preview_dir.rs @@ -4,45 +4,47 @@ use std::thread; use crate::context::AppContext; use crate::event::AppEvent; +use crate::fs::JoshutoDirList; use crate::history::DirectoryHistory; -pub fn load_preview(context: &mut AppContext, p: path::PathBuf) -> io::Result<path::PathBuf> { - // get preview +pub fn load_preview(context: &mut AppContext, p: path::PathBuf) -> io::Result<()> { let options = context.config_ref().display_options_ref().clone(); context .tab_context_mut() .curr_tab_mut() .history_mut() .create_or_soft_update(p.as_path(), &options)?; - Ok(p) + Ok(()) } -pub struct CursorDir {} - -impl CursorDir { - pub fn load(context: &mut AppContext) -> io::Result<()> { - let mut p: Option<path::PathBuf> = None; - if let Some(curr_list) = context.tab_context_ref().curr_tab_ref().curr_list_ref() { - if let Some(index) = curr_list.index { - let entry = &curr_list.contents[index]; - p = Some(entry.file_path().to_path_buf()) +pub fn background_load_preview( + context: &mut AppContext, + p: path::PathBuf, +) -> thread::JoinHandle<()> { + let need_to_load = match context + .tab_context_mut() + .curr_tab_mut() + .history_mut() + .get(p.as_path()) + { + Some(entry) => entry.need_update(), + None => true, + }; + if need_to_load { + let event_tx = context.events.event_tx.clone(); + let options = context.config_ref().display_options_ref().clone(); + let handle = thread::spawn(move || { + match JoshutoDirList::new(p, &options) { + Ok(dirlist) => { + event_tx.send(AppEvent::PreviewDir(Ok(dirlist))); + } + Err(_) => {} } - } - - let res = match p { - Some(p) if p.is_dir() => load_preview(context, p), - Some(p) => Err(io::Error::new( - io::ErrorKind::InvalidData, - "Not a directory".to_string(), - )), - None => Err(io::Error::new( - io::ErrorKind::NotFound, - "No such file or directory".to_string(), - )), - }; - match res { - Ok(_) => Ok(()), - Err(e) => Err(e), - } + () + }); + handle + } else { + let handle = thread::spawn(|| ()); + handle } } diff --git a/src/preview/preview_file.rs b/src/preview/preview_file.rs index 5aabb13..1a2e5f9 100644 --- a/src/preview/preview_file.rs +++ b/src/preview/preview_file.rs @@ -1,86 +1,142 @@ use std::io; use std::path; use std::process::{Command, Output}; +use std::thread; use tui::layout::{Constraint, Direction, Layout, Rect}; use tui::widgets::{Block, Borders}; use crate::context::AppContext; -use crate::ui::TuiBackend; - -pub fn preview_path_with_script( - context: &AppContext, - backend: &mut TuiBackend, - p: path::PathBuf, -) -> io::Result<Output> { - let preview_options = context.config_ref().preview_options_ref(); - let config = context.config_ref(); - - match preview_options.preview_script.as_ref() { - None => Err(io::Error::new( - io::ErrorKind::Other, - "No preview script specified", - )), - Some(script) => { - let area = backend.terminal.as_ref().unwrap().size().unwrap(); +use crate::event::AppEvent; +use crate::ui::{self, TuiBackend}; - let constraints: &[Constraint; 3] = &config.display_options_ref().default_layout; - - let layout_rect = if config.display_options_ref().show_borders() { - let area = Rect { - y: area.top() + 1, - height: area.height - 2, - ..area - }; - - let block = Block::default().borders(Borders::ALL); - let inner = block.inner(area); - - let layout_rect = Layout::default() - .direction(Direction::Horizontal) - .constraints(constraints.as_ref()) - .split(inner); - - let block = Block::default().borders(Borders::LEFT); - let inner3 = block.inner(layout_rect[2]); - inner3 - } else { - let layout_rect = Layout::default() - .direction(Direction::Horizontal) - .vertical_margin(1) - .constraints(constraints.as_ref()) - .split(area); - layout_rect[2] - }; - - let file_full_path = p.as_path(); - let preview_width = layout_rect.width; - let preview_height = layout_rect.height; - let image_cache = 0; - let preview_image = if preview_options.preview_images { 1 } else { 0 }; +#[derive(Clone, Debug)] +pub struct FilePreview { + pub _path: path::PathBuf, + pub status: std::process::ExitStatus, + pub output: String, +} + +impl std::convert::From<(path::PathBuf, Output)> for FilePreview { + fn from((p, output): (path::PathBuf, Output)) -> Self { + let s = String::from_utf8_lossy(&output.stdout).to_string(); + let status = output.status; + Self { + _path: p, + status, + output: s, + } + } +} + +pub struct Foreground {} + +impl Foreground { + pub fn preview_path_with_script( + context: &AppContext, + backend: &mut TuiBackend, + p: path::PathBuf, + ) -> io::Result<Output> { + let preview_options = context.config_ref().preview_options_ref(); + let config = context.config_ref(); + + match preview_options.preview_script.as_ref() { + None => Err(io::Error::new( + io::ErrorKind::Other, + "No preview script specified", + )), + Some(script) => { + let area = backend.terminal.as_ref().unwrap().size().unwrap(); + let display_options = config.display_options_ref(); + let constraints: &[Constraint; 3] = &display_options.default_layout; + + let layout_rect = ui::build_layout(area, constraints, display_options)[2]; + + let file_full_path = p.as_path(); + let preview_width = layout_rect.width; + let preview_height = layout_rect.height; + let image_cache = 0; + let preview_image = if preview_options.preview_images { 1 } else { 0 }; + + // spawn preview process + Command::new(script) + .arg(file_full_path) + .arg(preview_width.to_string()) + .arg(preview_height.to_string()) + .arg(image_cache.to_string()) + .arg(preview_image.to_string()) + .output() + } + } + } + + pub fn preview_with_script( + context: &AppContext, + backend: &mut TuiBackend, + ) -> io::Result<Output> { + let curr_tab = context.tab_context_ref().curr_tab_ref(); + let child_list = curr_tab.child_list_ref(); + + let preview_options = context.config_ref().preview_options_ref(); - // spawn preview process - Command::new(script) - .arg(file_full_path) - .arg(preview_width.to_string()) - .arg(preview_height.to_string()) - .arg(image_cache.to_string()) - .arg(preview_image.to_string()) - .output() + let config = context.config_ref(); + + match child_list.and_then(|list| list.curr_entry_ref()) { + None => Err(io::Error::new(io::ErrorKind::Other, "No file to preview")), + Some(entry) => { + Self::preview_path_with_script(context, backend, entry.file_path().to_path_buf()) + } } } } -pub fn preview_with_script(context: &AppContext, backend: &mut TuiBackend) -> io::Result<Output> { - let curr_tab = context.tab_context_ref().curr_tab_ref(); - let child_list = curr_tab.child_list_ref(); +pub struct Background {} + +impl Background { + pub fn preview_path_with_script( + context: &AppContext, + backend: &mut TuiBackend, + p: path::PathBuf, + ) { + if let Some(preview) = context.preview_context_ref().get_preview(p.as_path()) { + return; + } + + let preview_options = context.config_ref().preview_options_ref(); + let config = context.config_ref(); - let preview_options = context.config_ref().preview_options_ref(); + if let Some(script) = preview_options.preview_script.as_ref() { + let area = backend.terminal.as_ref().unwrap().size().unwrap(); + let display_options = config.display_options_ref(); + let constraints: &[Constraint; 3] = &display_options.default_layout; + + let layout_rect = ui::build_layout(area, constraints, display_options)[2]; + + let preview_width = layout_rect.width; + let preview_height = layout_rect.height; + let image_cache = 0; + let preview_image = if preview_options.preview_images { 1 } else { 0 }; - let config = context.config_ref(); + let script = script.clone(); + let event_tx = context.clone_event_tx(); + let thread = thread::spawn(move || { + let file_full_path = p.as_path(); - match child_list.and_then(|list| list.curr_entry_ref()) { - None => Err(io::Error::new(io::ErrorKind::Other, "No file to preview")), - Some(entry) => preview_path_with_script(context, backend, entry.file_path().to_path_buf()), + let res = Command::new(script) + .arg(file_full_path) + .arg(preview_width.to_string()) + .arg(preview_height.to_string()) + .arg(image_cache.to_string()) + .arg(preview_image.to_string()) + .output(); + match res { + Ok(output) => { + let preview = FilePreview::from((p, output)); + event_tx.send(AppEvent::PreviewFile(preview)); + } + Err(_) => {} + } + }); + } } } diff --git a/src/ui/tui_backend.rs b/src/ui/tui_backend.rs index f04450d..cf32c01 100644 --- a/src/ui/tui_backend.rs +++ b/src/ui/tui_backend.rs @@ -4,11 +4,14 @@ use std::io::Write; use termion::raw::{IntoRawMode, RawTerminal}; use termion::screen::AlternateScreen; use tui::backend::TermionBackend; -use tui::widgets::Widget; +use tui::layout::{Constraint, Direction, Layout, Rect}; +use tui::widgets::{Block, Borders, Widget}; #[cfg(feature = "mouse")] use termion::input::MouseTerminal; +use crate::util::display::DisplayOption; + trait New { fn new() -> std::io::Result<Self> where @@ -81,3 +84,50 @@ impl TuiBackend { Ok(()) } } + +pub fn build_layout( + area: Rect, + constraints: &[Constraint; 3], + display_options: &DisplayOption, +) -> Vec<Rect> { + let layout_rect = if display_options.show_borders() { + let area = Rect { + y: area.top() + 1, + height: area.height - 2, + ..area + }; + + let block = Block::default().borders(Borders::ALL); + let inner = block.inner(area); + + let layout_rect = Layout::default() + .direction(Direction::Horizontal) + .constraints(constraints.as_ref()) + .split(inner); + + let block = Block::default().borders(Borders::RIGHT); + let inner1 = block.inner(layout_rect[0]); + + let block = Block::default().borders(Borders::LEFT); + let inner3 = block.inner(layout_rect[2]); + + vec![inner1, layout_rect[1], inner3] + } else { + let mut layout_rect = Layout::default() + .direction(Direction::Horizontal) + .vertical_margin(1) + .constraints(constraints.as_ref()) + .split(area); + + layout_rect[0] = Rect { + width: layout_rect[0].width - 1, + ..layout_rect[0] + }; + layout_rect[1] = Rect { + width: layout_rect[1].width - 1, + ..layout_rect[1] + }; + layout_rect + }; + layout_rect +} diff --git a/src/ui/views/tui_folder_view.rs b/src/ui/views/tui_folder_view.rs index be3909a..e391473 100644 --- a/src/ui/views/tui_folder_view.rs +++ b/src/ui/views/tui_folder_view.rs @@ -6,7 +6,10 @@ use tui::text::Span; use tui::widgets::{Block, Borders, Paragraph, Widget, Wrap}; use crate::context::AppContext; -use crate::ui::widgets::{TuiDirList, TuiDirListDetailed, TuiFooter, TuiTabBar, TuiTopBar}; +use crate::ui; +use crate::ui::widgets::{ + TuiDirList, TuiDirListDetailed, TuiFilePreview, TuiFooter, TuiTabBar, TuiTopBar, +}; const TAB_VIEW_WIDTH: u16 = 15; @@ -26,22 +29,33 @@ impl<'a> TuiFolderView<'a> { impl<'a> Widget for TuiFolderView<'a> { fn render(self, area: Rect, buf: &mut Buffer) { + let preview_context = self.context.preview_context_ref(); let curr_tab = self.context.tab_context_ref().curr_tab_ref(); let curr_list = curr_tab.curr_list_ref(); let parent_list = curr_tab.parent_list_ref(); let child_list = curr_tab.child_list_ref(); + let curr_entry = curr_list.and_then(|c| c.curr_entry_ref()); + let config = self.context.config_ref(); + let display_options = config.display_options_ref(); - let constraints: &[Constraint; 3] = if !config.display_options_ref().collapse_preview() { - &config.display_options_ref().default_layout - } else { - match child_list { - Some(_) => &config.display_options_ref().default_layout, - None => &config.display_options_ref().no_preview_layout, - } - }; + let (default_layout, constraints): (bool, &[Constraint; 3]) = + if !display_options.collapse_preview() { + (true, &display_options.default_layout) + } else { + match child_list { + Some(_) => (true, &display_options.default_layout), + None => match curr_entry { + None => (false, &display_options.no_preview_layout), + Some(e) => match preview_context.get_preview(e.file_path()) { + Some(_) => (true, &display_options.default_layout), + None => (false, &display_options.no_preview_layout), + }, + }, + } + }; let layout_rect = if config.display_options_ref().show_borders() { let area = Rect { @@ -73,7 +87,7 @@ impl<'a> Widget for TuiFolderView<'a> { }; intersections.render_left(buf); - if child_list.as_ref().is_some() { + if default_layout { intersections.render_right(buf); } } @@ -108,7 +122,7 @@ impl<'a> Widget for TuiFolderView<'a> { // render parent view if let Some(list) = parent_list.as_ref() { TuiDirList::new(&list).render(layout_rect[0], buf); - }; + } // render current view if let Some(list) = curr_list.as_ref() { @@ -137,12 +151,16 @@ impl<'a> Widget for TuiFolderView<'a> { TuiFooter::new(list).render(rect, buf); } } - }; + } // render preview if let Some(list) = child_list.as_ref() { TuiDirList::new(&list).render(layout_rect[2], buf); - }; + } else if let Some(entry) = curr_entry { + if let Some(preview) = preview_context.get_preview(entry.file_path()) { + TuiFilePreview::new(entry, preview).render(layout_rect[2], buf); + } + } let topbar_width = area.width; let rect = Rect { diff --git a/src/ui/widgets/mod.rs b/src/ui/widgets/mod.rs index 451ccdb..6319d91 100644 --- a/src/ui/widgets/mod.rs +++ b/src/ui/widgets/mod.rs @@ -1,5 +1,6 @@ mod tui_dirlist; mod tui_dirlist_detailed; +mod tui_file_preview; mod tui_footer; mod tui_menu; mod tui_prompt; @@ -10,6 +11,7 @@ mod tui_worker; pub use self::tui_dirlist::TuiDirList; pub use self::tui_dirlist_detailed::{trim_file_label, TuiDirListDetailed}; +pub use self::tui_file_preview::TuiFilePreview; pub use self::tui_footer::TuiFooter; pub use self::tui_menu::TuiMenu; pub use self::tui_prompt::TuiPrompt; diff --git a/src/ui/widgets/tui_file_preview.rs b/src/ui/widgets/tui_file_preview.rs new file mode 100644 index 0000000..f731a0e --- /dev/null +++ b/src/ui/widgets/tui_file_preview.rs @@ -0,0 +1,35 @@ +use std::process; + +use tui::buffer::Buffer; +use tui::layout::Rect; +use tui::style::{Color, Modifier, Style}; +use tui::widgets::Widget; + +use crate::fs::JoshutoDirEntry; +use crate::preview::preview_file::FilePreview; +use crate::util::format; +use crate::util::string::UnicodeTruncate; +use crate::util::style; +use unicode_width::UnicodeWidthStr; + +const MIN_LEFT_LABEL_WIDTH: i32 = 15; + +const ELLIPSIS: &str = "…"; + +pub struct TuiFilePreview<'a> { + entry: &'a JoshutoDirEntry, + preview: &'a FilePreview, +} + +impl<'a> TuiFilePreview<'a> { + pub fn new(entry: &'a JoshutoDirEntry, preview: &'a FilePreview) -> Self { + Self { entry, preview } + } +} + +impl<'a> Widget for TuiFilePreview<'a> { + fn render(self, area: Rect, buf: &mut Buffer) { + let style = Style::default(); + buf.set_string(area.x, area.y, self.preview.output.as_str(), style); + } +} diff --git a/src/util/input.rs b/src/util/input.rs index 24aff5e..0896292 100644 --- a/src/util/input.rs +++ b/src/util/input.rs @@ -1,3 +1,7 @@ +use std::collections::{hash_map::Entry, HashMap}; +use std::path; +use std::process; + use signal_hook::consts::signal; use termion::event::{MouseButton, MouseEvent}; use tui::layout::{Constraint, Direction, Layout}; @@ -5,11 +9,84 @@ use tui::layout::{Constraint, Direction, Layout}; use crate::commands::{cursor_move, parent_cursor_move, AppExecute, KeyCommand}; use crate::context::AppContext; use crate::event::AppEvent; +use crate::fs::JoshutoDirList; use crate::history::DirectoryHistory; use crate::io::{FileOp, IoWorkerProgress}; +use crate::preview::preview_file::FilePreview; use crate::ui; use crate::util::format; +pub fn process_noninteractive(event: AppEvent, context: &mut AppContext) { + match event { + AppEvent::IoWorkerProgress(res) => process_worker_progress(context, res), + AppEvent::IoWorkerResult(res) => process_finished_worker(context, res), + AppEvent::PreviewDir(Ok(dirlist)) => process_dir_preview(context, dirlist), + AppEvent::PreviewFile(file_preview) => process_file_preview(context, file_preview), + AppEvent::Signal(signal::SIGWINCH) => {} + _ => {} + } +} + +pub fn process_worker_progress(context: &mut AppContext, res: IoWorkerProgress) { + let worker_context = context.worker_context_mut(); + worker_context.set_progress(res); + worker_context.update_msg(); +} + +pub fn process_finished_worker(context: &mut AppContext, res: std::io::Result<IoWorkerProgress>) { + let worker_context = context.worker_context_mut(); + let observer = worker_context.remove_worker().unwrap(); + let options = context.config_ref().display_options_ref().clone(); + for tab in context.tab_context_mut().iter_mut() { + let _ = tab.history_mut().reload(observer.dest_path(), &options); + let _ = tab.history_mut().reload(observer.src_path(), &options); + } + observer.join(); + match res { + Ok(progress) => { + let op = match progress.kind() { + FileOp::Copy => "copied", + FileOp::Cut => "moved", + }; + let processed_size = format::file_size_to_string(progress.bytes_processed()); + let total_size = format::file_size_to_string(progress.total_bytes()); + let msg = format!( + "successfully {} {} items ({}/{})", + op, + progress.total_files(), + processed_size, + total_size, + ); + context.push_msg(msg); + } + Err(e) => { + let msg = format!("{}", e); + context.push_msg(msg); + } + } +} + +pub fn process_dir_preview(context: &mut AppContext, dirlist: JoshutoDirList) { + let history = context.tab_context_mut().curr_tab_mut().history_mut(); + match history.entry(dirlist.file_path().to_path_buf()) { + Entry::Occupied(mut entry) => { + let old_dirlist = entry.get(); + if old_dirlist.need_update() { + entry.insert(dirlist); + } + } + Entry::Vacant(entry) => { + entry.insert(dirlist); + } + } +} + +pub fn process_file_preview(context: &mut AppContext, file_preview: FilePreview) { + context + .preview_context_mut() + .insert_preview(file_preview._path.clone(), file_preview); +} + pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut ui::TuiBackend) { let f_size = backend.terminal.as_ref().unwrap().size().unwrap(); @@ -93,51 +170,3 @@ pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut } context.flush_event(); } - -pub fn process_noninteractive(event: AppEvent, context: &mut AppContext) { - match event { - AppEvent::IoWorkerProgress(res) => process_worker_progress(context, res), - AppEvent::IoWorkerResult(res) => process_finished_worker(context, res), - AppEvent::Signal(signal::SIGWINCH) => {} - _ => {} - } -} - -pub fn process_worker_progress(context: &mut AppContext, res: IoWorkerProgress) { - let worker_context = context.worker_context_mut(); - worker_context.set_progress(res); - worker_context.update_msg(); -} - -pub fn process_finished_worker(context: &mut AppContext, res: std::io::Result<IoWorkerProgress>) { - let worker_context = context.worker_context_mut(); - let observer = worker_context.remove_worker().unwrap(); - let options = context.config_ref().display_options_ref().clone(); - for tab in context.tab_context_mut().iter_mut() { - let _ = tab.history_mut().reload(observer.dest_path(), &options); - let _ = tab.history_mut().reload(observer.src_path(), &options); - } - observer.join(); - match res { - Ok(progress) => { - let op = match progress.kind() { - FileOp::Copy => "copied", - FileOp::Cut => "moved", - }; - let processed_size = format::file_size_to_string(progress.bytes_processed()); - let total_size = format::file_size_to_string(progress.total_bytes()); - let msg = format!( - "successfully {} {} items ({}/{})", - op, - progress.total_files(), - processed_size, - total_size, - ); - context.push_msg(msg); - } - Err(e) => { - let msg = format!("{}", e); - context.push_msg(msg); - } - } -} |