summaryrefslogtreecommitdiffstats
path: root/src/term_manager.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/term_manager.rs')
-rw-r--r--src/term_manager.rs126
1 files changed, 76 insertions, 50 deletions
diff --git a/src/term_manager.rs b/src/term_manager.rs
index 89bb937..498f610 100644
--- a/src/term_manager.rs
+++ b/src/term_manager.rs
@@ -2,6 +2,7 @@ use std::cmp::min;
use std::path::PathBuf;
use std::sync::Arc;
+use anyhow::{Context, Result};
use log::info;
use tuikit::attr::*;
use tuikit::event::Event;
@@ -17,8 +18,8 @@ use crate::constant_strings_paths::{
};
use crate::content_window::ContentWindow;
use crate::fileinfo::{fileinfo_attr, shorten_path, FileInfo};
-use crate::fm_error::{FmError, FmResult};
use crate::mode::{InputSimple, MarkAction, Mode, Navigate, NeedConfirmation};
+use crate::mount_help::MountHelper;
use crate::preview::{Preview, TextKind, Window};
use crate::selectable_content::SelectableContent;
use crate::status::Status;
@@ -76,7 +77,7 @@ impl EventReader {
/// Returns the events as they're received. Wait indefinitely for a new one.
/// We should spend most of the application life here, doing nothing :)
- pub fn poll_event(&self) -> FmResult<Event> {
+ pub fn poll_event(&self) -> Result<Event> {
Ok(self.term.poll_event()?)
}
}
@@ -143,7 +144,7 @@ impl<'a> WinMain<'a> {
}
}
- fn preview_as_second_pane(&self, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn preview_as_second_pane(&self, canvas: &mut dyn Canvas) -> Result<()> {
let tab = &self.status.tabs[0];
let (_, height) = canvas.size()?;
self.preview(tab, &tab.preview.window_for_second_pane(height), canvas)?;
@@ -157,11 +158,11 @@ impl<'a> WinMain<'a> {
/// When a confirmation is needed we ask the user to input `'y'` or
/// something else.
/// Returns the result of the number of printed chars.
- fn first_line(&self, tab: &Tab, disk_space: &str, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn first_line(&self, tab: &Tab, disk_space: &str, canvas: &mut dyn Canvas) -> Result<()> {
draw_colored_strings(0, 0, self.create_first_row(tab, disk_space)?, canvas)
}
- fn second_line(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<usize> {
+ fn second_line(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<usize> {
match tab.mode {
Mode::Normal => {
if !status.display_full {
@@ -182,7 +183,7 @@ impl<'a> WinMain<'a> {
}
}
- fn second_line_detailed(&self, file: &FileInfo, canvas: &mut dyn Canvas) -> FmResult<usize> {
+ fn second_line_detailed(&self, file: &FileInfo, canvas: &mut dyn Canvas) -> Result<usize> {
let owner_size = file.owner.len();
let group_size = file.group.len();
let mut attr = fileinfo_attr(file, self.colors);
@@ -190,7 +191,7 @@ impl<'a> WinMain<'a> {
Ok(canvas.print_with_attr(1, 0, &file.format(owner_size, group_size)?, attr)?)
}
- fn second_line_simple(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<usize> {
+ fn second_line_simple(&self, status: &Status, canvas: &mut dyn Canvas) -> Result<usize> {
Ok(canvas.print_with_attr(
1,
0,
@@ -199,7 +200,7 @@ impl<'a> WinMain<'a> {
)?)
}
- fn normal_first_row(&self, disk_space: &str) -> FmResult<Vec<String>> {
+ fn normal_first_row(&self, disk_space: &str) -> Result<Vec<String>> {
Ok(vec![
format!("{} ", shorten_path(&self.tab.path_content.path, None)?),
format!("{} files ", self.tab.path_content.true_len()),
@@ -211,8 +212,10 @@ impl<'a> WinMain<'a> {
}
fn help_first_row() -> Vec<String> {
+ let version = std::env!("CARGO_PKG_VERSION");
vec![
HELP_FIRST_SENTENCE.to_owned(),
+ format!("Version: {version} "),
HELP_SECOND_SENTENCE.to_owned(),
]
}
@@ -240,7 +243,7 @@ impl<'a> WinMain<'a> {
}
}
- fn create_first_row(&self, tab: &Tab, disk_space: &str) -> FmResult<Vec<String>> {
+ fn create_first_row(&self, tab: &Tab, disk_space: &str) -> Result<Vec<String>> {
let first_row = match tab.mode {
Mode::Normal | Mode::Tree => self.normal_first_row(disk_space)?,
Mode::Preview => match &tab.preview {
@@ -266,7 +269,7 @@ impl<'a> WinMain<'a> {
/// We reverse the attributes of the selected one, underline the flagged files.
/// When we display a simpler version, the second line is used to display the
/// metadata of the selected file.
- fn files(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn files(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
let len = tab.path_content.content.len();
let group_size: usize;
let owner_size: usize;
@@ -302,7 +305,7 @@ impl<'a> WinMain<'a> {
Ok(())
}
- fn tree(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn tree(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
let line_number_width = 3;
let (_, height) = canvas.size()?;
@@ -324,7 +327,7 @@ impl<'a> WinMain<'a> {
row_position_in_canvas: usize,
line_number_to_print: usize,
canvas: &mut dyn Canvas,
- ) -> FmResult<usize> {
+ ) -> Result<usize> {
Ok(canvas.print_with_attr(
row_position_in_canvas,
0,
@@ -340,7 +343,7 @@ impl<'a> WinMain<'a> {
/// else the content is supposed to be text and shown as such.
/// It may fail to recognize some usual extensions, notably `.toml`.
/// It may fail to recognize small files (< 1024 bytes).
- fn preview(&self, tab: &Tab, window: &ContentWindow, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn preview(&self, tab: &Tab, window: &ContentWindow, canvas: &mut dyn Canvas) -> Result<()> {
let length = tab.preview.len();
let line_number_width = length.to_string().len();
match &tab.preview {
@@ -391,6 +394,15 @@ impl<'a> WinMain<'a> {
)?;
}
}
+ Preview::ColoredText(colored_text) => {
+ for (i, line) in colored_text.window(window.top, window.bottom, length) {
+ let row = calc_line_row(i, window);
+ let mut col = 3;
+ for (chr, attr) in skim::AnsiString::parse(line).iter() {
+ col += canvas.print_with_attr(row, col, &chr.to_string(), attr)?;
+ }
+ }
+ }
Preview::Archive(text) => {
impl_preview!(text, tab, length, canvas, line_number_width, window)
}
@@ -406,6 +418,9 @@ impl<'a> WinMain<'a> {
Preview::Diff(text) => {
impl_preview!(text, tab, length, canvas, line_number_width, window)
}
+ Preview::Iso(text) => {
+ impl_preview!(text, tab, length, canvas, line_number_width, window)
+ }
Preview::Empty => (),
}
@@ -432,6 +447,7 @@ impl<'a> Draw for WinSecondary<'a> {
}
Mode::Navigate(Navigate::Marks(_)) => self.marks(self.status, canvas),
Mode::Navigate(Navigate::ShellMenu) => self.shell_menu(self.status, canvas),
+ Mode::Navigate(Navigate::CliInfo) => self.cli_info(self.status, canvas),
Mode::NeedConfirmation(confirmed_mode) => {
self.confirmation(self.status, self.tab, confirmed_mode, canvas)
}
@@ -457,11 +473,11 @@ impl<'a> WinSecondary<'a> {
}
}
- fn first_line(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn first_line(&self, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
draw_colored_strings(0, 0, self.create_first_row(tab)?, canvas)
}
- fn create_first_row(&self, tab: &Tab) -> FmResult<Vec<String>> {
+ fn create_first_row(&self, tab: &Tab) -> Result<Vec<String>> {
let first_row = match tab.mode {
Mode::NeedConfirmation(confirmed_action) => {
vec![format!("{confirmed_action}"), " (y/n)".to_owned()]
@@ -472,7 +488,7 @@ impl<'a> WinSecondary<'a> {
Mode::Navigate(Navigate::Marks(MarkAction::New)) => {
vec!["Save mark...".to_owned()]
}
- Mode::InputSimple(InputSimple::Password(password_kind, _encrypted_action)) => {
+ Mode::InputSimple(InputSimple::Password(password_kind, _encrypted_action, _)) => {
vec![format!("{password_kind}"), tab.input.password()]
}
Mode::InputCompleted(mode) => {
@@ -482,10 +498,7 @@ impl<'a> WinSecondary<'a> {
completion_strings.push(completion.to_owned())
}
if let InputCompleted::Exec = mode {
- let selected_path = &tab
- .selected()
- .ok_or_else(|| FmError::custom("create_first_row", "can't parse path"))?
- .path;
+ let selected_path = &tab.selected().context("can't parse path")?.path;
let selected_path = format!(" {}", selected_path.display());
completion_strings.push(selected_path);
@@ -504,7 +517,7 @@ impl<'a> WinSecondary<'a> {
/// Display the possible completion items. The currently selected one is
/// reversed.
- fn completion(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn completion(&self, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
canvas.set_cursor(0, tab.input.cursor_index + Self::EDIT_BOX_OFFSET)?;
for (row, candidate) in tab.completion.proposals.iter().enumerate() {
let mut attr = Attr::default();
@@ -516,7 +529,7 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
/// Display a cursor in the top row, at a correct column.
- fn cursor(&self, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn cursor(&self, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
match tab.mode {
Mode::Normal
| Mode::Tree
@@ -529,7 +542,7 @@ impl<'a> WinSecondary<'a> {
canvas.show_cursor(true)?;
canvas.set_cursor(0, Self::SORT_CURSOR_OFFSET)?;
}
- Mode::InputSimple(InputSimple::Password(_, _)) => {
+ Mode::InputSimple(InputSimple::Password(_, _, _)) => {
canvas.show_cursor(true)?;
canvas.set_cursor(0, Self::PASSWORD_CURSOR_OFFSET + tab.input.cursor_index)?;
}
@@ -550,7 +563,7 @@ impl<'a> WinSecondary<'a> {
&self,
canvas: &mut dyn Canvas,
selectable: &impl SelectableContent<PathBuf>,
- ) -> FmResult<()> {
+ ) -> Result<()> {
canvas.print(0, 0, "Go to...")?;
for (row, path, attr) in enumerated_colored_iter!(selectable) {
let mut attr = *attr;
@@ -560,8 +573,7 @@ impl<'a> WinSecondary<'a> {
let _ = canvas.print_with_attr(
row + ContentWindow::WINDOW_MARGIN_TOP,
4,
- path.to_str()
- .ok_or_else(|| FmError::custom("display", "Unreadable filename"))?,
+ path.to_str().context("Unreadable filename")?,
attr,
);
}
@@ -572,7 +584,7 @@ impl<'a> WinSecondary<'a> {
&self,
canvas: &mut dyn Canvas,
selectable: &impl SelectableContent<String>,
- ) -> FmResult<()> {
+ ) -> Result<()> {
canvas.print(0, 0, "Action...")?;
for (row, text, attr) in enumerated_colored_iter!(selectable) {
let mut attr = *attr;
@@ -588,7 +600,7 @@ impl<'a> WinSecondary<'a> {
&self,
canvas: &mut dyn Canvas,
selectable: &impl SelectableContent<TrashInfo>,
- ) -> FmResult<()> {
+ ) -> Result<()> {
canvas.print(
1,
0,
@@ -613,7 +625,7 @@ impl<'a> WinSecondary<'a> {
&self,
canvas: &mut dyn Canvas,
selectable: &impl SelectableContent<CompressionMethod>,
- ) -> FmResult<()> {
+ ) -> Result<()> {
canvas.print_with_attr(
1,
0,
@@ -636,7 +648,7 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
- fn marks(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn marks(&self, status: &Status, canvas: &mut dyn Canvas) -> Result<()> {
canvas.print_with_attr(2, 1, "mark path", Self::ATTR_YELLOW)?;
for ((row, line), attr) in std::iter::zip(
@@ -653,7 +665,7 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
- fn shell_menu(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn shell_menu(&self, status: &Status, canvas: &mut dyn Canvas) -> Result<()> {
canvas.print_with_attr(2, 1, "pick a command", Self::ATTR_YELLOW)?;
let tab = status.selected_non_mut();
@@ -672,12 +684,26 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
- fn encrypted_devices(
- &self,
- status: &Status,
- tab: &Tab,
- canvas: &mut dyn Canvas,
- ) -> FmResult<()> {
+ fn cli_info(&self, status: &Status, canvas: &mut dyn Canvas) -> Result<()> {
+ canvas.print_with_attr(2, 1, "pick a command", Self::ATTR_YELLOW)?;
+
+ let tab = status.selected_non_mut();
+ for ((row, command), attr) in std::iter::zip(
+ status.cli_info.content.iter().enumerate(),
+ MENU_COLORS.iter().cycle(),
+ ) {
+ let mut attr = *attr;
+ if row == status.cli_info.index() {
+ attr.effect |= Effect::REVERSE;
+ }
+ let row = calc_line_row(row, &tab.window) + 2;
+
+ canvas.print_with_attr(row, 3, command, attr)?;
+ }
+ Ok(())
+ }
+
+ fn encrypted_devices(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> Result<()> {
canvas.print_with_attr(2, 3, "m: mount -- u: unmount", Self::ATTR_YELLOW)?;
for (i, device) in status.encrypted_devices.content.iter().enumerate() {
let row = calc_line_row(i, &tab.window) + 2;
@@ -708,7 +734,7 @@ impl<'a> WinSecondary<'a> {
tab: &Tab,
confirmed_mode: NeedConfirmation,
canvas: &mut dyn Canvas,
- ) -> FmResult<()> {
+ ) -> Result<()> {
info!("confirmed action: {:?}", confirmed_mode);
match confirmed_mode {
NeedConfirmation::EmptyTrash => {
@@ -726,8 +752,7 @@ impl<'a> WinSecondary<'a> {
canvas.print_with_attr(
row + ContentWindow::WINDOW_MARGIN_TOP + 2,
4,
- path.to_str()
- .ok_or_else(|| FmError::custom("display", "Unreadable filename"))?,
+ path.to_str().context("Unreadable filename")?,
Attr::default(),
)?;
}
@@ -774,11 +799,11 @@ impl Display {
/// Used to force a display of the cursor before leaving the application.
/// Most of the times we don't need a cursor and it's hidden. We have to
/// do it unless the shell won't display a cursor anymore.
- pub fn show_cursor(&self) -> FmResult<()> {
+ pub fn show_cursor(&self) -> Result<()> {
Ok(self.term.show_cursor(true)?)
}
- fn hide_cursor(&self) -> FmResult<()> {
+ fn hide_cursor(&self) -> Result<()> {
self.term.set_cursor(0, 0)?;
Ok(self.term.show_cursor(false)?)
}
@@ -800,7 +825,7 @@ impl Display {
/// The preview in preview mode.
/// Displays one pane or two panes, depending of the width and current
/// status of the application.
- pub fn display_all(&mut self, status: &Status, colors: &Colors) -> FmResult<()> {
+ pub fn display_all(&mut self, status: &Status, colors: &Colors) -> Result<()> {
self.hide_cursor()?;
self.term.clear()?;
@@ -815,14 +840,15 @@ impl Display {
Ok(self.term.present()?)
}
- pub fn force_clear(&mut self) -> FmResult<()> {
+ /// Hide the curose, clear the terminal and present.
+ pub fn force_clear(&mut self) -> Result<()> {
self.hide_cursor()?;
self.term.clear()?;
self.term.present()?;
Ok(())
}
- fn size_for_second_window(&self, tab: &Tab) -> FmResult<usize> {
+ fn size_for_second_window(&self, tab: &Tab) -> Result<usize> {
if tab.need_second_window() {
Ok(self.height()? / 2)
} else {
@@ -836,7 +862,7 @@ impl Display {
win_secondary: &'a WinSecondary,
border: Attr,
size: usize,
- ) -> FmResult<VSplit<'a>> {
+ ) -> Result<VSplit<'a>> {
Ok(VSplit::default()
.split(
Win::new(win_main)
@@ -868,7 +894,7 @@ impl Display {
disk_space_tab_0: &str,
disk_space_tab_1: &str,
colors: &Colors,
- ) -> FmResult<()> {
+ ) -> Result<()> {
let (width, _) = self.term.term_size()?;
let win_main_left = WinMain::new(status, 0, disk_space_tab_0, colors, 0, false);
let win_main_right = WinMain::new(status, 1, disk_space_tab_1, colors, width / 2, true);
@@ -898,7 +924,7 @@ impl Display {
status: &Status,
disk_space_tab_0: &str,
colors: &Colors,
- ) -> FmResult<()> {
+ ) -> Result<()> {
let win_main_left = WinMain::new(status, 0, disk_space_tab_0, colors, 0, false);
let win_second_left = WinSecondary::new(status, 0);
let percent_left = self.size_for_second_window(&status.tabs[0])?;
@@ -912,7 +938,7 @@ impl Display {
}
/// Reads and returns the `tuikit::term::Term` height.
- pub fn height(&self) -> FmResult<usize> {
+ pub fn height(&self) -> Result<usize> {
let (_, height) = self.term.term_size()?;
Ok(height)
}
@@ -934,7 +960,7 @@ fn draw_colored_strings(
offset: usize,
strings: Vec<String>,
canvas: &mut dyn Canvas,
-) -> FmResult<()> {
+) -> Result<()> {
let mut col = 0;
for (text, attr) in std::iter::zip(strings.iter(), FIRST_LINE_COLORS.iter().cycle()) {
col += canvas.print_with_attr(row, offset + col, text, *attr)?;