diff --git a/docs/config/README.md b/docs/config/README.md index c9cf35ca..fdcb07ae 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -14,6 +14,9 @@ $ touch ~/.config/starship.toml All configuration for starship is done in this [TOML](https://github.com/toml-lang/toml) file: ```toml +# Don't print a new line at the start of the prompt +add_newline = false + # Replace the "➜" symbol in the prompt with "❯" [character] # The name of the module we are confguring is "character" symbol = "❯" # The "symbol" segment is being set to "❯" @@ -37,6 +40,24 @@ are segments within it. Every module also has a prefix and suffix that are the d "via " "⬢" "v10.4.1" "" ``` +## Prompt + +This is the list of prompt-wide configuration options. + +### Options + +| Variable | Default | Description| +| `add_newline` | `true` | Add a new line before the start of the prompt | + +### Example + +```toml +# ~/.config/starship.toml + +# Disable the newline at the start of the prompt +add_newline = false +``` + ## Battery The `battery` module shows how charged the device's battery is and its current charging status. diff --git a/src/config.rs b/src/config.rs index f2045a68..d5861b9f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,25 +2,33 @@ use crate::utils; use std::env; use dirs::home_dir; +use toml::value::Table; -pub struct Config { - data: toml::value::Table, +pub trait Config { + fn initialize() -> Table; + fn config_from_file() -> Option; + fn get_module_config(&self, module_name: &str) -> Option<&Table>; + + // Config accessor methods + fn get_as_bool(&self, key: &str) -> Option; + fn get_as_str(&self, key: &str) -> Option<&str>; + + // Internal implementation for accessors + fn get_config(&self, key: &str) -> Option<&toml::value::Value>; } -impl Config { +impl Config for Table { /// Initialize the Config struct - pub fn initialize() -> Config { - if let Some(file_data) = Config::config_from_file() { - return Config { data: file_data }; + fn initialize() -> Table { + if let Some(file_data) = Table::config_from_file() { + return file_data; } - Config { - data: toml::value::Table::new(), - } + Table::new() } /// Create a config from a starship configuration file - fn config_from_file() -> Option { + fn config_from_file() -> Option
{ let file_path = match env::var("STARSHIP_CONFIG") { Ok(path) => { // Use $STARSHIP_CONFIG as the config path if available @@ -55,9 +63,8 @@ impl 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> { + 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); @@ -74,16 +81,7 @@ impl Config { module_config } -} -/// Extends `toml::value::Table` with useful methods -pub trait TableExt { - fn get_config(&self, key: &str) -> Option<&toml::value::Value>; - fn get_as_bool(&self, key: &str) -> Option; - fn get_as_str(&self, key: &str) -> Option<&str>; -} - -impl TableExt for toml::value::Table { /// Get the config value for a given key fn get_config(&self, key: &str) -> Option<&toml::value::Value> { log::trace!("Looking for config key \"{}\"", key); diff --git a/src/context.rs b/src/context.rs index e8ca107f..3e3640ac 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,4 @@ -use crate::config::{Config, TableExt}; +use crate::config::Config; use crate::module::Module; use clap::ArgMatches; @@ -13,7 +13,7 @@ use std::path::PathBuf; /// of the prompt. pub struct Context<'a> { /// The deserialized configuration map from the user's `starship.toml` file. - pub config: Config, + pub config: toml::value::Table, /// The current working directory that starship is being called in. pub current_dir: PathBuf, @@ -51,7 +51,7 @@ impl<'a> Context<'a> { where T: Into, { - let config = Config::initialize(); + let config = toml::value::Table::initialize(); // TODO: Currently gets the physical directory. Get the logical directory. let current_dir = Context::expand_tilde(dir.into()); diff --git a/src/module.rs b/src/module.rs index 3e530c3f..af985ea3 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,4 +1,4 @@ -use crate::config::TableExt; +use crate::config::Config; use crate::segment::Segment; use ansi_term::Style; use ansi_term::{ANSIString, ANSIStrings}; diff --git a/src/print.rs b/src/print.rs index ae712e12..3cd185e4 100644 --- a/src/print.rs +++ b/src/print.rs @@ -2,6 +2,7 @@ use clap::ArgMatches; use rayon::prelude::*; use std::io::{self, Write}; +use crate::config::Config; use crate::context::Context; use crate::module::Module; use crate::modules; @@ -23,12 +24,15 @@ const PROMPT_ORDER: &[&str] = &[ pub fn prompt(args: ArgMatches) { let context = Context::new(args); + let config = &context.config; let stdout = io::stdout(); let mut handle = stdout.lock(); // Write a new line before the prompt - writeln!(handle).unwrap(); + if config.get_as_bool("add_newline") != Some(false) { + writeln!(handle).unwrap(); + } let modules = PROMPT_ORDER .par_iter() diff --git a/tests/testsuite/common.rs b/tests/testsuite/common.rs index ee817d8d..a2bc10f1 100644 --- a/tests/testsuite/common.rs +++ b/tests/testsuite/common.rs @@ -9,8 +9,8 @@ lazy_static! { static ref EMPTY_CONFIG: PathBuf = MANIFEST_DIR.join("empty_config.toml"); } -/// Run an instance of starship -fn run_starship() -> process::Command { +/// Render the full starship prompt +pub fn render_prompt() -> process::Command { let mut command = process::Command::new("./target/debug/starship"); command @@ -22,6 +22,7 @@ fn run_starship() -> process::Command { command } +/// Render a specific starship module by name pub fn render_module(module_name: &str) -> process::Command { let mut command = process::Command::new("./target/debug/starship"); diff --git a/tests/testsuite/configuration.rs b/tests/testsuite/configuration.rs index 189ee365..a9daefb6 100644 --- a/tests/testsuite/configuration.rs +++ b/tests/testsuite/configuration.rs @@ -32,3 +32,24 @@ fn disabled_module() -> io::Result<()> { Ok(()) } + +#[test] +fn add_newline_configuration() -> io::Result<()> { + // Start prompt with newline + let default_output = common::render_prompt().output()?; + let actual = String::from_utf8(default_output.stdout).unwrap(); + let expected = actual.trim_start(); + assert_ne!(actual, expected); + + // Start prompt without newline + let output = common::render_prompt() + .use_config(toml::toml! { + add_newline = false + }) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + let expected = actual.trim_start(); + assert_eq!(expected, actual); + + Ok(()) +}