mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-11-17 18:45:12 +00:00
173 lines
6.3 KiB
Rust
173 lines
6.3 KiB
Rust
use std::ffi::OsStr;
|
|
use std::path::Path;
|
|
|
|
/* We need to send execution time to the prompt for the cmd_duration module. For fish,
|
|
this is fairly straightforward. For bash and zsh, we'll need to use several
|
|
shell utilities to get the time, as well as render the prompt */
|
|
|
|
pub fn init(shell_name: &str) {
|
|
log::debug!("Shell name: {}", shell_name);
|
|
|
|
let shell_basename = Path::new(shell_name).file_stem().and_then(OsStr::to_str);
|
|
|
|
let setup_script = match shell_basename {
|
|
Some("bash") => {
|
|
let script = BASH_INIT;
|
|
Some(script)
|
|
}
|
|
Some("zsh") => {
|
|
let script = ZSH_INIT;
|
|
Some(script)
|
|
}
|
|
Some("fish") => {
|
|
let script = FISH_INIT;
|
|
Some(script)
|
|
}
|
|
None => {
|
|
println!(
|
|
"Invalid shell name provided: {}\\n\
|
|
If this issue persists, please open an \
|
|
issue in the starship repo: \\n\
|
|
https://github.com/starship/starship/issues/new\\n\"",
|
|
shell_name
|
|
);
|
|
None
|
|
}
|
|
_ => {
|
|
/* Calling unwrap() here is fine because the None case will have
|
|
already matched on the previous arm */
|
|
println!(
|
|
"printf \"\\n{0} is not yet supported by starship.\\n\
|
|
For the time being, we support bash, zsh, and fish.\\n\
|
|
Please open an issue in the starship repo if you would like to \
|
|
see support for {0}:\\nhttps://github.com/starship/starship/issues/new\"\\n\\n",
|
|
shell_basename.unwrap()
|
|
);
|
|
None
|
|
}
|
|
};
|
|
|
|
if let Some(script) = setup_script {
|
|
print!("{}", script);
|
|
}
|
|
}
|
|
|
|
/*
|
|
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.
|
|
|
|
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() {
|
|
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;
|
|
};
|
|
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;
|
|
"##;
|
|
|
|
/* For zsh: preexec_functions and precmd_functions provide preexec/precmd in a
|
|
way that lets us avoid clobbering them.
|
|
|
|
Zsh quirk: preexec() is only fired if a command is actually run (unlike in
|
|
bash, where spamming empty commands still triggers DEBUG). This means a user
|
|
spamming ENTER at an empty command line will see increasing runtime (since
|
|
preexec never actually fires to reset the start time).
|
|
|
|
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##"
|
|
starship_precmd() {
|
|
STATUS=$?;
|
|
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 --jobs="$(jobs | wc -l)")";
|
|
unset STARSHIP_START_TIME;
|
|
else
|
|
PROMPT="$(starship prompt --status=$STATUS --jobs="$(jobs | wc -l)")";
|
|
fi
|
|
};
|
|
starship_preexec(){
|
|
STARSHIP_START_TIME="$(date +%s)"
|
|
};
|
|
if [[ ${precmd_functions[(ie)starship_precmd]} -gt ${#precmd_functions} ]]; then
|
|
precmd_functions+=(starship_precmd);
|
|
fi;
|
|
if [[ ${preexec_functions[(ie)starship_preexec]} -gt ${#preexec_functions} ]]; then
|
|
preexec_functions+=(starship_preexec);
|
|
fi;
|
|
STARSHIP_START_TIME="$(date +%s)";
|
|
"##;
|
|
|
|
/* Fish setup is simple because they give us CMD_DURATION. Just account for name
|
|
changes between 2.7/3.0 and do some math to convert ms->s and we can use it */
|
|
const FISH_INIT: &str = r##"
|
|
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 --jobs=(count (jobs -p));
|
|
end;
|
|
"##;
|