summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Song <chipbuster@users.noreply.github.com>2019-08-13 19:49:47 -0700
committerMatan Kushner <hello@matchai.me>2019-08-13 22:49:47 -0400
commit22c8c3459f9583cd23098d76736f8af0fbbbeab3 (patch)
treebebdb1aa092806a36fad03d93f18f65bcc87e0c1
parent56f4797a2583dfe4a15fea9790b8c4cb0f5883f9 (diff)
feat: implement `cmd_duration` for bash (#144)
-rw-r--r--docs/config/README.md11
-rw-r--r--src/init.rs74
2 files changed, 72 insertions, 13 deletions
diff --git a/docs/config/README.md b/docs/config/README.md
index 0c92e9361..e3d759fff 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -119,11 +119,16 @@ The `cmd_duration` module shows how long the last command took to execute.
The module will be shown only if the command took longer than two seconds, or
the `min_time` config value, if it exists.
-::: warning NOTE
-Command duration is currently not supported in `bash`. See
-[this issue](https://github.com/starship/starship/issues/124) for more details.
+::: warning Do Not Hook the DEBUG trap in Bash
+If you are running Starship in `bash`, do not hook the `DEBUG` trap after running
+`eval $(starship init $0)`, or this module **will** break.
:::
+Bash users who need preexec-like functionality can use
+[rcaloras's bash_preexec framework](https://github.com/rcaloras/bash-preexec).
+Simply define the arrays `preexec_functions` and `precmd_functions` before
+running `eval $(starship init $0)`, and then proceed as normal.
+
### Options
| Variable | Default | Description |
diff --git a/src/init.rs b/src/init.rs
index 16d466df2..d366bc1b8 100644
--- a/src/init.rs
+++ b/src/init.rs
@@ -52,23 +52,74 @@ pub fn init(shell_name: &str) {
}
}
-/* Bash does not currently support command durations (see issue #124) for details
-https://github.com/starship/starship/issues/124
+/*
+ For bash: we need to manually hook functions ourself: PROMPT_COMMAND will exec
+ right before the prompt is drawn, and any function trapped by DEBUG will exec
+ before a command is run.
-We need to quote the output of `$(jobs -p | wc -l)` since MacOS `wc` leaves
-giant spaces in front of the number (e.g. " 3"), which messes up the
-word-splitting. Instead, quote the whole thing, then let Rust do the whitespace
-trimming within the jobs module.
+ There is a preexec/precmd framework for bash out there: if we find the
+ appropriate variables set, assume we are using that framework:
+ https://github.com/rcaloras/bash-preexec
+
+ Bash quirk: DEBUG is triggered whenever a command is executed, even if that
+ command is part of a pipeline. To avoid only timing the last part of a pipeline,
+ we only start the timer if no timer has been started since the last prompt draw,
+ tracked by the variable PREEXEC_READY. Similarly, only draw timing info if
+ STARSHIP_START_TIME is defined, in case preexec was interrupted.
+
+ Finally, to work around existing DEBUG traps in the absence of a preexec-like,
+ we parse out the name of the old DEBUG hook, then make a new function which
+ calls both that function and our starship hooks. We don't do this for
+ PROMPT_COMMAND because that would probably result in two prompts.
+
+ We need to quote the output of `$(jobs -p | wc -l)` since MacOS `wc` leaves
+ giant spaces in front of the number (e.g. " 3"), which messes up the
+ word-splitting. Instead, quote the whole thing, then let Rust do the whitespace
+ trimming within the jobs module
*/
+/*
+Note to programmers: this and the zsh init will be evaluated on a single line.
+Use semicolons, avoid comments, and generally think like all newlines will be
+deleted.
+*/
const BASH_INIT: &str = r##"
+starship_preexec() {
+ if [ "$PREEXEC_READY" = "true" ]; then
+ PREEXEC_READY=false;
+ STARSHIP_START_TIME=$(date +%s);
+ fi
+};
starship_precmd() {
- PS1="$(starship prompt --status=$? --jobs="$(jobs -p | wc -l)")";
+ STATUS=$?;
+ if [[ $STARSHIP_START_TIME ]]; then
+ STARSHIP_END_TIME=$(date +%s);
+ 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;
+ else
+ PS1="$(starship prompt --status=$STATUS --jobs="$(jobs -p | wc -l)")";
+ fi;
+ PREEXEC_READY=true;
};
-PROMPT_COMMAND=starship_precmd;
+if [[ $preexec_functions ]]; then
+ preexec_functions+=(starship_preexec);
+ precmd_functions+=(starship_precmd);
+ STARSHIP_START_TIME=$(date +%s);
+else
+ dbg_trap="$(trap -p DEBUG | cut -d' ' -f3 | tr -d \')";
+ if [[ -z "$dbg_trap" ]]; then
+ trap starship_preexec DEBUG;
+ elif [[ "$dbg_trap" != "starship_preexec" && "$dbg_trap" != "starship_preexec_all" ]]; then
+ function starship_preexec_all(){
+ $dbg_trap; starship_preexec;
+ };
+ trap starship_preexec_all DEBUG;
+ fi;
+ PROMPT_COMMAND=starship_precmd;
+ STARSHIP_START_TIME=$(date +%s);
+fi;
"##;
-/* TODO: Once warning/error system is implemented in starship, print a warning
-if starship will not be printing timing due to DEBUG clobber error */
/* For zsh: preexec_functions and precmd_functions provide preexec/precmd in a
way that lets us avoid clobbering them.
@@ -80,6 +131,9 @@ if starship will not be printing timing due to DEBUG clobber error */
To fix this, only pass the time if STARSHIP_START_TIME is defined, and unset
it after passing the time, so that we only measure actual commands.
+
+ We need to quote the output of the jobs command for the same reason as
+ bash.
*/
const ZSH_INIT: &str = r##"