fix: $EDITOR argument parsing (#1595)

Fixed editor argument parsing by properly splitting
whitespace with the same procedure used by shell.
This commit is contained in:
jRimbault 2020-08-21 18:41:36 +02:00 committed by GitHub
parent d4515696a4
commit 12c7877932
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 29 deletions

7
Cargo.lock generated
View File

@ -1187,6 +1187,12 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "shell-words"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
[[package]] [[package]]
name = "starship" name = "starship"
version = "0.44.0" version = "0.44.0"
@ -1215,6 +1221,7 @@ dependencies = [
"rayon", "rayon",
"regex", "regex",
"serde_json", "serde_json",
"shell-words",
"starship_module_config_derive", "starship_module_config_derive",
"sysinfo", "sysinfo",
"tempfile", "tempfile",

View File

@ -63,6 +63,7 @@ notify-rust = { version = "4.0.0", optional = true }
# Optional/http: # Optional/http:
attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] } attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] }
native-tls = { version = "0.2", optional = true } native-tls = { version = "0.2", optional = true }
shell-words = "1.0.0"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = [ winapi = { version = "0.3", features = [

View File

@ -10,7 +10,10 @@ use std::io::Write;
use toml::map::Map; use toml::map::Map;
use toml::Value; use toml::Value;
#[cfg(not(windows))]
const STD_EDITOR: &str = "vi"; const STD_EDITOR: &str = "vi";
#[cfg(windows)]
const STD_EDITOR: &str = "notepad.exe";
pub fn update_configuration(name: &str, value: &str) { pub fn update_configuration(name: &str, value: &str) {
let config_path = get_config_path(); let config_path = get_config_path();
@ -61,17 +64,12 @@ pub fn update_configuration(name: &str, value: &str) {
pub fn edit_configuration() { pub fn edit_configuration() {
let config_path = get_config_path(); let config_path = get_config_path();
let editor_cmd = get_editor(); let editor_cmd = shell_words::split(&get_editor()).expect("Unmatched quotes found in $EDITOR.");
let mut cmd_iter = editor_cmd let command = Command::new(&editor_cmd[0])
.to_str() .args(&editor_cmd[1..])
.expect("environment variable contains invalid unicode") .arg(config_path)
.split_whitespace(); .status();
let editor = cmd_iter.next().unwrap_or(STD_EDITOR);
let args: Vec<_> = cmd_iter.collect();
let command = Command::new(editor).args(args).arg(config_path).status();
match command { match command {
Ok(_) => (), Ok(_) => (),
@ -80,7 +78,7 @@ pub fn edit_configuration() {
eprintln!( eprintln!(
"Error: editor {:?} was not found. Did you set your $EDITOR or $VISUAL \ "Error: editor {:?} was not found. Did you set your $EDITOR or $VISUAL \
environment variables correctly?", environment variables correctly?",
editor editor_cmd
); );
eprintln!("Full error: {:?}", error); eprintln!("Full error: {:?}", error);
std::process::exit(1) std::process::exit(1)
@ -90,16 +88,16 @@ pub fn edit_configuration() {
}; };
} }
fn get_editor() -> OsString { fn get_editor() -> String {
get_editor_internal(env::var_os("VISUAL"), env::var_os("EDITOR")) get_editor_internal(env::var("VISUAL").ok(), env::var("EDITOR").ok())
} }
fn get_editor_internal(visual: Option<OsString>, editor: Option<OsString>) -> OsString { fn get_editor_internal(visual: Option<String>, editor: Option<String>) -> String {
let mut editor_name = visual.unwrap_or_else(|| "".into()); let editor_name = visual.unwrap_or_else(|| "".into());
if !editor_name.is_empty() { if !editor_name.is_empty() {
return editor_name; return editor_name;
} }
editor_name = editor.unwrap_or_else(|| "".into()); let editor_name = editor.unwrap_or_else(|| "".into());
if !editor_name.is_empty() { if !editor_name.is_empty() {
return editor_name; return editor_name;
} }
@ -107,16 +105,14 @@ fn get_editor_internal(visual: Option<OsString>, editor: Option<OsString>) -> Os
} }
fn get_config_path() -> OsString { fn get_config_path() -> OsString {
let config_path = env::var_os("STARSHIP_CONFIG").unwrap_or_else(|| "".into()); if let Some(config_path) = env::var_os("STARSHIP_CONFIG") {
if config_path.is_empty() { return config_path;
dirs_next::home_dir()
.expect("couldn't find home directory")
.join(".config/starship.toml")
.as_os_str()
.to_owned()
} else {
config_path
} }
dirs_next::home_dir()
.expect("couldn't find home directory")
.join(".config")
.join("starship.toml")
.into()
} }
#[cfg(test)] #[cfg(test)]
@ -149,12 +145,12 @@ mod tests {
#[test] #[test]
fn visual_empty_editor_empty() { fn visual_empty_editor_empty() {
let actual = get_editor_internal(Some("".into()), Some("".into())); let actual = get_editor_internal(Some("".into()), Some("".into()));
assert_eq!("vi", actual); assert_eq!(STD_EDITOR, actual);
} }
#[test] #[test]
fn visual_empty_editor_not_set() { fn visual_empty_editor_not_set() {
let actual = get_editor_internal(Some("".into()), None); let actual = get_editor_internal(Some("".into()), None);
assert_eq!("vi", actual); assert_eq!(STD_EDITOR, actual);
} }
#[test] #[test]
@ -165,11 +161,11 @@ mod tests {
#[test] #[test]
fn visual_not_set_editor_empty() { fn visual_not_set_editor_empty() {
let actual = get_editor_internal(None, Some("".into())); let actual = get_editor_internal(None, Some("".into()));
assert_eq!("vi", actual); assert_eq!(STD_EDITOR, actual);
} }
#[test] #[test]
fn visual_not_set_editor_not_set() { fn visual_not_set_editor_not_set() {
let actual = get_editor_internal(None, None); let actual = get_editor_internal(None, None);
assert_eq!("vi", actual); assert_eq!(STD_EDITOR, actual);
} }
} }