start stuff in the background

This commit is contained in:
rabite 2019-03-21 21:25:38 +01:00
parent 2ca81c123c
commit e4a2749ee0
4 changed files with 298 additions and 57 deletions

View File

@ -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()?; },

View File

@ -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();

View File

@ -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> {

View File

@ -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)
})
}
}