From 6a2b0a67b0ad8143f223f7abc6562ac839875b88 Mon Sep 17 00:00:00 2001 From: Luca Rinaldi Date: Thu, 19 Dec 2019 14:38:06 -0800 Subject: [PATCH] feat: cmd_duration module optionally reports milliseconds (#696) --- docs/config/README.md | 37 +++++++++++++++++---------------- src/configs/cmd_duration.rs | 4 +++- src/init/starship.bash | 17 +++++++++------ src/init/starship.fish | 3 +-- src/init/starship.ps1 | 2 +- src/init/starship.zsh | 6 +++--- src/main.rs | 18 +++++++++++++++- src/modules/cmd_duration.rs | 34 ++++++++++++++++++++---------- tests/testsuite/cmd_duration.rs | 16 +++++++------- 9 files changed, 86 insertions(+), 51 deletions(-) diff --git a/docs/config/README.md b/docs/config/README.md index b5519cee..9ca73a8a 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -270,12 +270,13 @@ running `eval $(starship init $0)`, and then proceed as normal. ### Options -| Variable | Default | Description | -| ---------- | --------------- | ---------------------------------------------------------- | -| `min_time` | `2` | Shortest duration to show time for. | -| `prefix` | `took` | Prefix to display immediately before the command duration. | -| `style` | `"bold yellow"` | The style for the module. | -| `disabled` | `false` | Disables the `cmd_duration` module. | +| Variable | Default | Description | +| ------------------- | --------------- | ---------------------------------------------------------- | +| `min_time` | `2_000` | Shortest duration to show time for (in milliseconds). | +| `show_milliseconds` | `false` | Show milliseconds in addition to seconds for the duration. | +| `prefix` | `took` | Prefix to display immediately before the command duration. | +| `style` | `"bold yellow"` | The style for the module. | +| `disabled` | `false` | Disables the `cmd_duration` module. | ### Example @@ -283,7 +284,7 @@ running `eval $(starship init $0)`, and then proceed as normal. # ~/.config/starship.toml [cmd_duration] -min_time = 4 +min_time = 500 prefix = "underwent " ``` @@ -299,12 +300,12 @@ This does not suppress conda's own prompt modifier, you may want to run `conda c ### Options -| Variable | Default | Description | -| ------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Variable | Default | Description | +| ------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `truncation_length` | `1` | The number of directories the environment path should be truncated to, if the environment was created via `conda create -p [path]`. `0` means no truncation. Also see the [`directory`](#directory) module. | -| `symbol` | `"C "` | The symbol used before the environment name. | -| `style` | `"bold green"` | The style for the module. | -| `disabled` | `false` | Disables the `conda` module. | +| `symbol` | `"C "` | The symbol used before the environment name. | +| `style` | `"bold green"` | The style for the module. | +| `disabled` | `false` | Disables the `conda` module. | ### Example @@ -1010,12 +1011,12 @@ The module will be shown if any of the following conditions are met: ### Options -| Variable | Default | Description | -| -------------- | ------------- | ----------------------------------------------------------- | -| `symbol` | `"💠 "` | The symbol used before displaying the terraform workspace. | -| `show_version` | `false` | Shows the terraform version. Very slow on large workspaces. | -| `style` | `"bold 105"` | The style for the module. | -| `disabled` | `false` | Disables the `terraform` module. | +| Variable | Default | Description | +| -------------- | ------------ | ----------------------------------------------------------- | +| `symbol` | `"💠 "` | The symbol used before displaying the terraform workspace. | +| `show_version` | `false` | Shows the terraform version. Very slow on large workspaces. | +| `style` | `"bold 105"` | The style for the module. | +| `disabled` | `false` | Disables the `terraform` module. | ### Example diff --git a/src/configs/cmd_duration.rs b/src/configs/cmd_duration.rs index 2cf7a85a..f6039015 100644 --- a/src/configs/cmd_duration.rs +++ b/src/configs/cmd_duration.rs @@ -8,14 +8,16 @@ pub struct CmdDurationConfig<'a> { pub min_time: i64, pub prefix: &'a str, pub style: Style, + pub show_milliseconds: bool, pub disabled: bool, } impl<'a> RootModuleConfig<'a> for CmdDurationConfig<'a> { fn new() -> Self { CmdDurationConfig { - min_time: 2, + min_time: 2_000, prefix: "took ", + show_milliseconds: false, style: Color::Yellow.bold(), disabled: false, } diff --git a/src/init/starship.bash b/src/init/starship.bash index cf7b30db..9b488617 100644 --- a/src/init/starship.bash +++ b/src/init/starship.bash @@ -20,7 +20,7 @@ starship_preexec() { # Avoid restarting the timer for commands in the same pipeline if [ "$PREEXEC_READY" = "true" ]; then PREEXEC_READY=false - STARSHIP_START_TIME=$(date +%s) + STARSHIP_START_TIME=$(::STARSHIP:: time) fi : "$PREV_LAST_ARG" @@ -36,7 +36,7 @@ starship_precmd() { # Prepare the timer data, if needed. if [[ $STARSHIP_START_TIME ]]; then - STARSHIP_END_TIME=$(date +%s) + STARSHIP_END_TIME=$(::STARSHIP:: time) STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME)) PS1="$(::STARSHIP:: prompt --status=$STATUS --jobs="$(jobs -p | wc -l)" --cmd-duration=$STARSHIP_DURATION)" unset STARSHIP_START_TIME @@ -64,11 +64,16 @@ else } trap 'starship_preexec_all "$_"' DEBUG fi - - # Finally, prepare the precmd function and set up the start time. - PROMPT_COMMAND="starship_precmd;$PROMPT_COMMAND" + + # Finally, prepare the precmd function and set up the start time. We will avoid to + # add multiple instances of the starship function and keep other user functions if any. + if [[ -z "$PROMPT_COMMAND" ]]; then + PROMPT_COMMAND="starship_precmd" + elif [[ "$PROMPT_COMMAND" != *"starship_precmd" ]]; then + PROMPT_COMMAND="$PROMPT_COMMAND;starship_precmd" + fi fi # Set up the start time and STARSHIP_SHELL, which controls shell-specific sequences -STARSHIP_START_TIME=$(date +%s) +STARSHIP_START_TIME=$(::STARSHIP:: time) export STARSHIP_SHELL="bash" \ No newline at end of file diff --git a/src/init/starship.fish b/src/init/starship.fish index e8347108..6daa473d 100644 --- a/src/init/starship.fish +++ b/src/init/starship.fish @@ -7,8 +7,7 @@ function fish_prompt end set -l exit_code $status # Account for changes in variable name between v2.7 and v3.0 - set -l CMD_DURATION "$CMD_DURATION$cmd_duration" - set -l starship_duration (math --scale=0 "$CMD_DURATION / 1000") + set -l starship_duration "$CMD_DURATION$cmd_duration" ::STARSHIP:: prompt --status=$exit_code --keymap=$keymap --cmd-duration=$starship_duration --jobs=(count (jobs -p)) end diff --git a/src/init/starship.ps1 b/src/init/starship.ps1 index cab90cee..0ae42c78 100644 --- a/src/init/starship.ps1 +++ b/src/init/starship.ps1 @@ -8,7 +8,7 @@ function global:prompt { $jobs = @(Get-Job | Where-Object { $_.State -eq 'Running' }).Count if ($lastCmd = Get-History -Count 1) { - $duration = [math]::Round(($lastCmd.EndExecutionTime - $lastCmd.StartExecutionTime).TotalSeconds) + $duration = [math]::Round(($lastCmd.EndExecutionTime - $lastCmd.StartExecutionTime).TotalMilliseconds) # & ensures the path is interpreted as something to execute $out = @(&::STARSHIP:: prompt "--path=$PWD" --status=$lastexitcode --jobs=$jobs --cmd-duration=$duration) } else { diff --git a/src/init/starship.zsh b/src/init/starship.zsh index fdae70e1..c4cdccf8 100644 --- a/src/init/starship.zsh +++ b/src/init/starship.zsh @@ -19,7 +19,7 @@ starship_precmd() { NUM_JOBS=$#jobstates # Compute cmd_duration, if we have a time to consume if [[ ! -z "${STARSHIP_START_TIME+1}" ]]; then - STARSHIP_END_TIME="$(date +%s)" + STARSHIP_END_TIME=$(::STARSHIP:: time) STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME)) PROMPT="$(::STARSHIP:: prompt --status=$STATUS --cmd-duration=$STARSHIP_DURATION --jobs="$NUM_JOBS")" unset STARSHIP_START_TIME @@ -28,7 +28,7 @@ starship_precmd() { fi } starship_preexec(){ - STARSHIP_START_TIME="$(date +%s)" + STARSHIP_START_TIME=$(::STARSHIP:: time) } # If precmd/preexec arrays are not already set, set them. If we don't do this, @@ -53,6 +53,6 @@ function zle-keymap-select zle reset-prompt } -STARSHIP_START_TIME="$(date +%s)" +STARSHIP_START_TIME=$(::STARSHIP:: time) zle -N zle-keymap-select export STARSHIP_SHELL="zsh" diff --git a/src/main.rs b/src/main.rs index 2f995f0d..9fb1e0fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::time::SystemTime; + #[macro_use] extern crate clap; @@ -44,7 +46,7 @@ fn main() { .short("d") .long("cmd-duration") .value_name("CMD_DURATION") - .help("The execution duration of the last command, in seconds") + .help("The execution duration of the last command, in milliseconds") .takes_value(true); let keymap_arg = Arg::with_name("keymap") @@ -115,6 +117,11 @@ fn main() { .subcommand(SubCommand::with_name("bug-report").about( "Create a pre-populated GitHub issue with information about your configuration", )) + .subcommand( + SubCommand::with_name("time") + .about("Prints time in milliseconds") + .settings(&[AppSettings::Hidden]), + ) .get_matches(); match matches.subcommand() { @@ -141,6 +148,15 @@ fn main() { } ("configure", Some(_)) => configure::edit_configuration(), ("bug-report", Some(_)) => bug_report::create(), + ("time", _) => { + match SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .ok() + { + Some(time) => println!("{}", time.as_millis()), + None => println!("{}", -1), + } + } _ => {} } } diff --git a/src/modules/cmd_duration.rs b/src/modules/cmd_duration.rs index 938549f6..6c13798d 100644 --- a/src/modules/cmd_duration.rs +++ b/src/modules/cmd_duration.rs @@ -15,7 +15,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { let elapsed = props .get("cmd_duration") .unwrap_or(&"invalid_time".into()) - .parse::() + .parse::() .ok()?; /* TODO: Once error handling is implemented, warn the user if their config @@ -28,7 +28,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { return None; } - let config_min = config.min_time as u64; + let config_min = config.min_time as u128; let module_color = match elapsed { time if time < config_min => return None, @@ -36,7 +36,11 @@ pub fn module<'a>(context: &'a Context) -> Option> { }; module.set_style(module_color); - let cmd_duration_stacked = &format!("{}{}", config.prefix, render_time(elapsed)); + let cmd_duration_stacked = &format!( + "{}{}", + config.prefix, + render_time(elapsed, config.show_milliseconds) + ); module.create_segment("cmd_duration", &SegmentConfig::new(&cmd_duration_stacked)); module.get_prefix().set_value(""); @@ -44,8 +48,9 @@ pub fn module<'a>(context: &'a Context) -> Option> { } // Render the time into a nice human-readable string -fn render_time(raw_seconds: u64) -> String { - // Calculate a simple breakdown into days/hours/minutes/seconds +fn render_time(raw_millis: u128, show_millis: bool) -> String { + // Calculate a simple breakdown into days/hours/minutes/seconds/milliseconds + let (millis, raw_seconds) = (raw_millis % 1000, raw_millis / 1000); let (seconds, raw_minutes) = (raw_seconds % 60, raw_seconds / 60); let (minutes, raw_hours) = (raw_minutes % 60, raw_minutes / 60); let (hours, days) = (raw_hours % 24, raw_hours / 24); @@ -53,16 +58,19 @@ fn render_time(raw_seconds: u64) -> String { let components = [days, hours, minutes, seconds]; let suffixes = ["d", "h", "m", "s"]; - let rendered_components: Vec = components + let mut rendered_components: Vec = components .iter() .zip(&suffixes) .map(render_time_component) .collect(); + if show_millis || raw_millis < 1000 { + rendered_components.push(render_time_component((&millis, &"ms"))); + } rendered_components.join("") } /// Render a single component of the time string, giving an empty string if component is zero -fn render_time_component((component, suffix): (&u64, &&str)) -> String { +fn render_time_component((component, suffix): (&u128, &&str)) -> String { match component { 0 => String::new(), n => format!("{}{}", n, suffix), @@ -73,20 +81,24 @@ fn render_time_component((component, suffix): (&u64, &&str)) -> String { mod tests { use super::*; + #[test] + fn test_500ms() { + assert_eq!(render_time(500 as u128, true), "500ms") + } #[test] fn test_10s() { - assert_eq!(render_time(10 as u64), "10s") + assert_eq!(render_time(10_000 as u128, true), "10s") } #[test] fn test_90s() { - assert_eq!(render_time(90 as u64), "1m30s") + assert_eq!(render_time(90_000 as u128, true), "1m30s") } #[test] fn test_10110s() { - assert_eq!(render_time(10110 as u64), "2h48m30s") + assert_eq!(render_time(10_110_000 as u128, true), "2h48m30s") } #[test] fn test_1d() { - assert_eq!(render_time(86400 as u64), "1d") + assert_eq!(render_time(86_400_000 as u128, true), "1d") } } diff --git a/tests/testsuite/cmd_duration.rs b/tests/testsuite/cmd_duration.rs index c498f4e0..d2a996a6 100644 --- a/tests/testsuite/cmd_duration.rs +++ b/tests/testsuite/cmd_duration.rs @@ -6,7 +6,7 @@ use crate::common::{self, TestCommand}; #[test] fn config_blank_duration_1s() -> io::Result<()> { let output = common::render_module("cmd_duration") - .arg("--cmd-duration=1") + .arg("--cmd-duration=1000") .output()?; let actual = String::from_utf8(output.stdout).unwrap(); @@ -18,7 +18,7 @@ fn config_blank_duration_1s() -> io::Result<()> { #[test] fn config_blank_duration_5s() -> io::Result<()> { let output = common::render_module("cmd_duration") - .arg("--cmd-duration=5") + .arg("--cmd-duration=5000") .output()?; let actual = String::from_utf8(output.stdout).unwrap(); @@ -32,9 +32,9 @@ fn config_5s_duration_3s() -> io::Result<()> { let output = common::render_module("cmd_duration") .use_config(toml::toml! { [cmd_duration] - min_time = 5 + min_time = 5000 }) - .arg("--cmd-duration=3") + .arg("--cmd-duration=3000") .output()?; let actual = String::from_utf8(output.stdout).unwrap(); @@ -48,9 +48,9 @@ fn config_5s_duration_10s() -> io::Result<()> { let output = common::render_module("cmd_duration") .use_config(toml::toml! { [cmd_duration] - min_time = 5 + min_time = 5000 }) - .arg("--cmd-duration=10") + .arg("--cmd-duration=10000") .output()?; let actual = String::from_utf8(output.stdout).unwrap(); @@ -66,7 +66,7 @@ fn config_1s_duration_prefix_underwent() -> io::Result<()> { [cmd_duration] prefix = "underwent " }) - .arg("--cmd-duration=1") + .arg("--cmd-duration=1000") .output()?; let actual = String::from_utf8(output.stdout).unwrap(); @@ -82,7 +82,7 @@ fn config_5s_duration_prefix_underwent() -> io::Result<()> { [cmd_duration] prefix = "underwent " }) - .arg("--cmd-duration=5") + .arg("--cmd-duration=5000") .output()?; let actual = String::from_utf8(output.stdout).unwrap();