summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2019-03-21 21:25:38 +0100
committerrabite <rabite@posteo.de>2019-03-21 21:32:41 +0100
commite4a2749ee0671c7d112b0ab6cabb8e61f8c0f9c0 (patch)
tree2c35b741b40b8bc8c829a6b722fa79352304b2d5
parent2ca81c123c4dad7b9944967a57d14fc76f067dc0 (diff)
start stuff in the background
-rw-r--r--src/file_browser.rs82
-rw-r--r--src/files.rs96
-rw-r--r--src/paths.rs12
-rw-r--r--src/proclist.rs165
4 files changed, 298 insertions, 57 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs
index 91194f2..558e5a6 100644
--- a/src/file_browser.rs
+++ b/src/file_browser.rs
@@ -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 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 cwd = self.cwd()?.clone();
+ let selected_file = self.selected_file()?;
+ let selected_files = self.selected_files()?;
- let cmd = OsString::from(cmd);
- let space = OsString::from(" ");
+ let cmd = self.minibuffer("exec")?.trim_start().to_string() + " ";
- 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();
+ let cwd_files = if selected_files.len() == 0 {
+ vec![selected_file]
+ } else { selected_files };
- 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()?; },
diff --git a/src/files.rs b/src/files.rs
index 54e9049..1a038ac 100644
--- a/src/files.rs
+++ b/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();
diff --git a/src/paths.rs b/src/paths.rs
index b3f3e1d..8917756 100644
--- a/src/paths.rs
+++ b/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> {
diff --git a/src/proclist.rs b/src/proclist.rs
index a841b44..a4efabf 100644
--- a/src/proclist.rs
+++ b/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)
+ })
+ }
+}