summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatan Kushner <hello@matchai.me>2019-07-02 16:12:53 -0400
committerGitHub <noreply@github.com>2019-07-02 16:12:53 -0400
commit463ec260247fa0e62d2ea14e237681a499955392 (patch)
tree0d7ed8d19187c298c2e7764f21387a919d21877c
parent2440ed60d0a315e6248c040d2a114f7deeea6260 (diff)
feat: Add a `disabled` configuration option for modules (#86)
โ€ข Add support for the disabled configuration option This will allow you to selectively disable modules that you don't want or need. ๐Ÿ˜„ โ€ข Overwrite starship configuration file path with STARSHIP_CONFIG environment variable โ€ข Write tests for the two configuration options that are available
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/config.rs63
-rw-r--r--src/context.rs21
-rw-r--r--src/main.rs50
-rw-r--r--src/modules/battery.rs6
-rw-r--r--src/modules/character.rs4
-rw-r--r--src/modules/directory.rs4
-rw-r--r--src/modules/git_branch.rs4
-rw-r--r--src/modules/git_status.rs4
-rw-r--r--src/modules/go.rs4
-rw-r--r--src/modules/line_break.rs4
-rw-r--r--src/modules/mod.rs24
-rw-r--r--src/modules/nodejs.rs4
-rw-r--r--src/modules/package.rs14
-rw-r--r--src/modules/python.rs4
-rw-r--r--src/modules/rust.rs11
-rw-r--r--src/modules/username.rs4
-rw-r--r--src/print.rs31
-rw-r--r--tests/fixtures/empty_config.toml0
-rw-r--r--tests/testsuite/common.rs45
-rw-r--r--tests/testsuite/configuration.rs34
-rw-r--r--tests/testsuite/main.rs1
-rw-r--r--tests/testsuite/username.rs6
24 files changed, 240 insertions, 104 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ed8070901..943c7b47f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -818,6 +818,7 @@ dependencies = [
"criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 641282208..097426fce 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,7 @@ rayon = "1.1.0"
pretty_env_logger = "0.3.0"
log = "0.4.6"
battery = "0.7.4"
+lazy_static = "1.3.0"
[dev-dependencies]
tempfile = "3.1.0"
diff --git a/src/config.rs b/src/config.rs
index 7c0509a2b..74ff447d2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,4 +1,5 @@
use crate::utils;
+use std::env;
use dirs::home_dir;
@@ -20,9 +21,33 @@ impl Config {
/// Create a config from a starship configuration file
fn config_from_file() -> Option<toml::value::Table> {
- let file_path = home_dir()?.join(".config/starship.toml");
- let toml_content = utils::read_file(&file_path.to_str()?).ok()?;
- log::trace!("Config file content: \n{}", &toml_content);
+ let file_path = match env::var("STARSHIP_CONFIG") {
+ Ok(path) => {
+ // Use $STARSHIP_CONFIG as the config path if available
+ log::debug!("STARSHIP_CONFIG is set: {}", &path);
+ path
+ }
+ Err(_) => {
+ // Default to using ~/.config/starhip.toml
+ log::debug!("STARSHIP_CONFIG is not set");
+ let config_path = home_dir()?.join(".config/starship.toml");
+ let config_path_str = config_path.to_str()?.to_owned();
+
+ log::debug!("Using default config path: {}", config_path_str);
+ config_path_str
+ }
+ };
+
+ let toml_content = match utils::read_file(&file_path) {
+ Ok(content) => {
+ log::trace!("Config file content: \n{}", &content);
+ Some(content)
+ }
+ Err(e) => {
+ log::debug!("Unable to read config file content: \n{}", &e);
+ None
+ }
+ }?;
let config = toml::from_str(&toml_content).ok()?;
log::debug!("Config found: \n{:?}", &config);
@@ -40,3 +65,35 @@ impl Config {
module_config
}
}
+
+/// Extends `toml::value::Table` with useful methods
+pub trait TableExt {
+ fn get_as_bool(&self, key: &str) -> Option<bool>;
+}
+
+impl TableExt for toml::value::Table {
+ /// Get a key from a module's configuration as a boolean
+ fn get_as_bool(&self, key: &str) -> Option<bool> {
+ self.get(key).map(toml::Value::as_bool).unwrap_or(None)
+ }
+}
+
+mod tests {
+ use super::*;
+
+ #[test]
+ fn table_get_as_bool() {
+ let mut table = toml::value::Table::new();
+
+ // Use with boolean value
+ table.insert("boolean".to_string(), toml::value::Value::Boolean(true));
+ assert_eq!(table.get_as_bool("boolean"), Some(true));
+
+ // Use with string value
+ table.insert(
+ "string".to_string(),
+ toml::value::Value::String("true".to_string()),
+ );
+ assert_eq!(table.get_as_bool("string"), None);
+ }
+}
diff --git a/src/context.rs b/src/context.rs
index fd0ccc825..f62ea76cd 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,4 +1,4 @@
-use crate::config::Config;
+use crate::config::{Config, TableExt};
use crate::module::Module;
use clap::ArgMatches;
@@ -75,8 +75,23 @@ impl<'a> Context<'a> {
dir
}
- pub fn new_module(&self, name: &str) -> Module {
- Module::new(name, self.config.get_module_config(name))
+ /// Create a new module
+ ///
+ /// Will return `None` if the module is disabled by configuration, by setting
+ /// the `disabled` key to `true` in the configuration for that module.
+ pub fn new_module(&self, name: &str) -> Option<Module> {
+ let config = self.config.get_module_config(name);
+
+ // If the segment has "disabled" set to "true", don't show it
+ let disabled = config
+ .map(|table| table.get_as_bool("disabled"))
+ .unwrap_or(None);
+
+ if disabled == Some(true) {
+ return None;
+ }
+
+ Some(Module::new(name, config))
}
// returns a new ScanDir struct with reference to current dir_files of context
diff --git a/src/main.rs b/src/main.rs
index 70f68e2e5..371109e50 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,6 +14,20 @@ use clap::{App, Arg, SubCommand};
fn main() {
pretty_env_logger::init();
+ let status_code_arg = Arg::with_name("status_code")
+ .short("s")
+ .long("status")
+ .value_name("STATUS_CODE")
+ .help("The status code of the previously run command")
+ .takes_value(true);
+
+ let path_arg = Arg::with_name("path")
+ .short("p")
+ .long("path")
+ .value_name("PATH")
+ .help("The path that the prompt should render for")
+ .takes_value(true);
+
let matches = App::new("Starship")
.about("The cross-shell prompt for astronauts. โœจ๐Ÿš€")
// pull the version number from Cargo.toml
@@ -24,22 +38,8 @@ fn main() {
.subcommand(
SubCommand::with_name("prompt")
.about("Prints the full starship prompt")
- .arg(
- Arg::with_name("status_code")
- .short("s")
- .long("status")
- .value_name("STATUS_CODE")
- .help("The status code of the previously run command")
- .takes_value(true),
- )
- .arg(
- Arg::with_name("path")
- .short("p")
- .long("path")
- .value_name("PATH")
- .help("The path that the prompt should render for ($PWD by default)")
- .takes_value(true),
- ),
+ .arg(&status_code_arg)
+ .arg(&path_arg),
)
.subcommand(
SubCommand::with_name("module")
@@ -49,22 +49,8 @@ fn main() {
.help("The name of the module to be printed")
.required(true),
)
- .arg(
- Arg::with_name("status_code")
- .short("s")
- .long("status")
- .value_name("STATUS_CODE")
- .help("The status code of the previously run command")
- .takes_value(true),
- )
- .arg(
- Arg::with_name("path")
- .short("p")
- .long("path")
- .value_name("PATH")
- .help("The path the prompt should render for ($PWD by default)")
- .takes_value(true),
- ),
+ .arg(&status_code_arg)
+ .arg(&path_arg),
)
.get_matches();
diff --git a/src/modules/battery.rs b/src/modules/battery.rs
index 75ac1c554..048abe05f 100644
--- a/src/modules/battery.rs
+++ b/src/modules/battery.rs
@@ -3,7 +3,7 @@ use ansi_term::Color;
use super::{Context, Module};
/// Creates a segment for the battery percentage and charging state
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const BATTERY_FULL: &str = "โ€ข";
const BATTERY_CHARGING: &str = "โ‡ก";
const BATTERY_DISCHARGING: &str = "โ‡ฃ";
@@ -22,7 +22,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
}
// TODO: Set style based on percentage when threshold is modifiable
- let mut module = context.new_module("battery");
+ let mut module = context.new_module("battery")?;
module.set_style(Color::Red.bold());
module.get_prefix().set_value("");
@@ -61,7 +61,7 @@ fn get_battery_status() -> Option<BatteryStatus> {
Some(battery_status)
}
Some(Err(e)) => {
- log::debug!("Unable to access battery information:\n{}", e);
+ log::debug!("Unable to access battery information:\n{}", &e);
None
}
None => {
diff --git a/src/modules/character.rs b/src/modules/character.rs
index 1a55cf78f..447fd759e 100644
--- a/src/modules/character.rs
+++ b/src/modules/character.rs
@@ -9,12 +9,12 @@ use ansi_term::Color;
/// (green by default)
/// - If the exit-code was anything else, the arrow will be formatted with
/// `COLOR_FAILURE` (red by default)
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const PROMPT_CHAR: &str = "โžœ";
let color_success = Color::Green.bold();
let color_failure = Color::Red.bold();
- let mut module = context.new_module("char");
+ let mut module = context.new_module("char")?;
module.get_prefix().set_value("");
let symbol = module.new_segment("symbol", PROMPT_CHAR);
diff --git a/src/modules/directory.rs b/src/modules/directory.rs
index 8e719c452..a2cafac16 100644
--- a/src/modules/directory.rs
+++ b/src/modules/directory.rs
@@ -12,12 +12,12 @@ use super::{Context, Module};
///
/// **Truncation**
/// Paths will be limited in length to `3` path components by default.
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const HOME_SYMBOL: &str = "~";
const DIR_TRUNCATION_LENGTH: usize = 3;
let module_color = Color::Cyan.bold();
- let mut module = context.new_module("directory");
+ let mut module = context.new_module("directory")?;
module.set_style(module_color);
let current_dir = &context.current_dir;
diff --git a/src/modules/git_branch.rs b/src/modules/git_branch.rs
index 010c4eccb..d2861c47b 100644
--- a/src/modules/git_branch.rs
+++ b/src/modules/git_branch.rs
@@ -5,13 +5,13 @@ use super::{Context, Module};
/// Creates a segment with the Git branch in the current directory
///
/// Will display the branch name if the current directory is a git repo
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let branch_name = context.branch_name.as_ref()?;
const GIT_BRANCH_CHAR: &str = "๎‚  ";
let segment_color = Color::Purple.bold();
- let mut module = context.new_module("git_branch");
+ let mut module = context.new_module("git_branch")?;
module.set_style(segment_color);
module.get_prefix().set_value("on ");
diff --git a/src/modules/git_status.rs b/src/modules/git_status.rs
index 6db29ba12..c5ec57e4d 100644
--- a/src/modules/git_status.rs
+++ b/src/modules/git_status.rs
@@ -17,7 +17,7 @@ use super::{Context, Module};
/// - `+` โ€” A new file has been added to the staging area
/// - `ยป` โ€” A renamed file has been added to the staging area
/// - `โœ˜` โ€” A file's deletion has been added to the staging area
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// This is the order that the sections will appear in
const GIT_STATUS_CONFLICTED: &str = "=";
const GIT_STATUS_AHEAD: &str = "โ‡ก";
@@ -35,7 +35,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
let repository = Repository::open(repo_root).ok()?;
let module_style = Color::Red.bold();
- let mut module = context.new_module("git_status");
+ let mut module = context.new_module("git_status")?;
module.get_prefix().set_value("[").set_style(module_style);
module.get_suffix().set_value("] ").set_style(module_style);
module.set_style(module_style);
diff --git a/src/modules/go.rs b/src/modules/go.rs
index e4b689aff..a1b192e4a 100644
--- a/src/modules/go.rs
+++ b/src/modules/go.rs
@@ -13,7 +13,7 @@ use super::{Context, Module};
/// - Current directory contains a `Gopkg.lock` file
/// - Current directory contains a `.go` file
/// - Current directory contains a `Godeps` directory
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_go_project = context
.new_scan_dir()
.set_files(&["go.mod", "go.sum", "glide.yaml", "Gopkg.yml", "Gopkg.lock"])
@@ -30,7 +30,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
const GO_CHAR: &str = "๐Ÿน ";
let module_color = Color::Cyan.bold();
- let mut module = context.new_module("go");
+ let mut module = context.new_module("go")?;
module.set_style(module_color);
let formatted_version = format_go_version(go_version)?;
diff --git a/src/modules/line_break.rs b/src/modules/line_break.rs
index 0b11367ec..b86f85e38 100644
--- a/src/modules/line_break.rs
+++ b/src/modules/line_break.rs
@@ -1,10 +1,10 @@
use super::{Context, Module};
/// Creates a segment for the line break
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const LINE_ENDING: &str = "\n";
- let mut module = context.new_module("line_break");
+ let mut module = context.new_module("line_break")?;
module.get_prefix().set_value("");
module.get_suffix().set_value("");
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index cf1c64018..30a459ef1 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -16,18 +16,18 @@ use crate::module::Module;
pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
match module {
- "dir" | "directory" => directory::segment(context),
- "char" | "character" => character::segment(context),
- "node" | "nodejs" => nodejs::segment(context),
- "rust" | "rustlang" => rust::segment(context),
- "python" => python::segment(context),
- "go" | "golang" => go::segment(context),
- "line_break" => line_break::segment(context),
- "package" => package::segment(context),
- "git_branch" => git_branch::segment(context),
- "git_status" => git_status::segment(context),
- "username" => username::segment(context),
- "battery" => battery::segment(context),
+ "dir" | "directory" => directory::module(context),
+ "char" | "character" => character::module(context),
+ "node" | "nodejs" => nodejs::module(context),
+ "rust" | "rustlang" => rust::module(context),
+ "python" => python::module(context),
+ "go" | "golang" => go::module(context),
+ "line_break" => line_break::module(context),
+ "package" => package::module(context),
+ "git_branch" => git_branch::module(context),
+ "git_status" => git_status::module(context),
+ "username" => username::module(context),
+ "battery" => battery::module(context),
_ => panic!("Unknown module: {}", module),
}
diff --git a/src/modules/nodejs.rs b/src/modules/nodejs.rs
index e542acf1e..9aa5a4376 100644
--- a/src/modules/nodejs.rs
+++ b/src/modules/nodejs.rs
@@ -9,7 +9,7 @@ use super::{Context, Module};
/// - Current directory contains a `.js` file
/// - Current directory contains a `package.json` file
/// - Current directory contains a `node_modules` directory
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_js_project = context
.new_scan_dir()
.set_files(&["package.json"])
@@ -26,7 +26,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
const NODE_CHAR: &str = "โฌข ";
let module_color = Color::Green.bold();
- let mut module = context.new_module("node");
+ let mut module = context.new_module("node")?;
module.set_style(module_color);
let formatted_version = node_version.trim();
diff --git a/src/modules/package.rs b/src/modules/package.rs
index a9af63891..527d5eaec 100644
--- a/src/modules/package.rs
+++ b/src/modules/package.rs
@@ -8,13 +8,13 @@ use toml;
/// Creates a segment with the current package version
///
/// Will display if a version is defined for your Node.js or Rust project (if one exists)
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
match get_package_version() {
Some(package_version) => {
const PACKAGE_CHAR: &str = "๐Ÿ“ฆ ";
let module_color = Color::Red.bold();
- let mut module = context.new_module("package");
+ let mut module = context.new_module("package")?;
module.set_style(module_color);
module.get_prefix().set_value("is ");
@@ -75,19 +75,21 @@ mod tests {
#[test]
fn test_extract_cargo_version() {
- let cargo_with_version = r#"
+ let cargo_with_version = toml::toml! {
[package]
name = "starship"
version = "0.1.0"
- "#;
+ }
+ .to_string();
let expected_version = Some("v0.1.0".to_string());
assert_eq!(extract_cargo_version(&cargo_with_version), expected_version);
- let cargo_without_version = r#"
+ let cargo_without_version = toml::toml! {
[package]
name = "starship"
- "#;
+ }
+ .to_string();
let expected_version = None;
assert_eq!(
diff --git a/src/modules/python.rs b/src/modules/python.rs
index 8b72e5187..a1a36cd3a 100644
--- a/src/modules/python.rs
+++ b/src/modules/python.rs
@@ -10,7 +10,7 @@ use super::{Context, Module};
/// - Current directory contains a `.python-version` file
/// - Current directory contains a `requirements.txt` file
/// - Current directory contains a `pyproject.toml` file
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_py_project = context
.new_scan_dir()
.set_files(&["requirements.txt", ".python-version", "pyproject.toml"])
@@ -26,7 +26,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
const PYTHON_CHAR: &str = "๐Ÿ ";
let module_color = Color::Yellow.bold();
- let mut module = context.new_module("python");
+ let mut module = context.new_module("python")?;
module.set_style(module_color);
let formatted_version = format_python_version(python_version);
diff --git a/src/modules/rust.rs b/src/modules/rust.rs
index 9ccdcc5d2..057344064 100644
--- a/src/modules/rust.rs
+++ b/src/modules/rust.rs
@@ -8,7 +8,7 @@ use super::{Context, Module};
/// Will display the Rust version if any of the following criteria are met:
/// - Current directory contains a file with a `.rs` extension
/// - Current directory contains a `Cargo.toml` file
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_rs_project = context
.new_scan_dir()
.set_files(&["Cargo.toml"])
@@ -24,7 +24,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
const RUST_CHAR: &str = "๐Ÿฆ€ ";
let module_color = Color::Red.bold();
- let mut module = context.new_module("rust");
+ let mut module = context.new_module("rust")?;
module.set_style(module_color);
let formatted_version = format_rustc_version(rust_version);
@@ -38,14 +38,14 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
}
fn get_rust_version() -> Option<String> {
- match Command::new("rustc").arg("-V").output() {
+ match Command::new("rustc").arg("--version").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
Err(_) => None,
}
}
fn format_rustc_version(mut rustc_stdout: String) -> String {
- let offset = &rustc_stdout.find('(').unwrap();
+ let offset = &rustc_stdout.find('(').unwrap_or(rustc_stdout.len());
let formatted_version: String = rustc_stdout.drain(..offset).collect();
format!("v{}", formatted_version.replace("rustc", "").trim())
@@ -65,5 +65,8 @@ mod tests {
let stable_input = String::from("rustc 1.34.0 (91856ed52 2019-04-10)");
assert_eq!(format_rustc_version(stable_input), "v1.34.0");
+
+ let version_without_hash = String::from("rustc 1.34.0");
+ assert_eq!(format_rustc_version(version_without_hash), "v1.34.0");
}
}
diff --git a/src/modules/username.rs b/src/modules/username.rs
index 8885791b9..73295b79e 100644
--- a/src/modules/username.rs
+++ b/src/modules/username.rs
@@ -10,7 +10,7 @@ use super::{Context, Module};
/// - The current user isn't the same as the one that is logged in ($LOGNAME != $USER)
/// - The current user is root (UID = 0)
/// - The user is currently connected as an SSH session ($SSH_CONNECTION)
-pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let user = env::var("USER").ok();
let logname = env::var("LOGNAME").ok();
let ssh_connection = env::var("SSH_CONNECTION").ok();
@@ -18,7 +18,7 @@ pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module_color = Color::Yellow.bold();
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
- let mut module = context.new_module("username");
+ let mut module = context.new_module("username")?;
module.set_style(module_color);
module.new_segment("username", user?);
diff --git a/src/print.rs b/src/print.rs
index 71d453e34..ae712e123 100644
--- a/src/print.rs
+++ b/src/print.rs
@@ -6,21 +6,22 @@ use crate::context::Context;
use crate::module::Module;
use crate::modules;
+const PROMPT_ORDER: &[&str] = &[
+ "battery",
+ "username",
+ "directory",
+ "git_branch",
+ "git_status",
+ "package",
+ "nodejs",
+ "rust",
+ "python",
+ "go",
+ "line_break",
+ "character",
+];
+
pub fn prompt(args: ArgMatches) {
- let prompt_order = vec![
- "battery",
- "username",
- "directory",
- "git_branch",
- "git_status",
- "package",
- "nodejs",
- "rust",
- "python",
- "go",
- "line_break",
- "character",
- ];
let context = Context::new(args);
let stdout = io::stdout();
@@ -29,7 +30,7 @@ pub fn prompt(args: ArgMatches) {
// Write a new line before the prompt
writeln!(handle).unwrap();
- let modules = prompt_order
+ let modules = PROMPT_ORDER
.par_iter()
.map(|module| modules::handle(module, &context)) // Compute modules
.flatten()
diff --git a/tests/fixtures/empty_config.toml b/tests/fixtures/empty_config.toml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/fixtures/empty_config.toml
diff --git a/tests/testsuite/common.rs b/tests/testsuite/common.rs
index 451880288..ee817d8d5 100644
--- a/tests/testsuite/common.rs
+++ b/tests/testsuite/common.rs
@@ -1,15 +1,36 @@
+use lazy_static::lazy_static;
+use std::io::prelude::*;
+use std::path::{Path, PathBuf};
use std::{io, process};
-pub fn render_prompt() -> process::Command {
+lazy_static! {
+ static ref MANIFEST_DIR: &'static Path = Path::new(env!("CARGO_MANIFEST_DIR"));
+ pub static ref FIXTURES_DIR: PathBuf = MANIFEST_DIR.join("tests/fixtures");
+ static ref EMPTY_CONFIG: PathBuf = MANIFEST_DIR.join("empty_config.toml");
+}
+
+/// Run an instance of starship
+fn run_starship() -> process::Command {
let mut command = process::Command::new("./target/debug/starship");
- command.arg("prompt");
+
+ command
+ .arg("prompt")
+ .env_clear()
+ .env("PATH", env!("PATH")) // Provide the $PATH variable so that external programs are runnable
+ .env("STARSHIP_CONFIG", EMPTY_CONFIG.as_os_str());
command
}
pub fn render_module(module_name: &str) -> process::Command {
let mut command = process::Command::new("./target/debug/starship");
- command.arg("module").arg(module_name);
+
+ command
+ .arg("module")
+ .arg(module_name)
+ .env_clear()
+ .env("PATH", env!("PATH")) // Provide the $PATH variable so that external programs are runnable
+ .env("STARSHIP_CONFIG", EMPTY_CONFIG.as_os_str());
command
}
@@ -20,3 +41,21 @@ pub fn new_tempdir() -> io::Result<tempfile::TempDir> {
// "/var/folders", which provides us with restricted permissions (rwxr-xr-x)
tempfile::tempdir_in("/tmp")
}
+
+/// Extends `std::process::Command` with methods for testing
+pub trait TestCommand {
+ fn use_config(&mut self, toml: toml::value::Value) -> &mut process::Command;
+}
+
+impl TestCommand for process::Command {
+ /// Create a configuration file with the provided TOML and use it
+ fn use_config(&mut self, toml: toml::value::Value) -> &mut process::Command {
+ // Create a persistent config file in a tempdir
+ let (mut config_file, config_path) =
+ tempfile::NamedTempFile::new().unwrap().keep().unwrap();
+ write!(config_file, "{}", toml.to_string()).unwrap();
+
+ // Set that newly-created file as the config for the prompt instance
+ self.env("STARSHIP_CONFIG", config_path)
+ }
+}
diff --git a/tests/testsuite/configuration.rs b/tests/testsuite/configuration.rs
new file mode 100644
index 000000000..231e0b99a
--- /dev/null
+++ b/tests/testsuite/configuration.rs
@@ -0,0 +1,34 @@
+use ansi_term::Color;
+use std::io;
+
+use crate::common::{self, TestCommand};
+
+#[test]
+fn char_symbol_configuration() -> io::Result<()> {
+ let expected = format!("{} ", Color::Green.bold().paint("โฏ"));
+
+ let output = common::render_module("char")
+ .use_config(toml::toml! {
+ [char]
+ symbol = "โฏ"
+ })
+ .output()?;
+ let actual = String::from_utf8(output.stdout).unwrap();
+ assert_eq!(expected, actual);
+
+ Ok(())
+}
+
+#[test]
+fn disabled_module() -> io::Result<()> {
+ let output = common::render_module("package")
+ .use_config(toml::toml! {
+ [package]
+ disabled = true
+ })
+ .output()?;
+ let actual = String::from_utf8(output.stdout).unwrap();
+ assert_eq!("", actual);
+
+ Ok(())
+}
diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs
index 1705ae3ae..d7989e7ad 100644
--- a/tests/testsuite/main.rs
+++ b/tests/testsuite/main.rs
@@ -1,5 +1,6 @@
mod character;
mod common;
+mod configuration;
mod directory;
mod golang;
mod line_break;
diff --git a/tests/testsuite/username.rs b/tests/testsuite/username.rs
index ed71e3239..49b1d6377 100644
--- a/