From 097f1b05f1d82967fe2a900ccf7ba3597c04ad77 Mon Sep 17 00:00:00 2001 From: Matan Kushner Date: Mon, 10 Jun 2019 15:56:17 +0100 Subject: [PATCH] Add support for prompt configuration (#62) - Create `Config` struct that is added to `Context` when initialized - Read `~/.confg/starship.toml` during initialization (can be updated later to also look at `$XDG_CONFIG_HOME`) - `Context` now has a method for creating modules. This allows us to provide modules with a reference to the configuration specific to that module --- README.md | 6 ++-- ci/azure-test-docker.yml | 6 +++- ci/azure-test-stable.yml | 9 +++-- integration_test | 2 +- src/config.rs | 42 ++++++++++++++++++++++ src/context.rs | 11 ++++++ src/lib.rs | 2 ++ src/main.rs | 2 ++ src/module.rs | 33 ++++++++++++----- src/modules/battery.rs | 4 +-- src/modules/character.rs | 4 +-- src/modules/directory.rs | 4 +-- src/modules/git_branch.rs | 4 +-- src/modules/git_status.rs | 4 +-- src/modules/go.rs | 4 +-- src/modules/line_break.rs | 4 +-- src/modules/mod.rs | 2 +- src/modules/nodejs.rs | 4 +-- src/modules/package.rs | 70 +++++++++++++----------------------- src/modules/python.rs | 11 ++---- src/modules/rust.rs | 4 +-- src/modules/username.rs | 4 +-- src/segment.rs | 65 ++------------------------------- src/utils.rs | 11 ++++++ tests/Dockerfile | 41 +++++++++++---------- tests/testsuite/directory.rs | 4 +-- tests/testsuite/username.rs | 21 ++++++----- 27 files changed, 196 insertions(+), 182 deletions(-) create mode 100644 src/config.rs create mode 100644 src/utils.rs diff --git a/README.md b/README.md index bae3808f..f32fca68 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ I'm very new to Rust, so any help is appreciated when it comes to improving deve ### Other features -- [ ] `.starshiprc` configuration (JSON or TOML) +- [x] `starship.toml` configuration - [ ] Custom sections given commands or binaries - [ ] Self-updating @@ -69,9 +69,9 @@ I'm very new to Rust, so any help is appreciated when it comes to improving deve ### Test strategy -- [x] Per-segment benchmarking +- [ ] Per-segment benchmarking - [x] Per-segment unit + integration tests -- [ ] Shell + OS matrix acceptance tests +- [x] Shell + OS matrix acceptance tests ## Setup diff --git a/ci/azure-test-docker.yml b/ci/azure-test-docker.yml index 22df04cb..99a7d507 100644 --- a/ci/azure-test-docker.yml +++ b/ci/azure-test-docker.yml @@ -8,7 +8,11 @@ jobs: - script: docker pull starshipcommand/starship-test displayName: Pull docker image - - script: ./integration_test + - script: | + # In order to run tests as a non-root user in docker, + # the files need to be accessible to non-root users + chmod -R a+w . + ./integration_test displayName: Run integration test suite - script: | diff --git a/ci/azure-test-stable.yml b/ci/azure-test-stable.yml index 031b6939..9c445bf5 100644 --- a/ci/azure-test-stable.yml +++ b/ci/azure-test-stable.yml @@ -7,8 +7,10 @@ jobs: vmImage: ubuntu-16.04 MacOS: vmImage: macOS-10.13 - Windows: - vmImage: vs2017-win2016 + # # Temporarily disabling Windows tests while I'm away + # # Will reenable Windows tests once I'm able to troubleshoot Windows bugs + # Windows: + # vmImage: vs2017-win2016 pool: vmImage: $(vmImage) @@ -19,5 +21,6 @@ jobs: - template: azure-setup-test-env.yml - - script: cargo test -- --ignored + # "-Z unstable-options" is required for "--include-ignored" + - script: cargo test -- -Z unstable-options --include-ignored displayName: cargo test diff --git a/integration_test b/integration_test index cf91a213..93a6466d 100755 --- a/integration_test +++ b/integration_test @@ -13,4 +13,4 @@ docker build -f tests/Dockerfile \ . printf 'Running test suite:\n' -docker run --rm -v $(pwd):/starship starshipcommand/starship-test +docker run --rm -v $(pwd):/src/starship starshipcommand/starship-test diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 00000000..7c0509a2 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,42 @@ +use crate::utils; + +use dirs::home_dir; + +pub struct Config { + data: toml::value::Table, +} + +impl Config { + /// Initialize the Config struct + pub fn initialize() -> Config { + if let Some(file_data) = Config::config_from_file() { + return Config { data: file_data }; + } + + Config { + data: toml::value::Table::new(), + } + } + + /// Create a config from a starship configuration file + fn config_from_file() -> Option { + 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 config = toml::from_str(&toml_content).ok()?; + log::debug!("Config found: \n{:?}", &config); + Some(config) + } + + /// Get the subset of the table for a module by its name + pub fn get_module_config(&self, module_name: &str) -> Option<&toml::value::Table> { + let module_config = self + .data + .get(module_name) + .map(toml::Value::as_table) + .unwrap_or(None); + log::debug!("Config found for {}: {:?}", &module_name, &module_config); + module_config + } +} diff --git a/src/context.rs b/src/context.rs index e0e7e286..fd0ccc82 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,3 +1,6 @@ +use crate::config::Config; +use crate::module::Module; + use clap::ArgMatches; use git2::Repository; use std::env; @@ -6,6 +9,7 @@ use std::fs; use std::path::PathBuf; pub struct Context<'a> { + pub config: Config, pub current_dir: PathBuf, pub dir_files: Vec, pub arguments: ArgMatches<'a>, @@ -28,6 +32,8 @@ impl<'a> Context<'a> { where T: Into, { + let config = Config::initialize(); + // TODO: Currently gets the physical directory. Get the logical directory. let current_dir = Context::expand_tilde(dir.into()); @@ -51,6 +57,7 @@ impl<'a> Context<'a> { .and_then(|repo| get_current_branch(&repo)); Context { + config, arguments, current_dir, dir_files, @@ -68,6 +75,10 @@ impl<'a> Context<'a> { dir } + pub fn new_module(&self, name: &str) -> Module { + Module::new(name, self.config.get_module_config(name)) + } + // returns a new ScanDir struct with reference to current dir_files of context // see ScanDir for methods pub fn new_scan_dir(&'a self) -> ScanDir<'a> { diff --git a/src/lib.rs b/src/lib.rs index 078fcd02..b8bef9af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ // Lib is present to allow for benchmarking +mod config; pub mod context; pub mod module; pub mod modules; pub mod print; pub mod segment; +mod utils; diff --git a/src/main.rs b/src/main.rs index 4707cd81..70f68e2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,13 @@ #[macro_use] extern crate clap; +mod config; mod context; mod module; mod modules; mod print; mod segment; +mod utils; use clap::{App, Arg, SubCommand}; diff --git a/src/module.rs b/src/module.rs index 43ff78c1..604258e1 100644 --- a/src/module.rs +++ b/src/module.rs @@ -6,7 +6,10 @@ use std::string::ToString; /// A module is a collection of segments showing data for a single integration /// (e.g. The git module shows the current git branch and status) -pub struct Module { +pub struct Module<'a> { + /// The module's configuration map if available + config: Option<&'a toml::value::Table>, + /// The module's name, to be used in configuration and logging. name: String, @@ -23,10 +26,11 @@ pub struct Module { suffix: ModuleAffix, } -impl Module { +impl<'a> Module<'a> { /// Creates a module with no segments. - pub fn new(name: &str) -> Module { + pub fn new(name: &str, config: Option<&'a toml::value::Table>) -> Module<'a> { Module { + config, name: name.to_string(), style: Style::default(), prefix: ModuleAffix::default_prefix(name.to_string()), @@ -42,7 +46,8 @@ impl Module { { let mut segment = Segment::new(name); segment.set_style(self.style); - segment.set_value(value.into()); + // Use the provided value unless overwritten by config + segment.set_value(self.config_value(name).unwrap_or_else(|| value.into())); self.segments.push(segment); self.segments.last_mut().unwrap() @@ -66,7 +71,7 @@ impl Module { /// Sets the style of the segment. /// /// Accepts either `Color` or `Style`. - pub fn set_style(&mut self, style: T) -> &mut Module + pub fn set_style(&mut self, style: T) -> &mut Module<'a> where T: Into