fix(zsh): do not fail under ERR_EXIT conditions if STARSHIP_DURATION computes to 0 (#6922)

Guard against `STARSHIP_DURATION=0`

If an arithmetic expression evaluates to `0`, its exit status is `1`:

> The return status is 0 if the arithmetic value of the expression is non-zero, 1 if it is zero, and 2 if an error occurred.

In rare cases, the subtraction for `STARSHIP_DURATION` can result in an `int(0)` result (yes, really - happens e.g. during `vhs` sessions), which would then kill the shell if `set -e` is in effect.

We therefore have to assign the result outside the expression (using `STARSHIP_DURATION=$((...))`), because unlike regular `(())` arithmetic expressions, a `$(())` arithmetic substitution gets a return status of `0` even if the expression evalues to `int(0)`.

The alternative would be to keep the expression, and ensure it always succeeds, by doing `(( STARSHIP_DURATION = ... )) || true`.

However, the `$(()` approach has the benefit of still bubbling up an error from the arithmetic expression (normally return status `2` as in the documentation quote above; return status `1` in a substitution), which is useful e.g. in the event of undefined variables.
This commit is contained in:
David Zuelke
2025-09-06 19:16:03 +02:00
committed by GitHub
parent ef7d8bd442
commit 38db5f0094
+8 -1
View File
@@ -34,7 +34,14 @@ prompt_starship_precmd() {
# Calculate duration if a command was executed
if (( ${+STARSHIP_START_TIME} )); then
__starship_get_time && (( STARSHIP_DURATION = STARSHIP_CAPTURED_TIME - STARSHIP_START_TIME ))
# If an arithmetic expression evaluates to 0, its exit status is 1:
# "The return status is 0 if the arithmetic value of the expression is non-zero, 1 if it is zero, and 2 if an error occurred."
# In rare cases, the subtraction below can result in an int 0 result (yes, really),
# which would then kill the shell if 'set -e' is in effect.
# We therefore have to assign the result outside the expression (using 'STARSHIP_DURATION=$((...))'),
# because unlike '(())', '$(())' gets a return status of 0 even if the expression evaluates to int 0
# (but it still surfaces a potential error, normally status 2, as status 1).
__starship_get_time && STARSHIP_DURATION=$(( STARSHIP_CAPTURED_TIME - STARSHIP_START_TIME ))
unset STARSHIP_START_TIME
# Drop status and duration otherwise
else