use crate::error::AppResult;
use crate::types::state::AppState;
use crate::ui::AppBackend;
use std::path::Path;
use std::process::{Command, Stdio};
use super::reload;
#[derive(Debug, Clone)]
pub enum SubprocessCallMode {
Interactive,
Spawn,
Capture,
}
pub fn current_files(app_state: &AppState) -> Vec<(&str, &Path)> {
let mut result = Vec::new();
if let Some(curr_list) = app_state
.state
.tab_state_ref()
.curr_tab_ref()
.curr_list_ref()
{
let mut i = 0;
curr_list.iter_selected().for_each(|entry| {
result.push((entry.file_name(), entry.file_path()));
i += 1;
});
if i == 0 {
if let Some(entry) = curr_list.curr_entry_ref() {
result.push((entry.file_name(), entry.file_path()));
}
}
}
result
}
fn current_dir(app_state: &AppState) -> &Path {
app_state.state.tab_state_ref().curr_tab_ref().get_cwd()
}
fn execute_sub_process(
app_state: &mut AppState,
words: &[String],
mode: SubprocessCallMode,
) -> std::io::Result<()> {
let current_files = current_files(app_state);
let command_base = if current_files.len() == 1 {
let (file_name, file_path) = current_files[0];
words[0]
.replace("%s", file_name)
.replace("%p", &file_path.to_string_lossy())
} else {
words[0].clone()
};
let mut command = Command::new(command_base);
for word in words.iter().skip(1) {
match word.as_str() {
"%s" => {
for (file_name, _) in ¤t_files {
command.arg(file_name);
}
}
"%p" => {
for (_, file_path) in ¤t_files {
command.arg(file_path);
}
}
"%d" => {
command.arg(current_dir(app_state));
}
s => {
command.arg(s);
}
};
}
match mode {
SubprocessCallMode::Interactive => {
let status = command.status();
match status {
Ok(status) => {
if status.code() == Some(0) {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Command failed with {}", status),
))
}
}
Err(err) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Shell execution failed: {}", err),
)),
}
}
SubprocessCallMode::Spawn => {
command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
Ok(())
}
SubprocessCallMode::Capture => {
let output = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()?;
if output.status.code() == Some(0) {
app_state.state.last_stdout =
Some(String::from_utf8_lossy(&output.stdout).to_string());
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Command failed with {}", output.status),
))
}
}
}
}
pub fn sub_process(
app_state: &mut AppState,
backend: &mut AppBackend,
words: &[String],
mode: SubprocessCallMode,
) -> AppResult {
match mode {
SubprocessCallMode::Interactive => {
backend.terminal_drop();
let res = execute_sub_process(app_state, words, mode);
backend.terminal_restore()?;
let _ = reload::soft_reload_curr_tab(app_state);
res?;
app_state
.state
.message_queue_mut()
.push_info(format!("Finished: {}", words.join(" ")));
}
SubprocessCallMode::Spawn => {
execute_sub_process(app_state, words, mode)?;
app_state
.state
.message_queue_mut()
.push_info(format!("Spawned: {}", words.join(" ")));
}
SubprocessCallMode::Capture => {
execute_sub_process(app_state, words, mode)?;
let _ = reload::soft_reload_curr_tab(app_state);
}
};
Ok(())
}