22#
33# Functions for measuring and reporting how long a command takes to run.
44
5+ # Notice: This function used to run as a sub-shell while defining:
6+ # local LC_ALL=C
7+ #
8+ # DFARREL You would think LC_NUMERIC would do it, but not working in my local.
9+ # Note: LC_ALL='en_US.UTF-8' has been used to enforce the decimal point to be
10+ # a period, but the specific locale 'en_US.UTF-8' is not ensured to exist in
11+ # the system. One should instead use the locale 'C', which is ensured by the
12+ # C and POSIX standards.
13+ #
14+ # We now use EPOCHREALTIME, while replacing any non-digit character by a period.
15+ #
16+ # Technically, one can define a locale with decimal_point being an arbitrary string.
17+ # For example, ps_AF uses U+066B as the decimal point.
18+ #
19+ # cf: https://github.com/Bash-it/bash-it/pull/2366#discussion_r2760681820
20+ #
521# Get shell duration in decimal format regardless of runtime locale.
6- # Notice: This function runs as a sub-shell - notice '(' vs '{'.
7- function _shell_duration_en() (
8- # DFARREL You would think LC_NUMERIC would do it, but not working in my local.
9- # Note: LC_ALL='en_US.UTF-8' has been used to enforce the decimal point to be
10- # a period, but the specific locale 'en_US.UTF-8' is not ensured to exist in
11- # the system. One should instead use the locale 'C', which is ensured by the
12- # C and POSIX standards.
13- local LC_ALL=C
14- printf " %s " " ${EPOCHREALTIME :- $SECONDS } "
15- )
16-
17- : " ${COMMAND_DURATION_START_SECONDS:= $(_shell_duration_en )} "
22+ function _command_duration_current_time() {
23+ local current_time
24+ if [[ -n " ${EPOCHREALTIME :- } " ]] ; then
25+ current_time= " ${EPOCHREALTIME // [!0-9] / .} "
26+ else
27+ current_time= " $SECONDS "
28+ fi
29+
30+ echo " $current_time "
31+ }
32+
33+ : " ${COMMAND_DURATION_START_SECONDS:= $(_command_duration_current_time )} "
1834: " ${COMMAND_DURATION_ICON:= 🕘} "
1935: " ${COMMAND_DURATION_MIN_SECONDS:= 1} "
36+ : " ${COMMAND_DURATION_PRECISION:= 1} "
2037
2138function _command_duration_pre_exec() {
22- COMMAND_DURATION_START_SECONDS=" $( _shell_duration_en ) "
39+ COMMAND_DURATION_START_SECONDS=" $( _command_duration_current_time ) "
2340}
2441
2542function _command_duration_pre_cmd() {
2643 COMMAND_DURATION_START_SECONDS=" "
2744}
2845
2946function _dynamic_clock_icon {
30- local clock_hand
47+ local clock_hand duration=" $1 "
48+
49+ # Clock only work for time >= 1s
50+ if (( duration < 1 )) ; then
51+ duration=1
52+ fi
53+
3154 # clock hand value is between 90 and 9b in hexadecimal.
3255 # so between 144 and 155 in base 10.
33- printf -v clock_hand ' %x' $(( ((${1 :- ${SECONDS} } - 1 ) % 12 ) + 144 ))
56+ printf -v clock_hand ' %x' $(( ((${duration :- ${SECONDS} } - 1 ) % 12 ) + 144 ))
3457 printf -v ' COMMAND_DURATION_ICON' ' %b' " \xf0\x9f\x95\x$clock_hand "
3558}
3659
3760function _command_duration() {
3861 [[ -n " ${BASH_IT_COMMAND_DURATION:- } " ]] || return
3962 [[ -n " ${COMMAND_DURATION_START_SECONDS:- } " ]] || return
4063
41- local command_duration=0 command_start=" ${COMMAND_DURATION_START_SECONDS:- 0} "
42- local -i minutes=0 seconds=0 deciseconds=0
43- local -i command_start_seconds=" ${command_start% .* } "
44- local -i command_start_deciseconds=$(( 10 #${command_start##* .} ))
45- command_start_deciseconds=" ${command_start_deciseconds: 0: 1} "
4664 local current_time
47- current_time=" $( _shell_duration_en) "
48- local -i current_time_seconds=" ${current_time% .* } "
49- local -i current_time_deciseconds=" $(( 10 #${current_time##* .} )) "
50- current_time_deciseconds=" ${current_time_deciseconds: 0: 1} "
65+ current_time=" $( _command_duration_current_time) "
66+
67+ local -i command_duration=0
68+ local -i minutes=0 seconds=0
69+ local microseconds=" "
5170
52- if [[ " ${command_start_seconds:- 0} " -gt 0 ]]; then
53- # seconds
54- command_duration=" $(( current_time_seconds - command_start_seconds)) "
71+ local -i command_start_seconds=${COMMAND_DURATION_START_SECONDS% .* }
72+ local -i current_time_seconds=${current_time% .* }
5573
56- if (( current_time_deciseconds >= command_start_deciseconds)) ; then
57- deciseconds=" $(( current_time_deciseconds - command_start_deciseconds)) "
74+ # Calculate seconds difference
75+ command_duration=$(( current_time_seconds - command_start_seconds))
76+
77+ # Calculate microseconds if both timestamps have fractional parts
78+ if [[ " $COMMAND_DURATION_START_SECONDS " == * .* ]] && [[ " $current_time " == * .* ]] && (( COMMAND_DURATION_PRECISION > 0 )) ; then
79+ local -i command_start_microseconds=$(( 10 #${COMMAND_DURATION_START_SECONDS##* .} ))
80+ local -i current_time_microseconds=$(( 10 #${current_time##* .} ))
81+
82+ if (( current_time_microseconds >= command_start_microseconds)) ; then
83+ microseconds=$(( current_time_microseconds - command_start_microseconds))
5884 else
5985 (( command_duration -= 1 ))
60- deciseconds= " $(( 10 - (command_start_deciseconds - current_time_deciseconds )) ) "
86+ microseconds= $(( 1000000 + current_time_microseconds - command_start_microseconds ))
6187 fi
62- else
63- command_duration=0
88+
89+ # Pad with leading zeros to 6 digits, then take first N digits
90+ printf -v microseconds ' %06d' " $microseconds "
91+ microseconds=" ${microseconds: 0: $COMMAND_DURATION_PRECISION } "
6492 fi
6593
6694 if (( command_duration >= COMMAND_DURATION_MIN_SECONDS)) ; then
@@ -71,7 +99,7 @@ function _command_duration() {
7199 if (( minutes > 0 )) ; then
72100 printf " %s %s%dm %ds" " ${COMMAND_DURATION_ICON:- } " " ${COMMAND_DURATION_COLOR:- } " " $minutes " " $seconds "
73101 else
74- printf " %s %s%d.%01ds " " ${COMMAND_DURATION_ICON:- } " " ${COMMAND_DURATION_COLOR:- } " " $seconds " " $deciseconds "
102+ printf " %s %s%ss " " ${COMMAND_DURATION_ICON:- } " " ${COMMAND_DURATION_COLOR:- } " " $seconds ${microseconds : +. $microseconds } "
75103 fi
76104 fi
77105}
0 commit comments