mirror of https://github.com/bobwen-dev/hunter
start stuff in the background
This commit is contained in:
parent
2ca81c123c
commit
e4a2749ee0
|
@ -273,6 +273,25 @@ impl FileBrowser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open_bg(&mut self) -> HResult<()> {
|
||||
let cwd = self.cwd()?;
|
||||
let file = self.selected_file()?;
|
||||
|
||||
let cmd = crate::proclist::Cmd {
|
||||
cmd: OsString::from(file.strip_prefix(&cwd)),
|
||||
short_cmd: None,
|
||||
args: None,
|
||||
cwd: cwd.clone(),
|
||||
cwd_files: None,
|
||||
tab_files: None,
|
||||
tab_paths: None
|
||||
};
|
||||
|
||||
self.proc_view.lock()?.run_proc_raw(cmd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main_widget_goto(&mut self, dir: &File) -> HResult<()> {
|
||||
match dir.is_readable() {
|
||||
Ok(true) => {},
|
||||
|
@ -665,58 +684,28 @@ impl FileBrowser {
|
|||
fn exec_cmd(&mut self,
|
||||
tab_dirs: Vec<File>,
|
||||
tab_files: Vec<Vec<File>>) -> HResult<()> {
|
||||
let cwd = self.cwd()?;
|
||||
let filename = self.selected_file()?.path.quoted_file_name()?;
|
||||
|
||||
let cwd = self.cwd()?.clone();
|
||||
let selected_file = self.selected_file()?;
|
||||
let selected_files = self.selected_files()?;
|
||||
|
||||
let files = selected_files.iter()
|
||||
.map(|f| f.path())
|
||||
.collect::<Vec<PathBuf>>();
|
||||
let cmd = self.minibuffer("exec")?.trim_start().to_string() + " ";
|
||||
|
||||
let cmd = self.minibuffer("exec")?.trim_start().to_string();
|
||||
let cwd_files = if selected_files.len() == 0 {
|
||||
vec![selected_file]
|
||||
} else { selected_files };
|
||||
|
||||
let cmd = OsString::from(cmd);
|
||||
let space = OsString::from(" ");
|
||||
|
||||
let mut cmd = if files.len() == 0 {
|
||||
cmd.replace(&OsString::from("$s"), &filename)
|
||||
} else {
|
||||
let args = files.iter()
|
||||
.fold(OsString::new(), |mut args, file| {
|
||||
if let Some(name) = file.quoted_file_name() {
|
||||
args.push(name);
|
||||
args.push(space.clone());
|
||||
}
|
||||
args
|
||||
});
|
||||
let args = args.trim_last_space();
|
||||
|
||||
cmd.replace(&OsString::from("$s"), &args)
|
||||
let cmd = crate::proclist::Cmd {
|
||||
cmd: OsString::from(cmd),
|
||||
short_cmd: None,
|
||||
args: None,
|
||||
cwd: cwd,
|
||||
cwd_files: Some(cwd_files),
|
||||
tab_files: Some(tab_files),
|
||||
tab_paths: Some(tab_dirs)
|
||||
};
|
||||
|
||||
for (i, tab_dir) in tab_dirs.iter().enumerate() {
|
||||
if let Some(tab_files) = tab_files.get(i) {
|
||||
let tab_file_identifier = OsString::from(format!("${}s", i));
|
||||
|
||||
let args = tab_files.iter()
|
||||
.fold(OsString::new(), |mut args, file| {
|
||||
let file_path = file.strip_prefix(&cwd);
|
||||
let name = file_path.quoted_path();
|
||||
args.push(name);
|
||||
args.push(space.clone());
|
||||
|
||||
args
|
||||
});
|
||||
|
||||
cmd = cmd.replace(&tab_file_identifier, &args);
|
||||
}
|
||||
|
||||
let tab_identifier = OsString::from(format!("${}", i));
|
||||
let tab_path = tab_dir.path().into_os_string();
|
||||
cmd = cmd.replace(&tab_identifier, &tab_path);
|
||||
}
|
||||
|
||||
self.proc_view.lock()?.run_proc(&cmd)?;
|
||||
self.proc_view.lock()?.run_proc_subshell(cmd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -856,6 +845,7 @@ impl Widget for FileBrowser {
|
|||
Key::Char('/') => { self.turbo_cd()?; },
|
||||
Key::Char('Q') => { self.quit_with_dir()?; },
|
||||
Key::Right | Key::Char('f') => { self.enter_dir()?; },
|
||||
Key::Char('F') => { self.open_bg()?; },
|
||||
Key::Left | Key::Char('b') => { self.go_back()?; },
|
||||
Key::Char('-') => { self.goto_prev_cwd()?; },
|
||||
Key::Char('`') => { self.goto_bookmark()?; },
|
||||
|
|
96
src/files.rs
96
src/files.rs
|
@ -517,6 +517,10 @@ impl File {
|
|||
}
|
||||
|
||||
pub fn strip_prefix(&self, base: &File) -> PathBuf {
|
||||
if self == base {
|
||||
return PathBuf::from("./");
|
||||
}
|
||||
|
||||
let base_path = base.path.clone();
|
||||
match self.path.strip_prefix(base_path) {
|
||||
Ok(path) => PathBuf::from(path),
|
||||
|
@ -741,13 +745,105 @@ impl PathBufExt for PathBuf {
|
|||
}
|
||||
|
||||
pub trait OsStrTools {
|
||||
fn split(&self, pat: &OsStr) -> Vec<OsString>;
|
||||
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString;
|
||||
fn trim_last_space(&self) -> OsString;
|
||||
fn contains_osstr(&self, pat: &OsStr) -> bool;
|
||||
fn position(&self, pat: &OsStr) -> Option<usize>;
|
||||
fn splice_quoted(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString>;
|
||||
fn splice_with(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString>;
|
||||
fn quote(&self) -> OsString;
|
||||
}
|
||||
|
||||
impl OsStrTools for OsStr {
|
||||
fn split(&self, pat: &OsStr) -> Vec<OsString> {
|
||||
let orig_string = self.as_bytes().to_vec();
|
||||
let pat = pat.as_bytes().to_vec();
|
||||
let pat_len = pat.len();
|
||||
|
||||
dbg!(&self);
|
||||
|
||||
let split_string = orig_string
|
||||
.windows(pat_len)
|
||||
.enumerate()
|
||||
.fold(Vec::new(), |mut split_pos, (i, chars)| {
|
||||
dbg!(&chars);
|
||||
dbg!(&split_pos);
|
||||
if chars == pat.as_slice() {
|
||||
if split_pos.len() == 0 {
|
||||
split_pos.push((0, i));
|
||||
} else {
|
||||
let len = split_pos.len();
|
||||
let last_split = split_pos[len-1].1;
|
||||
split_pos.push((last_split, i));
|
||||
}
|
||||
}
|
||||
split_pos
|
||||
}).iter()
|
||||
.map(|(start, end)| {
|
||||
//let orig_string = orig_string.clone();
|
||||
OsString::from_vec(orig_string[*start..*end]
|
||||
.to_vec()).replace(&OsString::from_vec(pat.clone()),
|
||||
&OsString::from(""))
|
||||
}).collect();
|
||||
split_string
|
||||
}
|
||||
|
||||
|
||||
fn quote(&self) -> OsString {
|
||||
let mut string = self.as_bytes().to_vec();
|
||||
let mut quote = "\"".as_bytes().to_vec();
|
||||
|
||||
let mut quoted = vec![];
|
||||
quoted.append(&mut quote.clone());
|
||||
quoted.append(&mut string);
|
||||
quoted.append(&mut quote);
|
||||
|
||||
OsString::from_vec(quoted)
|
||||
}
|
||||
|
||||
fn splice_quoted(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString> {
|
||||
let quoted_to = to.iter()
|
||||
.map(|to| to.quote())
|
||||
.collect();
|
||||
self.splice_with(from, quoted_to)
|
||||
}
|
||||
|
||||
fn splice_with(&self, from: &OsStr, to: Vec<OsString>) -> Vec<OsString> {
|
||||
let pos = self.position(from);
|
||||
|
||||
if pos.is_none() {
|
||||
return vec![OsString::from(self)];
|
||||
}
|
||||
|
||||
dbg!(&self);
|
||||
|
||||
let pos = pos.unwrap();
|
||||
let string = self.as_bytes().to_vec();
|
||||
let from = from.as_bytes().to_vec();
|
||||
let fromlen = from.len();
|
||||
|
||||
let lpart = OsString::from_vec(string[0..pos].to_vec());
|
||||
let rpart = OsString::from_vec(string[pos+fromlen..].to_vec());
|
||||
|
||||
dbg!(&lpart);
|
||||
dbg!(&rpart);
|
||||
|
||||
let mut result = vec![
|
||||
vec![lpart.trim_last_space()],
|
||||
to,
|
||||
vec![rpart]
|
||||
].into_iter()
|
||||
.flatten()
|
||||
.filter(|part| part.len() != 0)
|
||||
.collect::<Vec<OsString>>();
|
||||
|
||||
if result.last() == Some(&OsString::from("")) {
|
||||
result.pop();
|
||||
result
|
||||
} else { result }
|
||||
}
|
||||
|
||||
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString {
|
||||
let orig_string = self.as_bytes().to_vec();
|
||||
let from = from.as_bytes();
|
||||
|
|
12
src/paths.rs
12
src/paths.rs
|
@ -10,9 +10,15 @@ pub fn home_path() -> HResult<PathBuf> {
|
|||
}
|
||||
|
||||
pub fn hunter_path() -> HResult<PathBuf> {
|
||||
let mut config_dir = dirs_2::config_dir()?;
|
||||
config_dir.push("hunter/");
|
||||
Ok(config_dir)
|
||||
let mut hunter_path = dirs_2::config_dir()?;
|
||||
hunter_path.push("hunter/");
|
||||
Ok(hunter_path)
|
||||
}
|
||||
|
||||
pub fn config_path() -> HResult<PathBuf> {
|
||||
let mut config_path = hunter_path()?;
|
||||
config_path.push("config");
|
||||
Ok(config_path)
|
||||
}
|
||||
|
||||
pub fn bookmark_path() -> HResult<PathBuf> {
|
||||
|
|
165
src/proclist.rs
165
src/proclist.rs
|
@ -4,6 +4,7 @@ use std::process::Child;
|
|||
use std::os::unix::process::{CommandExt, ExitStatusExt};
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::ffi::OsString;
|
||||
use std::os::unix::ffi::{OsStringExt, OsStrExt};
|
||||
|
||||
use termion::event::Key;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
@ -17,7 +18,7 @@ use crate::hbox::HBox;
|
|||
use crate::preview::WillBeWidget;
|
||||
use crate::fail::{HResult, HError, ErrorLog};
|
||||
use crate::term;
|
||||
use crate::files::OsStrTools;
|
||||
use crate::files::{File, OsStrTools};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Process {
|
||||
|
@ -30,6 +31,75 @@ struct Process {
|
|||
|
||||
}
|
||||
|
||||
pub struct Cmd {
|
||||
pub cmd: OsString,
|
||||
pub args: Option<Vec<OsString>>,
|
||||
pub short_cmd: Option<String>,
|
||||
pub cwd: File,
|
||||
pub cwd_files: Option<Vec<File>>,
|
||||
pub tab_files: Option<Vec<Vec<File>>>,
|
||||
pub tab_paths: Option<Vec<File>>,
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
fn process(&mut self) -> Vec<OsString> {
|
||||
let cmd = self.cmd.clone().split(&OsString::from(" "));
|
||||
let cmd = self.substitute_cwd_files(cmd);
|
||||
let cmd = self.substitute_tab_files(cmd);
|
||||
let cmd = self.substitute_tab_paths(cmd);
|
||||
cmd
|
||||
}
|
||||
|
||||
fn substitute_cwd_files(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||
let cwd_pat = OsString::from("$s");
|
||||
let cwd_files = self.cwd_files
|
||||
.take()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|file| file.strip_prefix(&self.cwd).into_os_string())
|
||||
.collect::<Vec<OsString>>();
|
||||
|
||||
cmd.iter()
|
||||
.map(|part| part.splice_quoted(&cwd_pat,
|
||||
cwd_files.clone()))
|
||||
.flatten().collect()
|
||||
}
|
||||
|
||||
fn substitute_tab_files(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||
let tab_files = self.tab_files.take().unwrap();
|
||||
|
||||
tab_files.into_iter()
|
||||
.enumerate()
|
||||
.fold(cmd, |cmd, (i, tab_files)| {
|
||||
let tab_files_pat = OsString::from(format!("${}s", i));
|
||||
let tab_file_paths = tab_files.iter()
|
||||
.map(|file| file.strip_prefix(&self.cwd).into_os_string())
|
||||
.collect::<Vec<OsString>>();
|
||||
|
||||
cmd.iter().map(|part| {
|
||||
part.splice_quoted(&tab_files_pat,
|
||||
tab_file_paths.clone())
|
||||
}).flatten().collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn substitute_tab_paths(&mut self, cmd: Vec<OsString>) -> Vec<OsString> {
|
||||
let tab_paths = self.tab_paths.take().unwrap();
|
||||
|
||||
tab_paths.into_iter()
|
||||
.enumerate()
|
||||
.fold(cmd, |cmd, (i, tab_path)| {
|
||||
let tab_path_pat = OsString::from(format!("${}", i));
|
||||
let tab_path = tab_path.strip_prefix(&self.cwd).into_os_string();
|
||||
|
||||
cmd.iter().map(|part| {
|
||||
part.splice_quoted(&tab_path_pat,
|
||||
vec![tab_path.clone()])
|
||||
}).flatten().collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Process {
|
||||
fn eq(&self, other: &Process) -> bool {
|
||||
self.cmd == other.cmd
|
||||
|
@ -120,17 +190,44 @@ impl Listable for ListView<Vec<Process>> {
|
|||
}
|
||||
|
||||
impl ListView<Vec<Process>> {
|
||||
fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
|
||||
fn run_proc_subshell(&mut self, mut cmd: Cmd) -> HResult<()> {
|
||||
let shell = std::env::var("SHELL").unwrap_or("sh".into());
|
||||
let home = crate::paths::home_path()?.into_os_string();
|
||||
|
||||
let cmd_args = cmd.process();
|
||||
|
||||
let short = OsString::from("~");
|
||||
let short_cmd = cmd.replace(&home, &short).to_string_lossy().to_string();
|
||||
let short_cmd = cmd_args
|
||||
.concat()
|
||||
.replace(&home, &short)
|
||||
.replace(&OsString::from("\""), &OsString::from(""))
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
self.show_status(&format!("Running: {}", &short_cmd)).log();
|
||||
|
||||
let handle = std::process::Command::new(shell)
|
||||
.arg("-c")
|
||||
.arg(cmd)
|
||||
let shell_args = cmd_args.concat();
|
||||
let shell_args = vec![OsString::from("-c"), shell_args.clone()];
|
||||
|
||||
cmd.cmd = OsString::from(shell.clone());
|
||||
cmd.args = Some(shell_args.clone());
|
||||
cmd.short_cmd = Some(short_cmd);
|
||||
|
||||
self.run_proc_raw(cmd)
|
||||
}
|
||||
|
||||
fn run_proc_raw(&mut self, cmd: Cmd) -> HResult<()> {
|
||||
let real_cmd = cmd.cmd;
|
||||
let short_cmd = cmd.short_cmd
|
||||
.unwrap_or(real_cmd
|
||||
.to_string_lossy()
|
||||
.to_string());
|
||||
let args = cmd.args.unwrap_or(vec![]);
|
||||
|
||||
self.show_status(&format!("Running: {}", &short_cmd)).log();
|
||||
|
||||
let handle = std::process::Command::new(real_cmd)
|
||||
.args(args)
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.before_exec(|| unsafe { libc::dup2(1, 2); Ok(()) })
|
||||
|
@ -289,8 +386,13 @@ impl ProcView {
|
|||
self.hbox.get_textview()
|
||||
}
|
||||
|
||||
pub fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
|
||||
self.get_listview_mut().run_proc(cmd)?;
|
||||
pub fn run_proc_subshell(&mut self, cmd: Cmd) -> HResult<()> {
|
||||
self.get_listview_mut().run_proc_subshell(cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_proc_raw(&mut self, cmd: Cmd) -> HResult<()> {
|
||||
self.get_listview_mut().run_proc_raw(cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -467,3 +569,50 @@ impl Widget for ProcView {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait ConcatOsString {
|
||||
fn concat(&self) -> OsString;
|
||||
fn concat_quoted(&self) -> OsString;
|
||||
}
|
||||
|
||||
impl ConcatOsString for Vec<OsString> {
|
||||
fn concat(&self) -> OsString {
|
||||
let len = self.len();
|
||||
self.iter().enumerate().fold(OsString::new(), |string, (i, part)| {
|
||||
let mut string = string.into_vec();
|
||||
let mut space = " ".as_bytes().to_vec();
|
||||
let mut part = part.clone().into_vec();
|
||||
|
||||
string.append(&mut part);
|
||||
|
||||
if i != len {
|
||||
string.append(&mut space);
|
||||
}
|
||||
|
||||
OsString::from_vec(string)
|
||||
})
|
||||
}
|
||||
|
||||
fn concat_quoted(&self) -> OsString {
|
||||
let len = self.len();
|
||||
self.iter().enumerate().fold(OsString::new(), |string, (i, part)| {
|
||||
let mut string = string.into_vec();
|
||||
let mut space = " ".as_bytes().to_vec();
|
||||
let mut quote = "\"".as_bytes().to_vec();
|
||||
let mut part = part.clone().into_vec();
|
||||
|
||||
|
||||
string.append(&mut quote.clone());
|
||||
string.append(&mut part);
|
||||
string.append(&mut quote);
|
||||
|
||||
|
||||
if i+1 != len {
|
||||
string.append(&mut space);
|
||||
}
|
||||
|
||||
OsString::from_vec(string)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue