From 34538845ba899a6892c6bbc10d294f209b78fdd7 Mon Sep 17 00:00:00 2001 From: Jeff Zhao Date: Mon, 21 Jun 2021 19:44:17 -0400 Subject: fix file sizes not appearing when filename too long (#78) * fix file sizes not appearing when filename too long * refactor previewing code - event.rs is moved out of utils as its an integral part of the codebase - load_child.rs has been replaced with preview module - moved previewing logic inside run.rs instead of spreading it across multiple commands * revert tui_dirlist_detailed to use MIN_LEFT_LABEL_WIDTH - add previewing loading trigger to mouse input as well * fix: right label disappears (#79) Co-authored-by: DLFW --- src/commands/change_directory.rs | 2 - src/commands/cursor_move.rs | 14 +---- src/commands/delete_files.rs | 2 - src/commands/key_command.rs | 2 - src/commands/new_directory.rs | 2 - src/commands/open_file.rs | 2 - src/commands/parent_directory.rs | 2 - src/commands/reload.rs | 2 - src/commands/rename_file.rs | 2 - src/commands/sort.rs | 12 ++-- src/commands/tab_ops.rs | 2 - src/commands/touch_file.rs | 9 ++- src/context/app_context.rs | 4 +- src/context/worker_context.rs | 2 +- src/event.rs | 109 +++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/preview/mod.rs | 6 +- src/preview/preview_default.rs | 27 ++++++++ src/preview/preview_dir.rs | 48 +++++++++++++++ src/preview/preview_file.rs | 86 ++++++++++++++++++++++++++ src/preview/preview_sh.rs | 15 ----- src/run.rs | 8 ++- src/ui/views/tui_command_menu.rs | 2 +- src/ui/views/tui_textfield.rs | 2 +- src/ui/views/tui_worker_view.rs | 2 +- src/ui/widgets/tui_dirlist_detailed.rs | 83 ++++++++++++++++--------- src/ui/widgets/tui_prompt.rs | 2 +- src/util/event.rs | 105 ------------------------------- src/util/input.rs | 2 +- src/util/load_child.rs | 31 ---------- src/util/mod.rs | 2 - 31 files changed, 350 insertions(+), 240 deletions(-) create mode 100644 src/event.rs create mode 100644 src/preview/preview_default.rs create mode 100644 src/preview/preview_dir.rs create mode 100644 src/preview/preview_file.rs delete mode 100644 src/preview/preview_sh.rs delete mode 100644 src/util/event.rs delete mode 100644 src/util/load_child.rs diff --git a/src/commands/change_directory.rs b/src/commands/change_directory.rs index 561aea4..0499011 100644 --- a/src/commands/change_directory.rs +++ b/src/commands/change_directory.rs @@ -3,7 +3,6 @@ use std::path; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::history::DirectoryHistory; -use crate::util::load_child::LoadChild; pub fn cd(path: &path::Path, context: &mut AppContext) -> std::io::Result<()> { std::env::set_current_dir(path)?; @@ -25,6 +24,5 @@ fn _change_directory(path: &path::Path, context: &mut AppContext) -> std::io::Re pub fn change_directory(context: &mut AppContext, path: &path::Path) -> JoshutoResult<()> { _change_directory(path, context)?; - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/cursor_move.rs b/src/commands/cursor_move.rs index c17097b..92042d6 100644 --- a/src/commands/cursor_move.rs +++ b/src/commands/cursor_move.rs @@ -1,7 +1,7 @@ use crate::context::AppContext; use crate::error::JoshutoResult; -use crate::history::DirectoryHistory; use crate::ui::TuiBackend; + use std::path::PathBuf; pub fn cursor_move(new_index: usize, context: &mut AppContext) -> JoshutoResult<()> { @@ -20,18 +20,6 @@ pub fn cursor_move(new_index: usize, context: &mut AppContext) -> JoshutoResult< path = Some(entry.file_path().to_path_buf()) } } - - // get preview - if let Some(path) = path { - if path.is_dir() { - let options = context.config_ref().display_options_ref().clone(); - context - .tab_context_mut() - .curr_tab_mut() - .history_mut() - .create_or_soft_update(path.as_path(), &options)?; - } - } Ok(()) } diff --git a/src/commands/delete_files.rs b/src/commands/delete_files.rs index ba84b33..4339a39 100644 --- a/src/commands/delete_files.rs +++ b/src/commands/delete_files.rs @@ -7,7 +7,6 @@ use crate::context::AppContext; use crate::history::DirectoryHistory; use crate::ui::widgets::TuiPrompt; use crate::ui::TuiBackend; -use crate::util::load_child::LoadChild; use super::reload; @@ -116,6 +115,5 @@ pub fn delete_selected_files( for tab in context.tab_context_mut().iter_mut() { tab.history_mut().reload(&curr_path, &options)?; } - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/key_command.rs b/src/commands/key_command.rs index d4f94be..3ca2980 100644 --- a/src/commands/key_command.rs +++ b/src/commands/key_command.rs @@ -4,7 +4,6 @@ use crate::context::AppContext; use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult}; use crate::io::IoWorkerOptions; use crate::ui::TuiBackend; -use crate::util::load_child::LoadChild; use crate::util::select::SelectOption; use crate::util::sort::SortType; @@ -358,7 +357,6 @@ impl AppExecute for KeyCommand { Self::BulkRename => bulk_rename::bulk_rename(context, backend), Self::ChangeDirectory(p) => { change_directory::change_directory(context, p.as_path())?; - LoadChild::load_child(context)?; Ok(()) } Self::NewTab => tab_ops::new_tab(context), diff --git a/src/commands/new_directory.rs b/src/commands/new_directory.rs index 6b0f3d0..8364d93 100644 --- a/src/commands/new_directory.rs +++ b/src/commands/new_directory.rs @@ -3,7 +3,6 @@ use std::path; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::history::DirectoryHistory; -use crate::util::load_child::LoadChild; pub fn new_directory(context: &mut AppContext, p: &path::Path) -> JoshutoResult<()> { std::fs::create_dir_all(p)?; @@ -12,6 +11,5 @@ pub fn new_directory(context: &mut AppContext, p: &path::Path) -> JoshutoResult< for tab in context.tab_context_mut().iter_mut() { tab.history_mut().reload(&curr_path, &options)?; } - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/open_file.rs b/src/commands/open_file.rs index ca07abc..e1d4208 100644 --- a/src/commands/open_file.rs +++ b/src/commands/open_file.rs @@ -6,7 +6,6 @@ use crate::context::AppContext; use crate::error::{JoshutoError, JoshutoErrorKind, JoshutoResult}; use crate::ui::views::TuiTextField; use crate::ui::TuiBackend; -use crate::util::load_child::LoadChild; use super::change_directory; @@ -35,7 +34,6 @@ pub fn open(context: &mut AppContext, backend: &mut TuiBackend) -> JoshutoResult if entry.file_path().is_dir() { let path = entry.file_path().to_path_buf(); change_directory::cd(path.as_path(), context)?; - LoadChild::load_child(context)?; } else { let paths = context .tab_context_ref() diff --git a/src/commands/parent_directory.rs b/src/commands/parent_directory.rs index 198841b..0b3a0b7 100644 --- a/src/commands/parent_directory.rs +++ b/src/commands/parent_directory.rs @@ -1,6 +1,5 @@ use crate::context::AppContext; use crate::error::JoshutoResult; -use crate::util::load_child::LoadChild; use super::reload; @@ -24,6 +23,5 @@ pub fn parent_directory_helper(context: &mut AppContext) -> std::io::Result<()> pub fn parent_directory(context: &mut AppContext) -> JoshutoResult<()> { parent_directory_helper(context)?; reload::soft_reload(context.tab_context_ref().index, context)?; - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/reload.rs b/src/commands/reload.rs index 1c149ce..de33a4f 100644 --- a/src/commands/reload.rs +++ b/src/commands/reload.rs @@ -1,6 +1,5 @@ use crate::context::AppContext; use crate::error::JoshutoResult; -use crate::util::load_child::LoadChild; pub fn soft_reload(index: usize, context: &mut AppContext) -> std::io::Result<()> { let options = context.config_ref().display_options_ref().clone(); @@ -42,6 +41,5 @@ pub fn reload(context: &mut AppContext, index: usize) -> std::io::Result<()> { pub fn reload_dirlist(context: &mut AppContext) -> JoshutoResult<()> { reload(context, context.tab_context_ref().index)?; - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/rename_file.rs b/src/commands/rename_file.rs index 011ee50..6907445 100644 --- a/src/commands/rename_file.rs +++ b/src/commands/rename_file.rs @@ -3,7 +3,6 @@ use std::path; use crate::context::AppContext; use crate::error::JoshutoResult; use crate::ui::TuiBackend; -use crate::util::load_child::LoadChild; use super::command_line; @@ -36,7 +35,6 @@ pub fn rename_file(context: &mut AppContext, dest: &path::Path) -> JoshutoResult if let Some(path) = path { _rename_file(context, path.as_path(), dest)?; } - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/sort.rs b/src/commands/sort.rs index 58ffd2e..dfc86a2 100644 --- a/src/commands/sort.rs +++ b/src/commands/sort.rs @@ -1,8 +1,6 @@ use crate::context::AppContext; use crate::error::JoshutoResult; use crate::history::DirectoryHistory; - -use crate::util::load_child::LoadChild; use crate::util::sort::SortType; use super::reload; @@ -15,10 +13,7 @@ pub fn set_sort(context: &mut AppContext, method: SortType) -> JoshutoResult<()> for tab in context.tab_context_mut().iter_mut() { tab.history_mut().depreciate_all_entries(); } - - reload::soft_reload(context.tab_context_ref().index, context)?; - LoadChild::load_child(context)?; - Ok(()) + refresh(context) } pub fn toggle_reverse(context: &mut AppContext) -> JoshutoResult<()> { @@ -28,7 +23,10 @@ pub fn toggle_reverse(context: &mut AppContext) -> JoshutoResult<()> { for tab in context.tab_context_mut().iter_mut() { tab.history_mut().depreciate_all_entries(); } + refresh(context) +} + +fn refresh(context: &mut AppContext) -> JoshutoResult<()> { reload::soft_reload(context.tab_context_ref().index, context)?; - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/tab_ops.rs b/src/commands/tab_ops.rs index f777df4..d3883af 100644 --- a/src/commands/tab_ops.rs +++ b/src/commands/tab_ops.rs @@ -4,7 +4,6 @@ use crate::context::AppContext; use crate::error::JoshutoResult; use crate::history::DirectoryHistory; use crate::tab::{JoshutoTab, TabHomePage}; -use crate::util::load_child::LoadChild; use crate::HOME_DIR; @@ -70,7 +69,6 @@ pub fn new_tab(context: &mut AppContext) -> JoshutoResult<()> { let new_index = context.tab_context_ref().len() - 1; context.tab_context_mut().index = new_index; _tab_switch(new_index, context)?; - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/commands/touch_file.rs b/src/commands/touch_file.rs index dff1666..458aad4 100644 --- a/src/commands/touch_file.rs +++ b/src/commands/touch_file.rs @@ -1,11 +1,11 @@ +use std::fs::File; use std::path; +use std::time::SystemTime; + +use filetime::FileTime; use crate::context::AppContext; use crate::error::JoshutoResult; -use crate::util::load_child::LoadChild; -use filetime::FileTime; -use std::fs::File; -use std::time::SystemTime; fn _update_actime(file: &path::Path) -> std::io::Result<()> { let file_time = FileTime::from_system_time(SystemTime::now()); @@ -44,6 +44,5 @@ pub fn touch_file(context: &mut AppContext, arg: &str) -> JoshutoResult<()> { if let Some(curr_list) = context.tab_context_mut().curr_tab_mut().curr_list_mut() { curr_list.reload_contents(&options)?; } - LoadChild::load_child(context)?; Ok(()) } diff --git a/src/context/app_context.rs b/src/context/app_context.rs index d60e8e0..e03079a 100644 --- a/src/context/app_context.rs +++ b/src/context/app_context.rs @@ -3,7 +3,7 @@ use std::sync::mpsc; use crate::config; use crate::context::{LocalStateContext, TabContext, WorkerContext}; -use crate::util::event::{AppEvent, Events}; +use crate::event::{AppEvent, Events}; use crate::util::search::SearchPattern; pub struct AppContext { @@ -11,7 +11,7 @@ pub struct AppContext { // app config config: config::AppConfig, // event loop querying - events: Events, + pub events: Events, // context related to tabs tab_context: TabContext, // context related to local file state diff --git a/src/context/worker_context.rs b/src/context/worker_context.rs index b97df99..bd0802c 100644 --- a/src/context/worker_context.rs +++ b/src/context/worker_context.rs @@ -3,8 +3,8 @@ use std::collections::VecDeque; use std::sync::mpsc; use std::thread; +use crate::event::AppEvent; use crate::io::{IoWorkerObserver, IoWorkerProgress, IoWorkerThread}; -use crate::util::event::AppEvent; pub struct WorkerContext { // queue of IO workers diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..da9330e --- /dev/null +++ b/src/event.rs @@ -0,0 +1,109 @@ +use std::io; +use std::path; +use std::process; +use std::sync::mpsc; +use std::thread; + +use signal_hook::consts::signal; +use signal_hook::iterator::exfiltrator::SignalOnly; +use signal_hook::iterator::SignalsInfo; + +use termion::event::Event; +use termion::input::TermRead; + +use crate::io::IoWorkerProgress; + +#[derive(Debug)] +pub enum AppEvent { + Termion(Event), + IoWorkerProgress(IoWorkerProgress), + IoWorkerResult(io::Result), + PreviewDir(io::Result), + PreviewFile(process::Output), + Signal(i32), + // Filesystem(notify::Result), +} + +#[derive(Debug, Clone, Copy)] +pub struct Config {} + +impl Default for Config { + fn default() -> Config { + Config {} + } +} + +/// A small event handler that wrap termion input and tick events. Each event +/// type is handled in its own thread and returned to a common `Receiver` +pub struct Events { + pub event_tx: mpsc::Sender, + event_rx: mpsc::Receiver, + pub input_tx: mpsc::SyncSender<()>, +} + +impl Events { + pub fn new() -> Self { + Events::with_config() + } + + pub fn with_config() -> Self { + let (input_tx, input_rx) = mpsc::sync_channel(1); + let (event_tx, event_rx) = mpsc::channel(); + + // signal thread + let event_tx2 = event_tx.clone(); + let _ = thread::spawn(move || { + let sigs = vec![signal::SIGWINCH]; + let mut signals = SignalsInfo::::new(&sigs).unwrap(); + for signal in &mut signals { + if let Err(e) = event_tx2.send(AppEvent::Signal(signal)) { + eprintln!("Signal thread send err: {:#?}", e); + return; + } + } + }); + + // input thread + let event_tx2 = event_tx.clone(); + let _ = thread::spawn(move || { + let stdin = io::stdin(); + let mut events = stdin.events(); + match events.next() { + Some(event) => match event { + Ok(event) => { + if let Err(e) = event_tx2.send(AppEvent::Termion(event)) { + eprintln!("Input thread send err: {:#?}", e); + return; + } + } + Err(_) => return, + }, + None => return, + } + + while input_rx.recv().is_ok() { + if let Some(Ok(event)) = events.next() { + if let Err(e) = event_tx2.send(AppEvent::Termion(event)) { + eprintln!("Input thread send err: {:#?}", e); + return; + } + } + } + }); + + Events { + event_tx, + event_rx, + input_tx, + } + } + + pub fn next(&self) -> Result { + let event = self.event_rx.recv()?; + Ok(event) + } + + pub fn flush(&self) { + let _ = self.input_tx.send(()); + } +} diff --git a/src/main.rs b/src/main.rs index d1a2026..446e00e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod commands; mod config; mod context; mod error; +mod event; mod fs; mod history; mod io; diff --git a/src/preview/mod.rs b/src/preview/mod.rs index 6a3e7fd..ebab23f 100644 --- a/src/preview/mod.rs +++ b/src/preview/mod.rs @@ -1,3 +1,3 @@ -pub mod preview_sh; - -pub use self::preview_sh::preview_with_script; +pub mod preview_default; +pub mod preview_dir; +pub mod preview_file; diff --git a/src/preview/preview_default.rs b/src/preview/preview_default.rs new file mode 100644 index 0000000..9601800 --- /dev/null +++ b/src/preview/preview_default.rs @@ -0,0 +1,27 @@ +use std::path; + +use crate::context::AppContext; +use crate::preview::{preview_dir, preview_file}; +use crate::ui::TuiBackend; + +pub fn load_preview_path(context: &mut AppContext, backend: &mut TuiBackend, p: path::PathBuf) { + if p.is_dir() { + preview_dir::load_preview(context, p); + } else if p.is_file() { + preview_file::preview_path_with_script(context, backend, p); + } +} + +pub fn load_preview(context: &mut AppContext, backend: &mut TuiBackend) { + let mut p: Option = 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()) + } + } + + if let Some(p) = p { + load_preview_path(context, backend, p); + } +} diff --git a/src/preview/preview_dir.rs b/src/preview/preview_dir.rs new file mode 100644 index 0000000..bf1d151 --- /dev/null +++ b/src/preview/preview_dir.rs @@ -0,0 +1,48 @@ +use std::io; +use std::path; +use std::thread; + +use crate::context::AppContext; +use crate::event::AppEvent; +use crate::history::DirectoryHistory; + +pub fn load_preview(context: &mut AppContext, p: path::PathBuf) -> io::Result { + // get preview + 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) +} + +pub struct CursorDir {} + +impl CursorDir { + pub fn load(context: &mut AppContext) -> io::Result<()> { + let mut p: Option = 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()) + } + } + + 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), + } + } +} diff --git a/src/preview/preview_file.rs b/src/preview/preview_file.rs new file mode 100644 index 0000000..5aabb13 --- /dev/null +++ b/src/preview/preview_file.rs @@ -0,0 +1,86 @@ +use std::io; +use std::path; +use std::process::{Command, Output}; + +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 { + 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 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 }; + + // 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 { + 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(); + + 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) => preview_path_with_script(context, backend, entry.file_path().to_path_buf()), + } +} diff --git a/src/preview/preview_sh.rs b/src/preview/preview_sh.rs deleted file mode 100644 index 9d66ab4..0000000 --- a/src/preview/preview_sh.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::context::AppContext; -use crate::ui::TuiBackend; - -pub fn preview_with_script(context: &AppContext, backend: &mut TuiBackend) { - let preview_options = context.config_ref().preview_options_ref(); - if let Some(script_path) = preview_options.preview_script.as_ref() { - let file_full_path = 0; - let preview_width = 0; - let preview_height = 0; - let image_cache = 0; - let preview_image = if preview_options.preview_images { 1 } else { 0 }; - - // spawn preview process - } -} diff --git a/src/run.rs b/src/run.rs index fa02d3e..fd1a3af 100644 --- a/src/run.rs +++ b/src/run.rs @@ -3,12 +3,12 @@ use termion::event::Event; use crate::commands::{AppExecute, CommandKeybind, KeyCommand}; use crate::config::AppKeyMapping; use crate::context::AppContext; +use crate::event::AppEvent; +use crate::preview::preview_default; use crate::tab::JoshutoTab; use crate::ui; use crate::ui::views::{TuiCommandMenu, TuiView}; -use crate::util::event::AppEvent; use crate::util::input; -use crate::util::load_child::LoadChild; use crate::util::to_string::ToString; pub fn run( @@ -23,7 +23,7 @@ pub fn run( context.tab_context_mut().push_tab(tab); // trigger a preview of child - let _ = LoadChild::load_child(context); + preview_default::load_preview(context, backend); } while !context.exit { @@ -40,6 +40,7 @@ pub fn run( match event { AppEvent::Termion(Event::Mouse(event)) => { input::process_mouse(event, context, backend); + preview_default::load_preview(context, backend); } AppEvent::Termion(key) => { if !context.message_queue_ref().is_empty() { @@ -82,6 +83,7 @@ pub fn run( }, } context.flush_event(); + preview_default::load_preview(context, backend); } event => input::process_noninteractive(event, context), } diff --git a/src/ui/views/tui_command_menu.rs b/src/ui/views/tui_command_menu.rs index c1bc627..5f7bc56 100644 --- a/src/ui/views/tui_command_menu.rs +++ b/src/ui/views/tui_command_menu.rs @@ -7,10 +7,10 @@ use tui::widgets::Clear; use crate::commands::{CommandKeybind, KeyCommand}; use crate::config::AppKeyMapping; use crate::context::AppContext; +use crate::event::AppEvent; use crate::ui::views::TuiView; use crate::ui::widgets::TuiMenu; use crate::ui::TuiBackend; -use crate::util::event::AppEvent; use crate::util::input; use crate::util::to_string::ToString; diff --git a/src/ui/views/tui_textfield.rs b/src/ui/views/tui_textfield.rs index 701bf20..b664300 100644 --- a/src/ui/views/tui_textfield.rs +++ b/src/ui/views/tui_textfield.rs @@ -7,10 +7,10 @@ use tui::widgets::Clear; use unicode_width::UnicodeWidthStr; use crate::context::AppContext; +use crate::event::AppEvent; use crate::ui::views::TuiView; use crate::ui::widgets::{TuiMenu, TuiMultilineText}; use crate::ui::TuiBackend; -use crate::util::event::AppEvent; use crate::util::input; struct CompletionTracker { diff --git a/src/ui/views/tui_worker_view.rs b/src/ui/views/tui_worker_view.rs index 387b279..91388bf 100644 --- a/src/ui/views/tui_worker_view.rs +++ b/src/ui/views/tui_worker_view.rs @@ -3,9 +3,9 @@ use termion::event::{Event, Key}; use tui::layout::Rect; use crate::context::AppContext; +use crate::event::AppEvent; use crate::ui::widgets::{TuiTopBar, TuiWorker}; use crate::ui::TuiBackend; -use crate::util::event::AppEvent; use crate::util::input; pub struct TuiWorkerView {} diff --git a/src/ui/widgets/tui_dirlist_detailed.rs b/src/ui/widgets/tui_dirlist_detailed.rs index 2c0337d..08772bc 100644 --- a/src/ui/widgets/tui_dirlist_detailed.rs +++ b/src/ui/widgets/tui_dirlist_detailed.rs @@ -90,8 +90,13 @@ fn print_entry( }; let left_label_original = entry.label(); let right_label_original = format!(" {}{}", symlink_string, size_string); - let (left_label, right_label) = - factor_labels_for_entry(left_label_original, right_label_original, drawing_width); + + let (left_label, right_label) = factor_labels_for_entry( + left_label_original, + right_label_original.as_str(), + drawing_width, + ); + let right_width = right_label.width(); buf.set_stringn(x, y, left_label, drawing_width, style); buf.set_stringn( @@ -103,30 +108,35 @@ fn print_entry( ); } -fn factor_labels_for_entry( - left_label_original: &str, - right_label_original: String, +fn factor_labels_for_entry<'a>( + left_label_original: &'a str, + right_label_original: &'a str, drawing_width: usize, -) -> (String, String) { - let left_width_remainder = drawing_width as i32 - right_label_original.width() as i32; - let width_remainder = left_width_remainder as i32 - left_label_original.width() as i32; - if width_remainder >= 0 { - ( - left_label_original.to_string(), - right_label_original.to_string(), - ) +) -> (String, &'a str) { + let left_label_original_width = left_label_original.width(); + let right_label_original_width = right_label_original.width(); + + let left_width_remainder = drawing_width as i32 - right_label_original_width as i32; + let width_remainder = left_width_remainder as i32 - left_label_original_width as i32; + + if drawing_width == 0 { + ("".to_string(), "") + } else if width_remainder >= 0 { + (left_label_original.to_string(), right_label_original) } else { - if left_label_original.width() <= drawing_width { - (left_label_original.to_string(), "".to_string()) - } else if left_width_remainder < MIN_LEFT_LABEL_WIDTH { + if left_width_remainder < MIN_LEFT_LABEL_WIDTH { ( - trim_file_label(left_label_original, drawing_width), - "".to_string(), + if left_label_original.width() as i32 <= left_width_remainder { + trim_file_label(left_label_original, drawing_width) + } else { + left_label_original.to_string() + }, + "", ) } else { ( trim_file_label(left_label_original, left_width_remainder as usize), - right_label_original.to_string(), + right_label_original, ) } } @@ -151,7 +161,7 @@ pub fn trim_file_label(name: &str, drawing_width: usize) -> String { // file ext does not fit ELLIPSIS.to_string() } else if ext_width == drawing_width { - extension.to_string().replacen('.', ELLIPSIS, 1) + extension.replacen('.', ELLIPSIS, 1).to_string() } else { let stem_width = drawing_width - ext_width; let truncated_stem = stem.trunc(stem_width - 1); @@ -169,8 +179,8 @@ mod test_factor_labels { let left = "foo.ext"; let right = "right"; assert_eq!( - ("".to_string(), "".to_string()), - factor_labels_for_entry(left, right.to_string(), 0) + ("".to_string(), ""), + factor_labels_for_entry(left, right, 0) ); } @@ -179,8 +189,8 @@ mod test_factor_labels { let left = "foo.ext"; let right = "right"; assert_eq!( - (left.to_string(), right.to_string()), - factor_labels_for_entry(left, right.to_string(), 20) + (left.to_string(), right), + factor_labels_for_entry(left, right, 20) ); } @@ -189,8 +199,8 @@ mod test_factor_labels { let left = "foo.ext"; let right = "right"; assert_eq!( - (left.to_string(), right.to_string()), - factor_labels_for_entry(left, right.to_string(), 12) + (left.to_string(), right), + factor_labels_for_entry(left, right, 12) ); } @@ -200,8 +210,8 @@ mod test_factor_labels { let right = "right"; assert!(left.chars().count() as i32 == MIN_LEFT_LABEL_WIDTH); assert_eq!( - (left.to_string(), "".to_string()), - factor_labels_for_entry(left, right.to_string(), MIN_LEFT_LABEL_WIDTH as usize) + ("foobarbazfo.ext".to_string(), ""), + factor_labels_for_entry(left, right, MIN_LEFT_LABEL_WIDTH as usize) ); } @@ -211,14 +221,27 @@ mod test_factor_labels { let right = "right"; assert!(left.chars().count() as i32 > MIN_LEFT_LABEL_WIDTH + right.chars().count() as i32); assert_eq!( - ("foobarbazf….ext".to_string(), right.to_string()), + ("foobarbazf….ext".to_string(), right), factor_labels_for_entry( left, - right.to_string(), + right, MIN_LEFT_LABEL_WIDTH as usize + right.chars().count() ) ); } + + #[test] + // regression + fn file_name_which_is_smaller_or_equal_drawing_width_does_not_cause_right_label_to_be_omitted() + { + let left = "foooooobaaaaaaarbaaaaaaaaaz"; + let right = "right"; + assert!(left.chars().count() as i32 > MIN_LEFT_LABEL_WIDTH); + assert_eq!( + ("foooooobaaaaaaarbaaaa…".to_string(), right), + factor_labels_for_entry(left, right, left.chars().count()) + ); + } } #[cfg(test)] diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs index aff44e9..ec947a9 100644 --- a/src/ui/widgets/tui_prompt.rs +++ b/src/ui/widgets/tui_prompt.rs @@ -5,9 +5,9 @@ use tui::text::Span; use tui::widgets::{Clear, Paragraph, Wrap}; use crate::context::AppContext; +use crate::event::AppEvent; use crate::ui::views::TuiView; use crate::ui::TuiBackend; -use crate::util::event::AppEvent; use crate::util::input; pub struct TuiPrompt<'a> { diff --git a/src/util/event.rs b/src/util/event.rs deleted file mode 100644 index c6656ee..0000000 --- a/src/util/event.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::io; -use std::sync::mpsc; -use std::thread; - -use signal_hook::consts::signal; -use signal_hook::iterator::exfiltrator::SignalOnly; -use signal_hook::iterator::SignalsInfo; - -use termion::event::Event; -use termion::input::TermRead; - -use crate::io::IoWorkerProgress; - -#[derive(Debug)] -pub enum AppEvent { - Termion(Event), - IoWorkerProgress(IoWorkerProgress), - IoWorkerResult(io::Result), - Signal(i32), - // Filesystem(notify::Result), -} - -#[derive(Debug, Clone, Copy)] -pub struct Config {} - -impl Default for Config { - fn default() -> Config { - Config {} - } -} - -/// A small event handler that wrap termion input and tick events. Each event -/// type is handled in its own thread and returned to a common `Receiver` -pub struct Events { - pub event_tx: mpsc::Sender, - event_rx: mpsc::Receiver, - pub input_tx: mpsc::SyncSender<()>, -} - -impl Events { - pub fn new() -> Self { - Events::with_config() - } - - pub fn with_config() -> Self { - let (input_tx, input_rx) = mpsc::sync_channel(1); - let (event_tx, event_rx) = mpsc::channel(); - - // signal thread - let event_tx2 = event_tx.clone(); - let _ = thread::spawn(move || { - let sigs = vec![signal::SIGWINCH]; - let mut signals = SignalsInfo::::new(&sigs).unwrap(); - for signal in &mut signals { - if let Err(e) = event_tx2.send(AppEvent::Signal(signal)) { - eprintln!("Signal thread send err: {:#?}", e); - return; - } - } - }); - - // input thread - let event_tx2 = event_tx.clone(); - let _ = thread::spawn(move || { - let stdin = io::stdin(); - let mut events = stdin.events(); - match events.next() { - Some(event) => match event { - Ok(event) => { - if let Err(e) = event_tx2.send(AppEvent::Termion(event)) { - eprintln!("Input thread send err: {:#?}", e); - return; - } - } - Err(_) => return, - }, - None => return, - } - - while input_rx.recv().is_ok() { - if let Some(Ok(event)) = events.next() { - if let Err(e) = event_tx2.send(AppEvent::Termion(event)) { - eprintln!("Input thread send err: {:#?}", e); - return; - } - } - } - }); - - Events { - event_tx, - event_rx, - input_tx, - } - } - - pub fn next(&self) -> Result { - let event = self.event_rx.recv()?; - Ok(event) - } - - pub fn flush(&self) { - let _ = self.input_tx.send(()); - } -} diff --git a/src/util/input.rs b/src/util/input.rs index 7a6d9ad..24aff5e 100644 --- a/src/util/input.rs +++ b/src/util/input.rs @@ -4,10 +4,10 @@ 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::history::DirectoryHistory; use crate::io::{FileOp, IoWorkerProgress}; use crate::ui; -use crate::util::event::AppEvent; use crate::util::format; pub fn process_mouse(event: MouseEvent, context: &mut AppContext, backend: &mut ui::TuiBackend) { diff --git a/src/util/load_child.rs b/src/util/load_child.rs deleted file mode 100644 index 63fb1f2..0000000 --- a/src/util/load_child.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::path::PathBuf; - -use crate::context::AppContext; -use crate::history::DirectoryHistory; - -pub struct LoadChild {} - -impl LoadChild { - pub fn load_child(context: &mut AppContext) -> std::io::Result<()> { - let mut path: Option = 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]; - path = Some(entry.file_path().to_path_buf()) - } - } - - // get preview - if let Some(path) = path { - if path.is_dir() { - let options = context.config_ref().display_options_ref().clone(); - context - .tab_context_mut() - .curr_tab_mut() - .history_mut() - .create_or_soft_update(path.as_path(), &options)?; - } - } - Ok(()) - } -} diff --git a/src/util/mod.rs b/src/util/mod.rs index 53b5512..848ae31 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,10 +2,8 @@ pub mod devicons; pub mod display; -pub mod event; pub mod format; pub mod input; -pub mod load_child; pub mod name_resolution; pub mod search; pub mod select; -- cgit v1.2.3