summaryrefslogtreecommitdiffstats
path: root/src/cli_info.rs
blob: 91544fd50a34815b482c2d9da2c0b9e9d3365046 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use std::process::{Command, Stdio};

use anyhow::Result;
use log::info;

use crate::constant_strings_paths::CLI_INFO_COMMANDS;
use crate::impl_selectable_content;
use crate::log_line;
use crate::utils::is_program_in_path;

/// Holds the command line commands we can run and display
/// without leaving FM.
/// Those are non interactive commands displaying some info about the current
/// file tree or setup.
#[derive(Clone)]
pub struct CliInfo {
    pub content: Vec<&'static str>,
    commands: Vec<Vec<&'static str>>,
    index: usize,
}

impl Default for CliInfo {
    fn default() -> Self {
        let index = 0;
        let commands: Vec<Vec<&str>> = CLI_INFO_COMMANDS
            .iter()
            .map(|command| command.split(' ').collect::<Vec<_>>())
            .filter(|args| is_program_in_path(args[0]))
            .collect();

        let content: Vec<&str> = commands.iter().map(|args| args[0]).collect();

        Self {
            content,
            index,
            commands,
        }
    }
}

impl CliInfo {
    /// 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();
        info!("execute. {args:?}");
        log_line!("Executed {args:?}");
        let child = Command::new(args[0])
            .args(&args[1..])
            .env("CLICOLOR_FORCE", "1")
            .env("COLORTERM", "ansi")
            .stdin(Stdio::null())
            .stdout(Stdio::piped())
            .stderr(Stdio::null())
            .spawn()?;
        let command_output = child.wait_with_output()?;
        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)
    }
}

type StaticStr = &'static str;
impl_selectable_content!(StaticStr, CliInfo);