mirror of
https://github.com/starship/starship.git
synced 2026-06-23 02:05:51 +07:00
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
This commit is contained in:
@@ -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(_context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(_context: &Context) -> Option<Module> {
|
||||
}
|
||||
|
||||
// TODO: Set style based on percentage when threshold is modifiable
|
||||
let mut module = Module::new("battery");
|
||||
let mut module = context.new_module("battery");
|
||||
module.set_style(Color::Red.bold());
|
||||
module.get_prefix().set_value("");
|
||||
|
||||
|
||||
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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 = Module::new("char");
|
||||
let mut module = context.new_module("char");
|
||||
module.get_prefix().set_value("");
|
||||
|
||||
let symbol = module.new_segment("symbol", PROMPT_CHAR);
|
||||
|
||||
@@ -12,12 +12,12 @@ use super::{Context, Module};
|
||||
///
|
||||
/// **Truncation**
|
||||
/// Paths will be limited in length to `3` path components by default.
|
||||
pub fn segment(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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 = Module::new("directory");
|
||||
let mut module = context.new_module("directory");
|
||||
module.set_style(module_color);
|
||||
|
||||
let current_dir = &context.current_dir;
|
||||
|
||||
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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 = Module::new("git_branch");
|
||||
let mut module = context.new_module("git_branch");
|
||||
module.set_style(segment_color);
|
||||
module.get_prefix().set_value("on ");
|
||||
|
||||
|
||||
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(context: &Context) -> Option<Module> {
|
||||
let repository = Repository::open(repo_root).ok()?;
|
||||
|
||||
let module_style = Color::Red.bold();
|
||||
let mut module = Module::new("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);
|
||||
|
||||
+2
-2
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(context: &Context) -> Option<Module> {
|
||||
const GO_CHAR: &str = "🐹 ";
|
||||
let module_color = Color::Cyan.bold();
|
||||
|
||||
let mut module = Module::new("go");
|
||||
let mut module = context.new_module("go");
|
||||
module.set_style(module_color);
|
||||
|
||||
let formatted_version = format_go_version(go_version)?;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::{Context, Module};
|
||||
|
||||
/// Creates a segment for the line break
|
||||
pub fn segment(_context: &Context) -> Option<Module> {
|
||||
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
const LINE_ENDING: &str = "\n";
|
||||
|
||||
let mut module = Module::new("line_break");
|
||||
let mut module = context.new_module("line_break");
|
||||
|
||||
module.get_prefix().set_value("");
|
||||
module.get_suffix().set_value("");
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ mod username;
|
||||
use crate::context::Context;
|
||||
use crate::module::Module;
|
||||
|
||||
pub fn handle(module: &str, context: &Context) -> Option<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),
|
||||
|
||||
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(context: &Context) -> Option<Module> {
|
||||
const NODE_CHAR: &str = "⬢ ";
|
||||
let module_color = Color::Green.bold();
|
||||
|
||||
let mut module = Module::new("node");
|
||||
let mut module = context.new_module("node");
|
||||
module.set_style(module_color);
|
||||
|
||||
let formatted_version = node_version.trim();
|
||||
|
||||
+25
-45
@@ -1,23 +1,20 @@
|
||||
use super::{Context, Module};
|
||||
use crate::utils;
|
||||
|
||||
use ansi_term::Color;
|
||||
use serde_json;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use serde_json as json;
|
||||
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(context: &Context) -> Option<Module> {
|
||||
match get_package_version(context) {
|
||||
pub fn segment<'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 = Module::new("package");
|
||||
let mut module = context.new_module("package");
|
||||
module.set_style(module_color);
|
||||
module.get_prefix().set_value("is ");
|
||||
|
||||
@@ -30,27 +27,8 @@ pub fn segment(context: &Context) -> Option<Module> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Combine into one function and just call for different file names!
|
||||
fn is_cargo_toml(dir_entry: &PathBuf) -> bool {
|
||||
dir_entry.is_file() && dir_entry.file_name().unwrap_or_default() == "Cargo.toml"
|
||||
}
|
||||
|
||||
fn is_package_json(dir_entry: &PathBuf) -> bool {
|
||||
dir_entry.is_file() && dir_entry.file_name().unwrap_or_default() == "package.json"
|
||||
}
|
||||
|
||||
// TODO: Move to `utils.rs` file and import
|
||||
fn read_file(file_name: &str) -> io::Result<String> {
|
||||
let mut file = File::open(file_name)?;
|
||||
let mut data = String::new();
|
||||
|
||||
file.read_to_string(&mut data)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
||||
let cargo_toml = file_contents.parse::<toml::Value>().ok()?;
|
||||
let cargo_toml: toml::Value = toml::from_str(&file_contents).ok()?;
|
||||
let raw_version = cargo_toml.get("package")?.get("version")?.as_str()?;
|
||||
|
||||
let formatted_version = format_version(raw_version);
|
||||
@@ -58,7 +36,7 @@ fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
||||
}
|
||||
|
||||
fn extract_package_version(file_contents: &str) -> Option<String> {
|
||||
let package_json: serde_json::Value = serde_json::from_str(&file_contents).ok()?;
|
||||
let package_json: json::Value = json::from_str(&file_contents).ok()?;
|
||||
let raw_version = package_json.get("version")?.as_str()?;
|
||||
if raw_version == "null" {
|
||||
return None;
|
||||
@@ -68,17 +46,15 @@ fn extract_package_version(file_contents: &str) -> Option<String> {
|
||||
Some(formatted_version)
|
||||
}
|
||||
|
||||
fn get_package_version(context: &Context) -> Option<String> {
|
||||
let has_cargo_toml = context.dir_files.iter().any(is_cargo_toml);
|
||||
if has_cargo_toml {
|
||||
let file_contents = read_file("Cargo.toml").ok()?;
|
||||
return extract_cargo_version(&file_contents);
|
||||
fn get_package_version() -> Option<String> {
|
||||
let cargo_toml = utils::read_file("Cargo.toml");
|
||||
if let Ok(cargo_toml) = cargo_toml {
|
||||
return extract_cargo_version(&cargo_toml);
|
||||
}
|
||||
|
||||
let has_package_json = context.dir_files.iter().any(is_package_json);
|
||||
if has_package_json {
|
||||
let file_contents = read_file("package.json").ok()?;
|
||||
return extract_package_version(&file_contents);
|
||||
let package_json = utils::read_file("package.json");
|
||||
if let Ok(package_json) = package_json {
|
||||
return extract_package_version(&package_json);
|
||||
}
|
||||
|
||||
None
|
||||
@@ -99,15 +75,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_cargo_version() {
|
||||
let cargo_with_version = "[package]
|
||||
name = \"starship\"
|
||||
version = \"0.1.0\"";
|
||||
let cargo_with_version = r#"
|
||||
[package]
|
||||
name = "starship"
|
||||
version = "0.1.0"
|
||||
"#;
|
||||
|
||||
let expected_version = Some("v0.1.0".to_string());
|
||||
assert_eq!(extract_cargo_version(&cargo_with_version), expected_version);
|
||||
|
||||
let cargo_without_version = "[package]
|
||||
name = \"starship\"";
|
||||
let cargo_without_version = r#"
|
||||
[package]
|
||||
name = "starship"
|
||||
"#;
|
||||
|
||||
let expected_version = None;
|
||||
assert_eq!(
|
||||
@@ -118,7 +98,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_package_version() {
|
||||
let package_with_version = serde_json::json!({
|
||||
let package_with_version = json::json!({
|
||||
"name": "spacefish",
|
||||
"version": "0.1.0"
|
||||
})
|
||||
@@ -130,7 +110,7 @@ mod tests {
|
||||
expected_version
|
||||
);
|
||||
|
||||
let package_without_version = serde_json::json!({
|
||||
let package_without_version = json::json!({
|
||||
"name": "spacefish"
|
||||
})
|
||||
.to_string();
|
||||
|
||||
@@ -10,15 +10,10 @@ 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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let is_py_project = context
|
||||
.new_scan_dir()
|
||||
.set_files(&[
|
||||
"requirements.txt",
|
||||
".python-version",
|
||||
"pyproject.toml",
|
||||
"pyproject.toml",
|
||||
])
|
||||
.set_files(&["requirements.txt", ".python-version", "pyproject.toml"])
|
||||
.set_extensions(&["py"])
|
||||
.scan();
|
||||
|
||||
@@ -31,7 +26,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
||||
const PYTHON_CHAR: &str = "🐍 ";
|
||||
let module_color = Color::Yellow.bold();
|
||||
|
||||
let mut module = Module::new("python");
|
||||
let mut module = context.new_module("python");
|
||||
module.set_style(module_color);
|
||||
|
||||
let formatted_version = format_python_version(python_version);
|
||||
|
||||
+2
-2
@@ -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(context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(context: &Context) -> Option<Module> {
|
||||
const RUST_CHAR: &str = "🦀 ";
|
||||
let module_color = Color::Red.bold();
|
||||
|
||||
let mut module = Module::new("rust");
|
||||
let mut module = context.new_module("rust");
|
||||
module.set_style(module_color);
|
||||
|
||||
let formatted_version = format_rustc_version(rust_version);
|
||||
|
||||
@@ -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(_context: &Context) -> Option<Module> {
|
||||
pub fn segment<'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(_context: &Context) -> Option<Module> {
|
||||
let mut module_color = Color::Yellow.bold();
|
||||
|
||||
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
|
||||
let mut module = Module::new("username");
|
||||
let mut module = context.new_module("username");
|
||||
module.set_style(module_color);
|
||||
module.new_segment("username", user?);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user