summaryrefslogtreecommitdiffstats
path: root/src/commands/custom_search.rs
blob: a9d4405883144c43d4af717f7c047b5890db709e (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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use super::change_directory::change_directory;
use super::sub_process::current_filenames;
use crate::commands::cursor_move;
use crate::context::AppContext;
use crate::error::{AppError, AppErrorKind, AppResult};
use crate::ui::AppBackend;
use shell_words::split;
use std::process::{Command, Stdio};

pub fn custom_search(
    context: &mut AppContext,
    backend: &mut AppBackend,
    words: &[String],
    interactive: bool,
) -> AppResult {
    let custom_command = context
        .config_ref()
        .custom_commands
        .as_slice()
        .iter()
        .find(|x| x.name == words[0])
        .ok_or(AppError::new(
            AppErrorKind::InvalidParameters,
            "No custom command with given name".into(),
        ))?
        .command
        .clone();

    let current_filenames = current_filenames(context);

    let text = custom_command.replace("%s", &current_filenames.join(" "));
    let text = text.replace(
        "%text",
        &words
            .iter()
            .skip(1)
            .cloned()
            .collect::<Vec<String>>()
            .join(" "),
    );
    let mut command_with_args: Vec<String> = split(&text).map_err(|_| {
        AppError::new(
            AppErrorKind::InvalidParameters,
            "Command cannot be splitted".into(),
        )
    })?;

    let mut cmd = Command::new(command_with_args.remove(0));
    command_with_args.into_iter().for_each(|x| {
        cmd.arg(x);
    });

    let cmd_result = if interactive {
        backend.terminal_drop();
        let cmd_result = cmd
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?
            .wait_with_output()?;
        backend.terminal_restore(context.config_ref().mouse_support)?;
        cmd_result
    } else {
        cmd.output()?
    };

    if cmd_result.status.success() {
        let returned_text = std::str::from_utf8(&cmd_result.stdout)
            .map_err(|_| {
                AppError::new(
                    AppErrorKind::ParseError,
                    "Could not get command result as utf8".into(),
                )
            })?
            .trim_end();

        let path = std::path::Path::new(returned_text);
        change_directory(
            context,
            path.parent().ok_or(AppError::new(
                AppErrorKind::ParseError,
                "Could not get parent directory".into(),
            ))?,
        )?;

        if let Some(current_dir_items) = context.tab_context_ref().curr_tab_ref().curr_list_ref() {
            let position = current_dir_items
                .iter()
                .enumerate()
                .find(|x| x.1.file_name() == path.file_name().unwrap_or_default())
                .map(|x| x.0)
                .unwrap_or_default();

            cursor_move::cursor_move(context, position);
        }

        Ok(())
    } else {
        let returned_text = std::str::from_utf8(&cmd_result.stderr).map_err(|_| {
            AppError::new(
                AppErrorKind::ParseError,
                "Could not get command result as utf8".into(),
            )
        })?;

        Err(AppError::new(
            AppErrorKind::ParseError,
            format!("Command failed: {}", returned_text),
        ))
    }
}