use osstring for filenames/paths

This commit is contained in:
rabite 2019-03-20 00:29:20 +01:00
parent 161ba5ac3f
commit e36ddf34b4
5 changed files with 185 additions and 37 deletions

View File

@ -7,8 +7,9 @@ use std::sync::mpsc::{channel, Receiver, Sender};
use std::time::Duration;
use std::path::PathBuf;
use std::collections::HashMap;
use std::ffi::{OsString, OsStr};
use crate::files::{File, Files, ShortPaths};
use crate::files::{File, Files, PathBufExt, OsStrTools};
use crate::listview::ListView;
use crate::miller_columns::MillerColumns;
use crate::widget::Widget;
@ -131,13 +132,15 @@ impl Tabbable for TabView<FileBrowser> {
Key::Char('!') => {
let tab_dirs = self.widgets.iter().map(|w| w.cwd.clone())
.collect::<Vec<_>>();
let selected_files = self.widgets.iter().fold(HashMap::new(),
|mut f, w| {
let dir = w.cwd().unwrap().clone();
let selected_files = w.selected_files().unwrap();
f.insert(dir, selected_files);
f
});
let selected_files = self
.widgets
.iter()
.map(|w| {
w.selected_files()
.map_err(|_| Vec::<Files>::new())
.unwrap()
}).collect();
self.widgets[self.active].exec_cmd(tab_dirs, selected_files)
}
_ => { self.active_tab_mut().on_key(key) }
@ -633,39 +636,55 @@ impl FileBrowser {
fn exec_cmd(&mut self,
tab_dirs: Vec<File>,
tab_files: HashMap<File, Vec<File>>) -> HResult<()> {
tab_files: Vec<Vec<File>>) -> HResult<()> {
let cwd = self.cwd()?;
let filename = self.selected_file()?.name.clone();
let filename = self.selected_file()?.path.quoted_file_name()?;
let selected_files = self.selected_files()?;
let file_names
= selected_files.iter().map(|f| f.name.clone()).collect::<Vec<String>>();
let files = selected_files.iter()
.map(|f| f.path())
.collect::<Vec<PathBuf>>();
let cmd = self.minibuffer("exec")?;
let cmd = self.minibuffer("exec")?.trim_start().to_string();
self.show_status(&format!("Running: \"{}\"", &cmd)).log();
let cmd = OsString::from(cmd);
let space = OsString::from(" ");
let mut cmd = if file_names.len() == 0 {
cmd.replace("$s", &format!("{}", &filename))
let mut cmd = if files.len() == 0 {
cmd.replace(&OsString::from("$s"), &filename)
} else {
let args = file_names.iter().map(|f| {
format!(" \"{}\" ", f)
}).collect::<String>();
cmd.replace("$s", &args)
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)
};
for (i, tab_dir) in tab_dirs.iter().enumerate() {
if let Some(tab_files) = tab_files.get(tab_dir) {
let tab_file_identifier = format!("${}s", i);
let args = tab_files.iter().map(|f| {
let file_path = f.strip_prefix(&cwd);
format!(" \"{}\" ", file_path.to_string_lossy())
}).collect::<String>();
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 = format!("${}", i);
let tab_path = tab_dir.path.to_string_lossy();
let tab_identifier = OsString::from(format!("${}", i));
let tab_path = tab_dir.path().into_os_string();
cmd = cmd.replace(&tab_identifier, &tab_path);
}

View File

@ -4,6 +4,8 @@ use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::hash::{Hash, Hasher};
use std::os::unix::ffi::{OsStringExt, OsStrExt};
use std::ffi::{OsStr, OsString};
use lscolors::LsColors;
use mime_detective;
@ -609,25 +611,144 @@ impl File {
Some(time.format("%F %R").to_string())
}
pub fn short_path(&self) -> PathBuf {
self.path.short_path()
}
pub fn short_string(&self) -> String {
self.path.short_string()
}
}
pub trait ShortPaths {
pub trait PathBufExt {
fn short_path(&self) -> PathBuf;
fn short_string(&self) -> String;
fn name_starts_with(&self, pat: &str) -> bool;
fn quoted_file_name(&self) -> Option<OsString>;
fn quoted_path(&self) -> OsString;
}
impl ShortPaths for PathBuf {
fn short_string(&self) -> String {
impl PathBufExt for PathBuf {
fn short_path(&self) -> PathBuf {
if let Ok(home) = crate::paths::home_path() {
if let Ok(short) = self.strip_prefix(home) {
let mut path = PathBuf::from("~");
path.push(short);
return path.to_string_lossy().to_string();
return path
}
}
return self.to_string_lossy().to_string();
return self.clone();
}
fn short_string(&self) -> String {
self.short_path().to_string_lossy().to_string()
}
fn name_starts_with(&self, pat: &str) -> bool {
if let Some(name) = self.file_name() {
let nbytes = name.as_bytes();
let pbytes = pat.as_bytes();
if nbytes.starts_with(pbytes) {
return true;
} else {
return false;
}
}
false
}
fn quoted_file_name(&self) -> Option<OsString> {
if let Some(name) = self.file_name() {
let mut name = name.as_bytes().to_vec();
let mut quote = "\"".as_bytes().to_vec();
//let mut quote_after = "\"".as_bytes().to_vec();
let mut quoted = vec![];
quoted.append(&mut quote.clone());
quoted.append(&mut name);
quoted.append(&mut quote);
let quoted_name = OsStr::from_bytes(&quoted).to_os_string();
return Some(quoted_name);
}
None
}
fn quoted_path(&self) -> OsString {
let mut path = self.clone().into_os_string().into_vec();
let mut quote = "\"".as_bytes().to_vec();
let mut quoted = vec![];
quoted.append(&mut quote.clone());
quoted.append(&mut path);
quoted.append(&mut quote);
OsString::from_vec(quoted)
}
}
pub trait OsStrTools {
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>;
}
impl OsStrTools for OsStr {
fn replace(&self, from: &OsStr, to: &OsStr) -> OsString {
let orig_string = self.as_bytes().to_vec();
let from = from.as_bytes();
let to = to.as_bytes().to_vec();
let from_len = from.len();
let new_string = orig_string
.windows(from_len)
.enumerate()
.fold(Vec::new(), |mut pos, (i, chars)| {
if chars == from {
pos.push(i);
}
pos
}).iter().rev().fold(orig_string.to_vec(), |mut string, pos| {
let pos = *pos;
string.splice(pos..pos+from_len, to.clone());
string
});
OsString::from_vec(new_string)
}
fn trim_last_space(&self) -> OsString {
let string = self.as_bytes();
let len = string.len();
if len > 0 {
OsString::from_vec(string[..len-1].to_vec())
} else {
self.to_os_string()
}
}
fn contains_osstr(&self, pat: &OsStr) -> bool {
let string = self.as_bytes();
let pat = pat.as_bytes();
let pat_len = pat.len();
string.windows(pat_len)
.find(|chars|
chars == &pat
).is_some()
}
fn position(&self, pat: &OsStr) -> Option<usize> {
let string = self.as_bytes();
let pat = pat.as_bytes();
let pat_len = pat.len();
string.windows(pat_len)
.position(|chars|
chars == pat
)
}
}

View File

@ -300,6 +300,7 @@ impl ListView<Files>
let file = self.selected_file_mut();
file.toggle_selection();
self.move_down();
self.core.set_dirty();
self.refresh().log();
}

View File

@ -388,7 +388,7 @@ impl Previewer {
-> Result<Box<dyn Widget + Send>, HError> {
let process =
std::process::Command::new("scope.sh")
.arg(&file.name)
.arg(&file.path)
.arg("10".to_string())
.arg("10".to_string())
.arg("".to_string())

View File

@ -3,6 +3,7 @@ use std::sync::mpsc::Sender;
use std::process::Child;
use std::os::unix::process::{CommandExt, ExitStatusExt};
use std::io::{BufRead, BufReader};
use std::ffi::OsString;
use termion::event::Key;
use unicode_width::UnicodeWidthStr;
@ -15,6 +16,7 @@ use crate::hbox::HBox;
use crate::preview::WillBeWidget;
use crate::fail::{HResult, HError, ErrorLog};
use crate::term;
use crate::files::OsStrTools;
#[derive(Debug)]
struct Process {
@ -114,8 +116,13 @@ impl Listable for ListView<Vec<Process>> {
}
impl ListView<Vec<Process>> {
fn run_proc(&mut self, cmd: &str) -> HResult<()> {
fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
let shell = std::env::var("SHELL").unwrap_or("sh".into());
let home = crate::paths::home_path()?.into_os_string();
let short = OsString::from("~");
let short_cmd = cmd.replace(&home, &short).to_string_lossy().to_string();
self.show_status(&format!("Running: {}", &short_cmd)).log();
let handle = std::process::Command::new(shell)
.arg("-c")
@ -125,7 +132,7 @@ impl ListView<Vec<Process>> {
.before_exec(|| unsafe { libc::dup2(1, 2); Ok(()) })
.spawn()?;
let mut proc = Process {
cmd: cmd.to_string(),
cmd: short_cmd,
handle: Arc::new(Mutex::new(handle)),
output: Arc::new(Mutex::new(String::new())),
status: Arc::new(Mutex::new(None)),
@ -278,7 +285,7 @@ impl ProcView {
self.hbox.get_textview()
}
pub fn run_proc(&mut self, cmd: &str) -> HResult<()> {
pub fn run_proc(&mut self, cmd: &OsString) -> HResult<()> {
self.get_listview_mut().run_proc(cmd)?;
Ok(())
}