summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorqkzk <qu3nt1n@gmail.com>2023-12-03 18:22:46 +0100
committerqkzk <qu3nt1n@gmail.com>2023-12-03 18:22:46 +0100
commitd4b5e46118154f80daf178d07f873b6a43ed01a1 (patch)
tree37ede46c7fe745c6cf32ca8a56686945e44ae1d9
parent1d0c6555437a2a1eb90902520616d4ee3f75b780 (diff)
WIP merge specific commands into cli info
-rw-r--r--development.md6
-rw-r--r--src/common/constant_strings_paths.rs13
-rw-r--r--src/io/display.rs15
-rw-r--r--src/modes/edit/cli_menu.rs106
-rw-r--r--src/modes/edit/leave_mode.rs2
5 files changed, 103 insertions, 39 deletions
diff --git a/development.md b/development.md
index 4dd7dd9..053d44f 100644
--- a/development.md
+++ b/development.md
@@ -675,9 +675,13 @@ New view: Tree ! Toggle with 't', fold with 'z'. Navigate normally.
- [x] use rc instead of owned types in fileinfo
- [x] renamed path_content to Directory
- [x] renamed Display::Normal to Display::Directory
-- [ ] WIP: event_dispatch refactor
+- [x] event_dispatch refactor
- [ ] refactor file opening. It's a mess - WIP
- [ ] opening a text file should try to open in current neovim (???)
+- [ ] merge specific commands & cli_info
+ - [x] merge
+ - [ ] remove specific commands
+ - [ ] ensure diff only use first 2 files (???)
## TODO
diff --git a/src/common/constant_strings_paths.rs b/src/common/constant_strings_paths.rs
index 945cc0f..2091583 100644
--- a/src/common/constant_strings_paths.rs
+++ b/src/common/constant_strings_paths.rs
@@ -168,8 +168,17 @@ pub const RENAME_LINES: [&str; 3] = [
];
pub const TRASH_CONFIRM_LINE: &str = "Enter: restore the selected file -- x: delete permanently";
/// Executable commands whose output is a text to be displayed in terminal
-pub const CLI_INFO_COMMANDS: [&str; 4] =
- ["duf", "inxi -S -I -D -i -J -M --color", "neofetch", "lsusb"];
+pub const CLI_INFO: [(&str, &str); 9] = [
+ ("drag and drop", "dragon-drop %s"),
+ ("set wallpaper", "nitrogen --set-zoom-fill --save %s"),
+ ("man page ", "man %s"),
+ ("space used ", "duf"),
+ ("system info ", "inxi -S -I -D -i -J -M --color"),
+ ("system info ", "neofetch"),
+ ("list usb ", "lsusb"),
+ ("media tags ", "mediainfo %s"),
+ ("diff 2 files ", "diff %f"),
+];
/// Wallpaper executable
pub const NITROGEN: &str = "nitrogen";
/// Mediainfo (used to preview media files) executable
diff --git a/src/io/display.rs b/src/io/display.rs
index be3fd2f..c07a4d7 100644
--- a/src/io/display.rs
+++ b/src/io/display.rs
@@ -912,9 +912,20 @@ impl<'a> WinSecondary<'a> {
canvas.print_with_attr(2, 1, "pick a command", Self::ATTR_YELLOW)?;
let content = &self.status.menu.cli_applications.content;
- for (row, command, attr) in enumerated_colored_iter!(content) {
+ for (row, cli_command, attr) in enumerated_colored_iter!(content) {
let attr = self.status.menu.cli_applications.attr(row, attr);
- Self::draw_content_line(canvas, row + 2, command, attr)?;
+ let col = canvas.print_with_attr(
+ row + 2 + ContentWindow::WINDOW_MARGIN_TOP,
+ 4,
+ cli_command.desc,
+ attr,
+ )?;
+ canvas.print_with_attr(
+ row + 2 + ContentWindow::WINDOW_MARGIN_TOP,
+ 8 + col,
+ cli_command.executable,
+ attr,
+ )?;
}
Ok(())
}
diff --git a/src/modes/edit/cli_menu.rs b/src/modes/edit/cli_menu.rs
index dee7f57..435ecdc 100644
--- a/src/modes/edit/cli_menu.rs
+++ b/src/modes/edit/cli_menu.rs
@@ -1,11 +1,75 @@
use anyhow::Result;
+use crate::app::Status;
use crate::common::is_program_in_path;
-use crate::common::CLI_INFO_COMMANDS;
+use crate::common::CLI_INFO;
use crate::impl_selectable_content;
use crate::io::execute_with_ansi_colors;
use crate::log_info;
use crate::log_line;
+use crate::modes::ShellCommandParser;
+
+/// A command line command.
+/// It's constructed from a line in [`crate::common::CLI_INFO`].
+/// Each command has a short description, a name (first word of second element)
+/// and a list of parsable parameters.
+/// See [`crate::modes::ShellCommandParser`] for a description of accetable tokens.
+///
+/// Only commands which are in `$PATH` at runtime are built from `Self::new(...)`,
+/// Commands which aren't accessible return `None`
+///
+/// Those commands should output a string (therefore be command line).
+/// No interaction with the user is possible.
+#[derive(Clone)]
+pub struct CliCommand {
+ /// The executable itself like `ls`
+ pub executable: &'static str,
+ /// The full command with parsable arguments like %s
+ parsable_command: &'static str,
+ /// A single line description of the command
+ pub desc: &'static str,
+}
+
+impl CliCommand {
+ fn new(desc_command: (&'static str, &'static str)) -> Option<Self> {
+ let desc = desc_command.0;
+ let parsable_command = desc_command.1;
+ let args = parsable_command.split(' ').collect::<Vec<_>>();
+ let Some(executable) = args.get(0) else {
+ return None;
+ };
+ if is_program_in_path(*executable) {
+ Some(Self {
+ executable,
+ parsable_command,
+ desc,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Run its parsable command and capture its output.
+ /// Some environement variables are first set to ensure the colored output.
+ /// Long running commands may freeze the display.
+ fn execute(&self, status: &Status) -> Result<String> {
+ let args = ShellCommandParser::new(self.parsable_command).compute(status)?;
+ log_info!("execute. {args:?}");
+ log_line!("Executed {args:?}");
+
+ let params: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
+ let command_output = execute_with_ansi_colors(&params)?;
+ let text_output = String::from_utf8(command_output.stdout)?;
+ if command_output.status.success() {
+ log_info!(
+ "Command {a} exited with error code {e}",
+ a = args[0],
+ e = command_output.status
+ );
+ };
+ Ok(text_output)
+ }
+}
/// Holds the command line commands we can run and display
/// without leaving FM.
@@ -13,27 +77,19 @@ use crate::log_line;
/// file tree or setup.
#[derive(Clone)]
pub struct CliApplications {
- pub content: Vec<&'static str>,
- commands: Vec<Vec<&'static str>>,
+ pub content: Vec<CliCommand>,
index: usize,
}
impl Default for CliApplications {
fn default() -> Self {
let index = 0;
- let commands: Vec<Vec<&str>> = CLI_INFO_COMMANDS
+ let content = CLI_INFO
.iter()
- .map(|command| command.split(' ').collect::<Vec<_>>())
- .filter(|args| is_program_in_path(args[0]))
+ .map(|line| CliCommand::new(*line))
+ .map(|opt_command| opt_command.unwrap())
.collect();
-
- let content: Vec<&str> = commands.iter().map(|args| args[0]).collect();
-
- Self {
- content,
- index,
- commands,
- }
+ Self { content, index }
}
}
@@ -41,25 +97,9 @@ impl CliApplications {
/// Run the selected command and capture its output.
/// Some environement variables are first set to ensure the colored output.
/// Long running commands may freeze the display.
- pub fn execute(&self) -> Result<String> {
- let args = self.commands[self.index].clone();
- log_info!("execute. {args:?}");
- log_line!("Executed {args:?}");
- let command_output = execute_with_ansi_colors(&args)?;
- let text_output = {
- if command_output.status.success() {
- String::from_utf8(command_output.stdout)?
- } else {
- format!(
- "Command {a} exited with error code {e}",
- a = args[0],
- e = command_output.status
- )
- }
- };
- Ok(text_output)
+ pub fn execute(&self, status: &Status) -> Result<String> {
+ self.content[self.index].execute(status)
}
}
-type StaticStr = &'static str;
-impl_selectable_content!(StaticStr, CliApplications);
+impl_selectable_content!(CliCommand, CliApplications);
diff --git a/src/modes/edit/leave_mode.rs b/src/modes/edit/leave_mode.rs
index a97e4bf..0321453 100644
--- a/src/modes/edit/leave_mode.rs
+++ b/src/modes/edit/leave_mode.rs
@@ -145,7 +145,7 @@ impl LeaveMode {
}
pub fn cli_info(status: &mut Status) -> Result<()> {
- let output = status.menu.cli_applications.execute()?;
+ let output = status.menu.cli_applications.execute(status)?;
log_info!("output\n{output}");
status.current_tab_mut().reset_edit_mode();
status.current_tab_mut().set_display_mode(Display::Preview);