From cea1a1ceb1636b8941b3c8e7bdd8d6284d737281 Mon Sep 17 00:00:00 2001 From: David Knaack Date: Sun, 4 Jul 2021 21:32:58 +0200 Subject: [PATCH] feat: add support for nu shell (#2847) --- Cargo.lock | 24 +++++++++++++----------- Cargo.toml | 2 +- README.md | 14 ++++++++++++++ docs/README.md | 17 +++++++++++++++++ docs/config/README.md | 6 +++--- src/bug_report.rs | 14 ++++++++++---- src/config.rs | 2 +- src/configs/shell.rs | 2 ++ src/configure.rs | 3 ++- src/context.rs | 8 +++++--- src/init/mod.rs | 4 ++++ src/init/starship.nu | 8 ++++++++ src/logger.rs | 3 ++- src/main.rs | 2 +- src/modules/directory.rs | 2 +- src/modules/shell.rs | 30 ++++++++++++++++++++++++++++++ src/utils.rs | 6 +++++- 17 files changed, 119 insertions(+), 28 deletions(-) create mode 100644 src/init/starship.nu diff --git a/Cargo.lock b/Cargo.lock index 5598f949..aae8690c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ahash" version = "0.4.7" @@ -383,6 +385,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + [[package]] name = "dirs" version = "1.0.5" @@ -394,16 +406,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1692,7 +1694,7 @@ dependencies = [ "byte-unit", "chrono", "clap", - "dirs-next", + "directories-next", "gethostname", "git2", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index 2acce319..fa323738 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ tls-vendored = ["native-tls/vendored"] [dependencies] clap = "2.33.3" ansi_term = "0.12.1" -dirs-next = "2.0.0" +directories-next = "2.0.0" git2 = { version = "0.13.20", default-features = false } toml = { version = "0.5.8", features = ["preserve_order"] } rust-ini = "0.17.0" diff --git a/README.md b/README.md index 0da15fb7..58428022 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,20 @@ shown below. Can't see yours? Have a look at the [extra platform instructions](h eval `starship init tcsh` ``` + #### Nushell + + **Warning** This will change in the future. Only nu version v0.33 or higher is supported. + Add the following to your nu config file: + + ```toml + startup = [ + "mkdir ~/.cache/starship", + "starship init nu | save ~/.cache/starship/init.nu", + "source ~/.cache/starship/init.nu" + ] + prompt = "starship_prompt" + ``` + ## 🤝 Contributing We are always looking for contributors of **all skill levels**! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/starship/starship/labels/🌱%20good%20first%20issue). diff --git a/docs/README.md b/docs/README.md index accda478..22ab3f01 100644 --- a/docs/README.md +++ b/docs/README.md @@ -129,3 +129,20 @@ description: Starship is the minimal, blazing fast, and extremely customizable p eval `starship init tcsh` ``` + + #### Nushell + + ::: warning + This will change in the future. + Only nu version v0.33 or higher is supported. + ::: + Add the following to your nu config file: + + ```toml + startup = [ + "mkdir ~/.cache/starship", + "starship init nu | save ~/.cache/starship/init.nu", + "source ~/.cache/starship/init.nu" + ] + prompt = "starship_prompt" + ``` diff --git a/docs/config/README.md b/docs/config/README.md index 522b3d9b..b7d62422 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -413,7 +413,7 @@ look at [this example](#with-custom-error-shape). ::: warning -`error_symbol` is not supported on elvish shell. +`error_symbol` is not supported on elvish and nu shell. ::: @@ -1487,7 +1487,7 @@ then the module will also show when there are 0 jobs running. ::: warning -This module is not supported on tcsh. +This module is not supported on tcsh and nu. ::: @@ -2624,7 +2624,7 @@ To enable it, set `disabled` to `false` in your configuration file. ::: ::: warning -This module is not supported on elvish shell. +This module is not supported on elvish and nu shell. ::: ### Options diff --git a/src/bug_report.rs b/src/bug_report.rs index 943a146f..82a76b61 100644 --- a/src/bug_report.rs +++ b/src/bug_report.rs @@ -1,6 +1,7 @@ use crate::shadow; -use crate::utils::exec_cmd; +use crate::utils::{self, exec_cmd}; +use directories_next::ProjectDirs; use std::fs; use std::path::PathBuf; use std::time::Duration; @@ -191,7 +192,12 @@ fn get_terminal_info() -> TerminalInfo { } fn get_config_path(shell: &str) -> Option { - dirs_next::home_dir().and_then(|home_dir| { + if shell == "nu" { + return ProjectDirs::from("org", "nushell", "nu") + .map(|project_dirs| project_dirs.config_dir().join("config.toml")); + } + + utils::home_dir().and_then(|home_dir| { match shell { "bash" => Some(".bashrc"), "fish" => Some(".config/fish/config.fish"), @@ -217,7 +223,7 @@ fn get_starship_config() -> String { .map(PathBuf::from) .ok() .or_else(|| { - dirs_next::home_dir().map(|mut home_dir| { + utils::home_dir().map(|mut home_dir| { home_dir.push(".config/starship.toml"); home_dir }) @@ -276,7 +282,7 @@ mod tests { fn test_get_config_path() { let config_path = get_config_path("bash"); assert_eq!( - dirs_next::home_dir().unwrap().join(".bashrc"), + utils::home_dir().unwrap().join(".bashrc"), config_path.unwrap() ); } diff --git a/src/config.rs b/src/config.rs index 55e7da86..1f002efc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -226,7 +226,7 @@ impl StarshipConfig { } else { // Default to using ~/.config/starship.toml log::debug!("STARSHIP_CONFIG is not set"); - let config_path = dirs_next::home_dir()?.join(".config/starship.toml"); + let config_path = utils::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 diff --git a/src/configs/shell.rs b/src/configs/shell.rs index 6be8b13a..2f0fc6d1 100644 --- a/src/configs/shell.rs +++ b/src/configs/shell.rs @@ -13,6 +13,7 @@ pub struct ShellConfig<'a> { pub ion_indicator: &'a str, pub elvish_indicator: &'a str, pub tcsh_indicator: &'a str, + pub nu_indicator: &'a str, pub unknown_indicator: &'a str, pub disabled: bool, } @@ -28,6 +29,7 @@ impl<'a> Default for ShellConfig<'a> { ion_indicator: "ion", elvish_indicator: "esh", tcsh_indicator: "tsh", + nu_indicator: "nu", unknown_indicator: "", disabled: true, } diff --git a/src/configure.rs b/src/configure.rs index aa2fba4d..b524845e 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -6,6 +6,7 @@ use std::process::Command; use crate::config::RootModuleConfig; use crate::config::StarshipConfig; +use crate::utils; use std::fs::File; use std::io::Write; use toml::map::Map; @@ -178,7 +179,7 @@ fn get_config_path() -> OsString { if let Some(config_path) = env::var_os("STARSHIP_CONFIG") { return config_path; } - dirs_next::home_dir() + utils::home_dir() .expect("couldn't find home directory") .join(".config") .join("starship.toml") diff --git a/src/context.rs b/src/context.rs index 4a00bba6..df88636a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -3,8 +3,8 @@ use crate::module::Module; use crate::utils::{exec_cmd, CommandOutput}; use crate::modules; +use crate::utils::{self, home_dir}; use clap::ArgMatches; -use dirs_next::home_dir; use git2::{ErrorCode::UnbornBranch, Repository, RepositoryState}; use once_cell::sync::OnceCell; use std::collections::{HashMap, HashSet}; @@ -168,7 +168,7 @@ impl<'a> Context<'a> { pub fn expand_tilde(dir: PathBuf) -> PathBuf { if dir.starts_with("~") { let without_home = dir.strip_prefix("~").unwrap(); - return dirs_next::home_dir().unwrap().join(without_home); + return utils::home_dir().unwrap().join(without_home); } dir } @@ -256,6 +256,7 @@ impl<'a> Context<'a> { "zsh" => Shell::Zsh, "elvish" => Shell::Elvish, "tcsh" => Shell::Tcsh, + "nu" => Shell::Nu, _ => Shell::Unknown, } } @@ -492,6 +493,7 @@ pub enum Shell { Zsh, Elvish, Tcsh, + Nu, Unknown, } @@ -621,7 +623,7 @@ mod tests { #[test] fn context_constructor_should_fall_back_to_tilde_replacement_when_canonicalization_fails() { - use dirs_next::home_dir; + use utils::home_dir; // Mock navigation to a directory which does not exist on disk let test_path = Path::new("~/path_which_does_not_exist").to_path_buf(); diff --git a/src/init/mod.rs b/src/init/mod.rs index ed9c6153..dfe360b4 100644 --- a/src/init/mod.rs +++ b/src/init/mod.rs @@ -168,6 +168,7 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> { r#"eval `({} init tcsh --print-full-init)`"#, starship.sprint_posix()? ), + "nu" => print_script(NU_INIT, &StarshipPath::init()?.sprint_posix()?), _ => { let quoted_arg = shell_words::quote(shell_basename); println!( @@ -180,6 +181,7 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> { * powershell\\n\ * tcsh\\n\ * zsh\\n\ + * nu\\n\ \\n\ Please open an issue in the starship repo if you would like to \ see support for %s:\\nhttps://github.com/starship/starship/issues/new\\n\\n\" {0} {0}", @@ -248,6 +250,8 @@ const ELVISH_INIT: &str = include_str!("starship.elv"); const TCSH_INIT: &str = include_str!("starship.tcsh"); +const NU_INIT: &str = include_str!("starship.nu"); + #[cfg(test)] mod tests { use super::*; diff --git a/src/init/starship.nu b/src/init/starship.nu new file mode 100644 index 00000000..9eb40a84 --- /dev/null +++ b/src/init/starship.nu @@ -0,0 +1,8 @@ +let-env STARSHIP_SHELL = "nu" +let-env STARSHIP_SESSION = (random chars -l 16) + +def starship_prompt [] { + # jobs are not supported + # status is not supported + ^::STARSHIP:: prompt --cmd-duration $nu.env.CMD_DURATION_MS +} diff --git a/src/logger.rs b/src/logger.rs index da8e31b8..216091f2 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,3 +1,4 @@ +use crate::utils; use ansi_term::Color; use log::{Level, LevelFilter, Metadata, Record}; use once_cell::sync::OnceCell; @@ -22,7 +23,7 @@ impl Default for StarshipLogger { let log_dir = env::var_os("STARSHIP_CACHE") .map(PathBuf::from) .unwrap_or_else(|| { - dirs_next::home_dir() + utils::home_dir() .expect("Unable to find home directory") .join(".cache/starship") }); diff --git a/src/main.rs b/src/main.rs index 514097a7..20b9d411 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ fn main() { let shell_arg = Arg::with_name("shell") .value_name("SHELL") .help( - "The name of the currently running shell\nCurrently supported options: bash, zsh, fish, powershell, ion, elvish, tcsh", + "The name of the currently running shell\nCurrently supported options: bash, zsh, fish, powershell, ion, elvish, tcsh, nu", ) .required(true); diff --git a/src/modules/directory.rs b/src/modules/directory.rs index 939e824a..879bc663 100644 --- a/src/modules/directory.rs +++ b/src/modules/directory.rs @@ -298,8 +298,8 @@ fn to_fish_style(pwd_dir_length: usize, dir_string: String, truncated_dir_string mod tests { use super::*; use crate::test::ModuleRenderer; + use crate::utils::home_dir; use ansi_term::Color; - use dirs_next::home_dir; #[cfg(not(target_os = "windows"))] use std::os::unix::fs::symlink; #[cfg(target_os = "windows")] diff --git a/src/modules/shell.rs b/src/modules/shell.rs index 02c9be41..d8a5f8e0 100644 --- a/src/modules/shell.rs +++ b/src/modules/shell.rs @@ -24,6 +24,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { Shell::Ion => Some(config.ion_indicator), Shell::Elvish => Some(config.elvish_indicator), Shell::Tcsh => Some(config.tcsh_indicator), + Shell::Nu => Some(config.nu_indicator), Shell::Unknown => Some(config.unknown_indicator), }, _ => None, @@ -249,6 +250,35 @@ mod tests { assert_eq!(expected, actual); } + #[test] + fn test_nu_default_format() { + let expected = Some(format!("{} ", "nu")); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Nu) + .config(toml::toml! { + [shell] + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + + #[test] + fn test_nu_custom_format() { + let expected = Some(format!("{} ", Color::Cyan.bold().paint("nu"))); + let actual = ModuleRenderer::new("shell") + .shell(Shell::Nu) + .config(toml::toml! { + [shell] + nu_indicator = "[nu](bold cyan)" + disabled = false + }) + .collect(); + + assert_eq!(expected, actual); + } + #[test] fn test_custom_format_conditional_indicator_match() { let expected = Some(format!("{} ", "B")); diff --git a/src/utils.rs b/src/utils.rs index 67265c9c..def0a5fa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,7 +2,7 @@ use process_control::{ChildExt, Timeout}; use std::fmt::Debug; use std::fs::read_to_string; use std::io::Result; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; @@ -414,6 +414,10 @@ fn render_time_component((component, suffix): (&u128, &&str)) -> String { } } +pub fn home_dir() -> Option { + directories_next::BaseDirs::new().map(|base_dirs| base_dirs.home_dir().to_owned()) +} + #[cfg(test)] mod tests { use super::*;