2019-12-18 22:09:36 +01:00
|
|
|
use std::env;
|
2019-12-20 15:55:53 +01:00
|
|
|
use std::ffi::OsString;
|
2020-03-05 16:50:34 +01:00
|
|
|
use std::io::ErrorKind;
|
2020-04-26 15:58:39 +02:00
|
|
|
use std::process;
|
2019-12-18 22:09:36 +01:00
|
|
|
use std::process::Command;
|
|
|
|
|
2020-10-17 11:09:27 +02:00
|
|
|
use crate::config::StarshipConfig;
|
2020-04-26 15:58:39 +02:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Write;
|
|
|
|
use toml::map::Map;
|
2021-01-07 19:04:06 +01:00
|
|
|
use toml::value::Table;
|
2020-04-26 15:58:39 +02:00
|
|
|
use toml::Value;
|
|
|
|
|
2020-08-21 18:41:36 +02:00
|
|
|
#[cfg(not(windows))]
|
2019-12-18 22:09:36 +01:00
|
|
|
const STD_EDITOR: &str = "vi";
|
2020-08-21 18:41:36 +02:00
|
|
|
#[cfg(windows)]
|
|
|
|
const STD_EDITOR: &str = "notepad.exe";
|
2019-12-18 22:09:36 +01:00
|
|
|
|
2020-04-26 15:58:39 +02:00
|
|
|
pub fn update_configuration(name: &str, value: &str) {
|
|
|
|
let keys: Vec<&str> = name.split('.').collect();
|
|
|
|
if keys.len() != 2 {
|
|
|
|
log::error!("Please pass in a config key with a '.'");
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:04:06 +01:00
|
|
|
if let Some(table) = get_configuration().as_table_mut() {
|
2020-04-26 15:58:39 +02:00
|
|
|
if !table.contains_key(keys[0]) {
|
|
|
|
table.insert(keys[0].to_string(), Value::Table(Map::new()));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(values) = table.get(keys[0]).unwrap().as_table() {
|
|
|
|
let mut updated_values = values.clone();
|
|
|
|
|
|
|
|
if value.parse::<bool>().is_ok() {
|
|
|
|
updated_values.insert(
|
|
|
|
keys[1].to_string(),
|
|
|
|
Value::Boolean(value.parse::<bool>().unwrap()),
|
|
|
|
);
|
|
|
|
} else if value.parse::<i64>().is_ok() {
|
|
|
|
updated_values.insert(
|
|
|
|
keys[1].to_string(),
|
|
|
|
Value::Integer(value.parse::<i64>().unwrap()),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
updated_values.insert(keys[1].to_string(), Value::String(value.to_string()));
|
|
|
|
}
|
|
|
|
|
|
|
|
table.insert(keys[0].to_string(), Value::Table(updated_values));
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:04:06 +01:00
|
|
|
write_configuration(table);
|
2020-04-26 15:58:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-07 19:04:06 +01:00
|
|
|
pub fn toggle_configuration(name: &str, key: &str) {
|
|
|
|
if let Some(table) = get_configuration().as_table_mut() {
|
|
|
|
match table.get(name) {
|
|
|
|
Some(v) => {
|
|
|
|
if let Some(values) = v.as_table() {
|
|
|
|
let mut updated_values = values.clone();
|
|
|
|
|
|
|
|
let current: bool = match updated_values.get(key) {
|
|
|
|
Some(v) => match v.as_bool() {
|
|
|
|
Some(b) => b,
|
|
|
|
_ => {
|
|
|
|
log::error!(
|
|
|
|
"Given config key '{}' must be in 'boolean' format",
|
|
|
|
key
|
|
|
|
);
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
log::error!("Given config key '{}' must be exist in config file", key);
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
updated_values.insert(key.to_string(), Value::Boolean(!current));
|
|
|
|
|
|
|
|
table.insert(name.to_string(), Value::Table(updated_values));
|
|
|
|
|
|
|
|
write_configuration(table);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
log::error!("Given module '{}' not found in config file", name);
|
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_configuration() -> Value {
|
|
|
|
let starship_config = StarshipConfig::initialize();
|
|
|
|
|
|
|
|
starship_config
|
|
|
|
.config
|
|
|
|
.expect("Failed to load starship config")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write_configuration(table: &mut Table) {
|
|
|
|
let config_path = get_config_path();
|
|
|
|
|
|
|
|
let config_str =
|
|
|
|
toml::to_string_pretty(&table).expect("Failed to serialize the config to string");
|
|
|
|
|
|
|
|
File::create(&config_path)
|
|
|
|
.and_then(|mut file| file.write_all(config_str.as_ref()))
|
|
|
|
.expect("Error writing starship config");
|
|
|
|
}
|
|
|
|
|
2019-12-18 22:09:36 +01:00
|
|
|
pub fn edit_configuration() {
|
|
|
|
let config_path = get_config_path();
|
2020-08-21 18:41:36 +02:00
|
|
|
let editor_cmd = shell_words::split(&get_editor()).expect("Unmatched quotes found in $EDITOR.");
|
2019-12-23 16:27:00 +01:00
|
|
|
|
2020-08-21 18:41:36 +02:00
|
|
|
let command = Command::new(&editor_cmd[0])
|
|
|
|
.args(&editor_cmd[1..])
|
|
|
|
.arg(config_path)
|
|
|
|
.status();
|
2020-03-05 16:50:34 +01:00
|
|
|
|
|
|
|
match command {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(error) => match error.kind() {
|
|
|
|
ErrorKind::NotFound => {
|
|
|
|
eprintln!(
|
|
|
|
"Error: editor {:?} was not found. Did you set your $EDITOR or $VISUAL \
|
|
|
|
environment variables correctly?",
|
2020-08-21 18:41:36 +02:00
|
|
|
editor_cmd
|
2020-03-05 16:50:34 +01:00
|
|
|
);
|
|
|
|
std::process::exit(1)
|
|
|
|
}
|
|
|
|
other_error => panic!("failed to open file: {:?}", other_error),
|
|
|
|
},
|
|
|
|
};
|
2019-12-18 22:09:36 +01:00
|
|
|
}
|
|
|
|
|
2020-08-21 18:41:36 +02:00
|
|
|
fn get_editor() -> String {
|
|
|
|
get_editor_internal(env::var("VISUAL").ok(), env::var("EDITOR").ok())
|
2019-12-23 16:27:00 +01:00
|
|
|
}
|
|
|
|
|
2020-08-21 18:41:36 +02:00
|
|
|
fn get_editor_internal(visual: Option<String>, editor: Option<String>) -> String {
|
|
|
|
let editor_name = visual.unwrap_or_else(|| "".into());
|
2019-12-23 16:27:00 +01:00
|
|
|
if !editor_name.is_empty() {
|
|
|
|
return editor_name;
|
|
|
|
}
|
2020-08-21 18:41:36 +02:00
|
|
|
let editor_name = editor.unwrap_or_else(|| "".into());
|
2019-12-23 16:27:00 +01:00
|
|
|
if !editor_name.is_empty() {
|
|
|
|
return editor_name;
|
|
|
|
}
|
|
|
|
STD_EDITOR.into()
|
2019-12-18 22:09:36 +01:00
|
|
|
}
|
|
|
|
|
2019-12-20 15:55:53 +01:00
|
|
|
fn get_config_path() -> OsString {
|
2020-08-21 18:41:36 +02:00
|
|
|
if let Some(config_path) = env::var_os("STARSHIP_CONFIG") {
|
|
|
|
return config_path;
|
2019-12-31 00:46:02 +01:00
|
|
|
}
|
2020-08-21 18:41:36 +02:00
|
|
|
dirs_next::home_dir()
|
|
|
|
.expect("couldn't find home directory")
|
|
|
|
.join(".config")
|
|
|
|
.join("starship.toml")
|
|
|
|
.into()
|
2019-12-18 22:09:36 +01:00
|
|
|
}
|
2019-12-23 16:27:00 +01:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
// This is every possible permutation, 3² = 9.
|
|
|
|
#[test]
|
|
|
|
fn visual_set_editor_set() {
|
|
|
|
let actual = get_editor_internal(Some("foo".into()), Some("bar".into()));
|
|
|
|
assert_eq!("foo", actual);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_set_editor_empty() {
|
|
|
|
let actual = get_editor_internal(Some("foo".into()), None);
|
|
|
|
assert_eq!("foo", actual);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_set_editor_not_set() {
|
|
|
|
let actual = get_editor_internal(Some("foo".into()), None);
|
|
|
|
assert_eq!("foo", actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn visual_empty_editor_set() {
|
|
|
|
let actual = get_editor_internal(Some("".into()), Some("bar".into()));
|
|
|
|
assert_eq!("bar", actual);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_empty_editor_empty() {
|
|
|
|
let actual = get_editor_internal(Some("".into()), Some("".into()));
|
2020-08-21 18:41:36 +02:00
|
|
|
assert_eq!(STD_EDITOR, actual);
|
2019-12-23 16:27:00 +01:00
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_empty_editor_not_set() {
|
|
|
|
let actual = get_editor_internal(Some("".into()), None);
|
2020-08-21 18:41:36 +02:00
|
|
|
assert_eq!(STD_EDITOR, actual);
|
2019-12-23 16:27:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn visual_not_set_editor_set() {
|
|
|
|
let actual = get_editor_internal(None, Some("bar".into()));
|
|
|
|
assert_eq!("bar", actual);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_not_set_editor_empty() {
|
|
|
|
let actual = get_editor_internal(None, Some("".into()));
|
2020-08-21 18:41:36 +02:00
|
|
|
assert_eq!(STD_EDITOR, actual);
|
2019-12-23 16:27:00 +01:00
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn visual_not_set_editor_not_set() {
|
|
|
|
let actual = get_editor_internal(None, None);
|
2020-08-21 18:41:36 +02:00
|
|
|
assert_eq!(STD_EDITOR, actual);
|
2019-12-23 16:27:00 +01:00
|
|
|
}
|
|
|
|
}
|