diff --git a/README.md b/README.md index 66828ef1..14fac360 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@

Starship is the minimal, blazing fast, and extremely customizable prompt for any shell!
-The prompt shows information need while you're working, while staying sleek and out of the way. +The prompt shows information you need while you're working, while staying sleek and out of the way.

Starship with Hyper and One Dark @@ -46,7 +46,7 @@ The prompt shows information need while you're working, while staying sleek and - `»` — renamed files - `✘` — deleted files - Execution time of the last command if it exceeds the set threshold. -- [PLANNED #80](https://github.com/starship/starship/issues/80) – Indicator for jobs in the background (`✦`). +- Indicator for jobs in the background (`✦`). ## 🚀 Installation diff --git a/docs/config/README.md b/docs/config/README.md index 004fe952..8177cec5 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -250,6 +250,29 @@ The module will be shown if any of the following conditions are met: symbol = "🏎💨 " ``` +## Jobs + +The `jobs` module shows the current number of jobs running. +The module will be shown only if there are background jobs running. +The module will show the number of jobs running if there is more than 1 job, or +more than the `threshold` config value, if it exists. + +### Options + +| Variable | Default | Description | +| ----------- | ------- | -------------------------------- | +| `threshold` | `1` | Show number of jobs if execeded. | +| `disabled` | `false` | Disables the `jobs` module. | + +### Example + +```toml +# ~/.config/starship.toml + +[jobs] +threshold = 4 +``` + ## Line Break The `line_break` module separates the prompt into two lines. diff --git a/src/init.rs b/src/init.rs index 3941e92d..a80dcd5c 100644 --- a/src/init.rs +++ b/src/init.rs @@ -58,7 +58,7 @@ https://github.com/starship/starship/issues/124 const BASH_INIT: &str = r##" starship_precmd() { - PS1="$(starship prompt --status=$?)"; + PS1="$(starship prompt --status=$? --jobs=$(jobs -p | wc -l))"; }; PROMPT_COMMAND=starship_precmd; "##; @@ -83,10 +83,10 @@ starship_precmd() { if [[ $STARSHIP_START_TIME ]]; then STARSHIP_END_TIME="$(date +%s)"; STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME)); - PROMPT="$(starship prompt --status=$STATUS --cmd-duration=$STARSHIP_DURATION)"; + PROMPT="$(starship prompt --status=$STATUS --cmd-duration=$STARSHIP_DURATION --jobs=$(jobs | wc -l))"; unset STARSHIP_START_TIME; else - PROMPT="$(starship prompt --status=$STATUS)"; + PROMPT="$(starship prompt --status=$STATUS --jobs=$(jobs | wc -l))"; fi }; starship_preexec(){ @@ -108,6 +108,6 @@ function fish_prompt; set -l exit_code $status; set -l CMD_DURATION "$CMD_DURATION$cmd_duration"; set -l starship_duration (math --scale=0 "$CMD_DURATION / 1000"); - starship prompt --status=$exit_code --cmd-duration=$starship_duration; + starship prompt --status=$exit_code --cmd-duration=$starship_duration --jobs=(count (jobs -p)); end; "##; diff --git a/src/main.rs b/src/main.rs index fa6f1488..c95b5fd2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,13 @@ fn main() { .help("The execution duration of the last command, in seconds") .takes_value(true); + let jobs_arg = Arg::with_name("jobs") + .short("j") + .long("jobs") + .value_name("JOBS") + .help("The number of currently running jobs") + .takes_value(true); + let matches = App::new("starship") .about("The cross-shell prompt for astronauts. ☄🌌️") // pull the version number from Cargo.toml @@ -61,7 +68,8 @@ fn main() { .about("Prints the full starship prompt") .arg(&status_code_arg) .arg(&path_arg) - .arg(&cmd_duration_arg), + .arg(&cmd_duration_arg) + .arg(&jobs_arg), ) .subcommand( SubCommand::with_name("module") @@ -73,7 +81,8 @@ fn main() { ) .arg(&status_code_arg) .arg(&path_arg) - .arg(&cmd_duration_arg), + .arg(&cmd_duration_arg) + .arg(&jobs_arg), ) .get_matches(); diff --git a/src/modules/jobs.rs b/src/modules/jobs.rs new file mode 100644 index 00000000..4a89a1af --- /dev/null +++ b/src/modules/jobs.rs @@ -0,0 +1,32 @@ +use ansi_term::Color; + +use super::{Context, Module}; + +/// Creates a segment to show if there are any active jobs running +pub fn module<'a>(context: &'a Context) -> Option> { + let mut module = context.new_module("jobs")?; + + let threshold = module.config_value_i64("threshold").unwrap_or(1); + + const JOB_CHAR: &str = "✦"; + let module_color = Color::Blue.bold(); + + module.set_style(module_color); + + let arguments = &context.arguments; + let num_of_jobs = arguments + .value_of("jobs") + .unwrap_or("0") + .parse::() + .ok()?; + if num_of_jobs == 0 { + return None; + } + module.new_segment("symbol", JOB_CHAR); + if num_of_jobs > threshold { + module.new_segment("number", &num_of_jobs.to_string()); + } + module.get_prefix().set_value(""); + + Some(module) +} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 5f3fcbba..9171f2a3 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -5,6 +5,7 @@ mod directory; mod git_branch; mod git_status; mod golang; +mod jobs; mod line_break; mod nodejs; mod package; @@ -30,6 +31,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option> { "username" => username::module(context), "battery" => battery::module(context), "cmd_duration" => cmd_duration::module(context), + "jobs" => jobs::module(context), _ => panic!("Unknown module: {}", module), } diff --git a/src/print.rs b/src/print.rs index 400020ba..6526991b 100644 --- a/src/print.rs +++ b/src/print.rs @@ -19,6 +19,7 @@ const PROMPT_ORDER: &[&str] = &[ "go", "cmd_duration", "line_break", + "jobs", "battery", "character", ]; diff --git a/tests/testsuite/jobs.rs b/tests/testsuite/jobs.rs new file mode 100644 index 00000000..885684ab --- /dev/null +++ b/tests/testsuite/jobs.rs @@ -0,0 +1,85 @@ +use ansi_term::Color; +use std::fs; +use std::io; +use std::path::Path; +use tempfile::TempDir; + +use crate::common::{self, TestCommand}; + +#[test] +fn config_blank_job_0() -> io::Result<()> { + let output = common::render_module("jobs").arg("--jobs=0").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = ""; + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn config_blank_job_1() -> io::Result<()> { + let output = common::render_module("jobs").arg("--jobs=1").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("{} ", Color::Blue.bold().paint("✦")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn config_blank_job_2() -> io::Result<()> { + let output = common::render_module("jobs").arg("--jobs=2").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("{} ", Color::Blue.bold().paint("✦2")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn config_2_job_2() -> io::Result<()> { + let output = common::render_module("jobs") + .use_config(toml::toml! { + [jobs] + threshold = 2 + }) + .arg("--jobs=2") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("{} ", Color::Blue.bold().paint("✦")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn config_2_job_3() -> io::Result<()> { + let output = common::render_module("jobs") + .use_config(toml::toml! { + [jobs] + threshold = 2 + }) + .arg("--jobs=3") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("{} ", Color::Blue.bold().paint("✦3")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn config_disabled() -> io::Result<()> { + let output = common::render_module("jobs") + .use_config(toml::toml! { + [jobs] + disabled = true + }) + .arg("--jobs=1") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = ""; + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index ab520117..a2d47ac2 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -4,6 +4,7 @@ mod common; mod configuration; mod directory; mod golang; +mod jobs; mod line_break; mod nodejs; mod python;