summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2019-03-20 00:29:20 +0100
committerrabite <rabite@posteo.de>2019-03-20 00:29:20 +0100
commite36ddf34b4ede92e88c31207c114bea9c0a67f6d (patch)
tree6ad8386708963a834f1f08ed6a56042f04a98b5c
parent161ba5ac3f38733b45c0167cb1e29f0be6059775 (diff)
use osstring for filenames/paths
-rw-r--r--src/file_browser.rs75
-rw-r--r--src/files.rs131
-rw-r--r--src/listview.rs1
-rw-r--r--src/preview.rs2
-rw-r--r--src/proclist.rs13
5 files changed, 185 insertions, 37 deletions
diff --git a/src/file_browser.rs b/src/file_browser.rs
index 51bf72f..ce4a843 100644
--- a/src/file_browser.rs
+++ b/src/file_browser.rs
@@ -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);
}
diff --git a/src/files.rs b/src/files.rs
index 84dbc93..53f167a 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -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.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;
}
}
- return self.to_string_lossy().to_string();
+ 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
+ )
}
}
diff --git a/src/listview.rs b/src/listview.rs
index 1c6f620..d655050 100644
--- a/src/listview.rs
+++ b/src/listview.rs
@@ -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();
}
diff --git a/src/preview.rs b/src/preview.rs
index 9965229..03e2805 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -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())
diff --git a/src/proclist.rs b/src/proclist.rs
index f36ede4..bab9394 100644
--- a/src/proclist.rs
+++ b/src/proclist.rs
@@ -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(())
}