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(())
+}