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.rs143
1 files changed, 116 insertions, 27 deletions
diff --git a/src/term_manager.rs b/src/term_manager.rs
index 5fb88ed..89bb937 100644
--- a/src/term_manager.rs
+++ b/src/term_manager.rs
@@ -8,13 +8,15 @@ use tuikit::event::Event;
use tuikit::prelude::*;
use tuikit::term::Term;
+use crate::completion::InputCompleted;
use crate::compress::CompressionMethod;
use crate::config::Colors;
use crate::constant_strings_paths::{
- FILTER_PRESENTATION, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE,
+ FILTER_PRESENTATION, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE, LOG_FIRST_SENTENCE,
+ LOG_SECOND_SENTENCE,
};
use crate::content_window::ContentWindow;
-use crate::fileinfo::{fileinfo_attr, FileInfo};
+use crate::fileinfo::{fileinfo_attr, shorten_path, FileInfo};
use crate::fm_error::{FmError, FmResult};
use crate::mode::{InputSimple, MarkAction, Mode, Navigate, NeedConfirmation};
use crate::preview::{Preview, TextKind, Window};
@@ -23,6 +25,13 @@ use crate::status::Status;
use crate::tab::Tab;
use crate::trash::TrashInfo;
+macro_rules! enumerated_colored_iter {
+ ($t:ident) => {
+ std::iter::zip($t.content().iter().enumerate(), MENU_COLORS.iter().cycle())
+ .map(|((a, b), c)| (a, b, c))
+ };
+}
+
/// At least 120 chars width to display 2 tabs.
pub const MIN_WIDTH_FOR_DUAL_PANE: usize = 120;
@@ -35,6 +44,19 @@ const FIRST_LINE_COLORS: [Attr; 6] = [
color_to_attr(Color::Rgb(230, 189, 87)),
];
+const MENU_COLORS: [Attr; 10] = [
+ color_to_attr(Color::Rgb(236, 250, 250)),
+ color_to_attr(Color::Rgb(221, 242, 209)),
+ color_to_attr(Color::Rgb(205, 235, 197)),
+ color_to_attr(Color::Rgb(190, 227, 186)),
+ color_to_attr(Color::Rgb(174, 220, 174)),
+ color_to_attr(Color::Rgb(159, 212, 163)),
+ color_to_attr(Color::Rgb(174, 220, 174)),
+ color_to_attr(Color::Rgb(190, 227, 186)),
+ color_to_attr(Color::Rgb(205, 235, 197)),
+ color_to_attr(Color::Rgb(221, 242, 209)),
+];
+
const ATTR_YELLOW_BOLD: Attr = Attr {
fg: Color::YELLOW,
bg: Color::Default,
@@ -179,7 +201,7 @@ impl<'a> WinMain<'a> {
fn normal_first_row(&self, disk_space: &str) -> FmResult<Vec<String>> {
Ok(vec![
- format!("{} ", self.tab.path_content.path.display()),
+ format!("{} ", shorten_path(&self.tab.path_content.path, None)?),
format!("{} files ", self.tab.path_content.true_len()),
format!("{} ", self.tab.path_content.used_space()),
format!("Avail: {disk_space} "),
@@ -195,6 +217,13 @@ impl<'a> WinMain<'a> {
]
}
+ fn log_first_row() -> Vec<String> {
+ vec![
+ LOG_FIRST_SENTENCE.to_owned(),
+ LOG_SECOND_SENTENCE.to_owned(),
+ ]
+ }
+
fn default_preview_first_line(&self, tab: &Tab) -> Vec<String> {
match tab.path_content.selected() {
Some(fileinfo) => {
@@ -215,13 +244,11 @@ impl<'a> WinMain<'a> {
let first_row = match tab.mode {
Mode::Normal | Mode::Tree => self.normal_first_row(disk_space)?,
Mode::Preview => match &tab.preview {
- Preview::Text(text_content) => {
- if matches!(text_content.kind, TextKind::HELP) {
- Self::help_first_row()
- } else {
- self.default_preview_first_line(tab)
- }
- }
+ Preview::Text(text_content) => match text_content.kind {
+ TextKind::HELP => Self::help_first_row(),
+ TextKind::LOG => Self::log_first_row(),
+ _ => self.default_preview_first_line(tab),
+ },
_ => self.default_preview_first_line(tab),
},
_ => match self.tab.previous_mode {
@@ -376,6 +403,9 @@ impl<'a> WinMain<'a> {
Preview::Text(text) => {
impl_preview!(text, tab, length, canvas, line_number_width, window)
}
+ Preview::Diff(text) => {
+ impl_preview!(text, tab, length, canvas, line_number_width, window)
+ }
Preview::Empty => (),
}
@@ -396,10 +426,12 @@ impl<'a> Draw for WinSecondary<'a> {
Mode::Navigate(Navigate::Shortcut) => self.destination(canvas, &self.tab.shortcut),
Mode::Navigate(Navigate::Trash) => self.trash(canvas, &self.status.trash),
Mode::Navigate(Navigate::Compress) => self.compress(canvas, &self.status.compression),
+ Mode::Navigate(Navigate::Bulk) => self.bulk(canvas, &self.status.bulk),
Mode::Navigate(Navigate::EncryptedDrive) => {
self.encrypted_devices(self.status, self.tab, canvas)
}
- Mode::Navigate(Navigate::Marks(_)) => self.marks(self.status, self.tab, canvas),
+ Mode::Navigate(Navigate::Marks(_)) => self.marks(self.status, canvas),
+ Mode::Navigate(Navigate::ShellMenu) => self.shell_menu(self.status, canvas),
Mode::NeedConfirmation(confirmed_mode) => {
self.confirmation(self.status, self.tab, confirmed_mode, canvas)
}
@@ -432,7 +464,7 @@ impl<'a> WinSecondary<'a> {
fn create_first_row(&self, tab: &Tab) -> FmResult<Vec<String>> {
let first_row = match tab.mode {
Mode::NeedConfirmation(confirmed_action) => {
- vec![format!("{confirmed_action} (y/n)")]
+ vec![format!("{confirmed_action}"), " (y/n)".to_owned()]
}
Mode::Navigate(Navigate::Marks(MarkAction::Jump)) => {
vec!["Jump to...".to_owned()]
@@ -443,12 +475,21 @@ impl<'a> WinSecondary<'a> {
Mode::InputSimple(InputSimple::Password(password_kind, _encrypted_action)) => {
vec![format!("{password_kind}"), tab.input.password()]
}
- Mode::InputCompleted(_) => {
+ Mode::InputCompleted(mode) => {
let mut completion_strings = vec![format!("{}", &tab.mode), tab.input.string()];
if let Some(completion) = tab.completion.complete_input_string(&tab.input.string())
{
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 = format!(" {}", selected_path.display());
+
+ completion_strings.push(selected_path);
+ }
completion_strings
}
_ => {
@@ -511,8 +552,8 @@ impl<'a> WinSecondary<'a> {
selectable: &impl SelectableContent<PathBuf>,
) -> FmResult<()> {
canvas.print(0, 0, "Go to...")?;
- for (row, path) in selectable.content().iter().enumerate() {
- let mut attr = Attr::default();
+ for (row, path, attr) in enumerated_colored_iter!(selectable) {
+ let mut attr = *attr;
if row == selectable.index() {
attr.effect |= Effect::REVERSE;
}
@@ -527,18 +568,37 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
+ fn bulk(
+ &self,
+ canvas: &mut dyn Canvas,
+ selectable: &impl SelectableContent<String>,
+ ) -> FmResult<()> {
+ canvas.print(0, 0, "Action...")?;
+ for (row, text, attr) in enumerated_colored_iter!(selectable) {
+ let mut attr = *attr;
+ if row == selectable.index() {
+ attr.effect |= Effect::REVERSE;
+ }
+ let _ = canvas.print_with_attr(row + ContentWindow::WINDOW_MARGIN_TOP, 4, text, attr);
+ }
+ Ok(())
+ }
+
fn trash(
&self,
canvas: &mut dyn Canvas,
selectable: &impl SelectableContent<TrashInfo>,
) -> FmResult<()> {
- canvas.print(1, 0, "Restore the selected file")?;
- for (row, trashinfo) in selectable.content().iter().enumerate() {
- let mut attr = Attr::default();
+ canvas.print(
+ 1,
+ 0,
+ "Enter: restore the selected file - x: delete permanently",
+ )?;
+ for (row, trashinfo, attr) in enumerated_colored_iter!(selectable) {
+ let mut attr = *attr;
if row == selectable.index() {
attr.effect |= Effect::REVERSE;
}
-
let _ = canvas.print_with_attr(
row + ContentWindow::WINDOW_MARGIN_TOP,
4,
@@ -560,8 +620,8 @@ impl<'a> WinSecondary<'a> {
"Archive and compress the flagged files. Pick a compression algorithm.",
Self::ATTR_YELLOW,
)?;
- for (row, compression_method) in selectable.content().iter().enumerate() {
- let mut attr = Attr::default();
+ for (row, compression_method, attr) in enumerated_colored_iter!(selectable) {
+ let mut attr = *attr;
if row == selectable.index() {
attr.effect |= Effect::REVERSE;
}
@@ -576,16 +636,38 @@ impl<'a> WinSecondary<'a> {
Ok(())
}
- fn marks(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> {
+ fn marks(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> {
canvas.print_with_attr(2, 1, "mark path", Self::ATTR_YELLOW)?;
- for (i, line) in status.marks.as_strings().iter().enumerate() {
- let row = calc_line_row(i, &tab.window) + 2;
- let mut attr = Attr::default();
- if i == status.marks.index() {
+ for ((row, line), attr) in std::iter::zip(
+ status.marks.as_strings().iter().enumerate(),
+ MENU_COLORS.iter().cycle(),
+ ) {
+ let mut attr = *attr;
+ if row == status.marks.index() {
attr.effect |= Effect::REVERSE;
}
- canvas.print_with_attr(row, 3, line, attr)?;
+
+ canvas.print_with_attr(row + 4, 3, line, attr)?;
+ }
+ Ok(())
+ }
+
+ fn shell_menu(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> {
+ 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.shell_menu.content.iter().enumerate(),
+ MENU_COLORS.iter().cycle(),
+ ) {
+ let mut attr = *attr;
+ if row == status.shell_menu.index() {
+ attr.effect |= Effect::REVERSE;
+ }
+ let row = calc_line_row(row, &tab.window) + 2;
+
+ canvas.print_with_attr(row, 3, command, attr)?;
}
Ok(())
}
@@ -733,6 +815,13 @@ impl Display {
Ok(self.term.present()?)
}
+ pub fn force_clear(&mut self) -> FmResult<()> {
+ self.hide_cursor()?;
+ self.term.clear()?;
+ self.term.present()?;
+ Ok(())
+ }
+
fn size_for_second_window(&self, tab: &Tab) -> FmResult<usize> {
if tab.need_second_window() {
Ok(self.height()? / 2)