diff --git a/bash_it.sh b/bash_it.sh index 00a1bcea..ddc02b70 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -51,8 +51,6 @@ if [[ -n "${BASH_IT_THEME:-}" ]]; then source "${BASH_IT}/themes/githelpers.theme.bash" BASH_IT_LOG_PREFIX="themes: p4helpers: " source "${BASH_IT}/themes/p4helpers.theme.bash" - BASH_IT_LOG_PREFIX="themes: command_duration: " - source "${BASH_IT}/themes/command_duration.theme.bash" BASH_IT_LOG_PREFIX="themes: base: " source "${BASH_IT}/themes/base.theme.bash" diff --git a/clean_files.txt b/clean_files.txt index 36bdc08c..e52d5a9f 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -78,6 +78,7 @@ completion/available/wpscan.completion.bash # libraries lib/appearance.bash lib/colors.bash +lib/command_duration.bash lib/helpers.bash lib/history.bash lib/log.bash @@ -155,7 +156,6 @@ themes/bobby-python themes/brainy themes/brunton themes/candy -themes/command_duration.theme.bash themes/easy themes/essential themes/githelpers.theme.bash diff --git a/lib/command_duration.bash b/lib/command_duration.bash new file mode 100644 index 00000000..bc0cca8e --- /dev/null +++ b/lib/command_duration.bash @@ -0,0 +1,56 @@ +# shellcheck shell=bash +# +# Functions for measuring and reporting how long a command takes to run. + +: "${COMMAND_DURATION_START_SECONDS:=${EPOCHREALTIME:-$SECONDS}}" +: "${COMMAND_DURATION_ICON:=🕘}" +: "${COMMAND_DURATION_MIN_SECONDS:=1}" + +function _command_duration_pre_exec() { + COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" +} + +function _dynamic_clock_icon { + local -i clock_hand=$(((${1:-${SECONDS}} % 12) + 90)) + printf -v 'COMMAND_DURATION_ICON' '%b' "\xf0\x9f\x95\x$clock_hand" +} + +function _command_duration() { + [[ -n "${BASH_IT_COMMAND_DURATION:-}" ]] || return + + local command_duration=0 command_start="${COMMAND_DURATION_START_SECONDS:-0}" + local -i minutes=0 seconds=0 deciseconds=0 + local -i command_start_seconds="${command_start%.*}" + local -i command_start_deciseconds=$((10#${command_start##*.})) + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i current_time_seconds="${current_time%.*}" + local -i current_time_deciseconds="$((10#${current_time##*.}))" + + if [[ "${command_start_seconds:-0}" -gt 0 ]]; then + # seconds + command_duration="$((current_time_seconds - command_start_seconds))" + + if ((current_time_deciseconds >= command_start_deciseconds)); then + deciseconds="$((current_time_deciseconds - command_start_deciseconds))" + else + ((command_duration -= 1)) + deciseconds="$((10 - (command_start_deciseconds - current_time_deciseconds)))" + fi + else + command_duration=0 + fi + + if ((command_duration > 0)); then + minutes=$((command_duration / 60)) + seconds=$((command_duration % 60)) + fi + + _dynamic_clock_icon "${command_duration}" + if ((minutes > 0)); then + printf "%s%s%dm %ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$minutes" "$seconds" + elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then + printf "%s%s%d.%01ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$seconds" "$deciseconds" + fi +} + +_bash_it_library_finalize_hook+=("safe_append_preexec '_command_duration_pre_exec'") diff --git a/plugins/available/cmd-returned-notify.plugin.bash b/plugins/available/cmd-returned-notify.plugin.bash index d9be5e4e..88c07722 100644 --- a/plugins/available/cmd-returned-notify.plugin.bash +++ b/plugins/available/cmd-returned-notify.plugin.bash @@ -2,15 +2,15 @@ cite about-plugin about-plugin 'Alert (BEL) when process ends after a threshold of seconds' -precmd_return_notification() { - export LAST_COMMAND_DURATION=$(($(date +%s) - ${LAST_COMMAND_TIME:=$(date +%s)})) - [[ ${LAST_COMMAND_DURATION} -gt ${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5} ]] && echo -e "\a" - export LAST_COMMAND_TIME= +function precmd_return_notification() { + local command_start="${COMMAND_DURATION_START_SECONDS:=0}" + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i command_duration="$((${current_time%.*} - ${command_start%.*}))" + if [[ "${command_duration}" -gt "${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5}" ]]; then + printf '\a' + fi + return 0 } -preexec_return_notification() { - [[ -z "${LAST_COMMAND_TIME}" ]] && LAST_COMMAND_TIME=$(date +%s) -} - -precmd_functions+=(precmd_return_notification) -preexec_functions+=(preexec_return_notification) +safe_append_prompt_command 'precmd_return_notification' +safe_append_preexec '_command_duration_pre_exec' diff --git a/test/plugins/cmd-returned-notify.plugin.bats b/test/plugins/cmd-returned-notify.plugin.bats index ca40f3b5..04edad95 100644 --- a/test/plugins/cmd-returned-notify.plugin.bats +++ b/test/plugins/cmd-returned-notify.plugin.bats @@ -3,46 +3,39 @@ load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" function local_setup_file() { - setup_libs "preexec" #"command_duration" + setup_libs "command_duration" load "${BASH_IT?}/plugins/available/cmd-returned-notify.plugin.bash" } @test "plugins cmd-returned-notify: notify after elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 - export LAST_COMMAND_TIME=$(date +%s) - sleep 1 - run precmd_return_notification - assert_success - assert_output $'\a' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'\a' } @test "plugins cmd-returned-notify: do not notify before elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 - export LAST_COMMAND_TIME=$(date +%s) - sleep 1 - run precmd_return_notification - assert_success - assert_output $'' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'' } -@test "plugins cmd-returned-notify: preexec no output" { - export LAST_COMMAND_TIME= - run preexec_return_notification - assert_success - assert_output "" +@test "lib command_duration: preexec no output" { + export COMMAND_DURATION_START_SECONDS= + run _command_duration_pre_exec + assert_success + assert_output "" } - -@test "plugins cmd-returned-notify: preexec no output env set" { - export LAST_COMMAND_TIME=$(date +%s) - run preexec_return_notification - assert_failure - assert_output "" -} - -@test "plugins cmd-returned-notify: preexec set LAST_COMMAND_TIME" { - export LAST_COMMAND_TIME= - assert_equal "${LAST_COMMAND_TIME}" "" - NOW=$(date +%s) - preexec_return_notification - assert_equal "${LAST_COMMAND_TIME}" "${NOW}" +@test "lib command_duration: preexec set COMMAND_DURATION_START_SECONDS" { + export COMMAND_DURATION_START_SECONDS= + assert_equal "${COMMAND_DURATION_START_SECONDS}" "" + NOW="${EPOCHREALTIME:-$SECONDS}" + _command_duration_pre_exec + # We need to make sure to account for nanoseconds... + assert_equal "${COMMAND_DURATION_START_SECONDS%.*}" "${NOW%.*}" } diff --git a/test/test_helper.bash b/test/test_helper.bash index 919e7559..bffb59ed 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -57,7 +57,7 @@ function common_setup_file() { function setup_libs() { local lib # Use a loop to allow convenient short-circuiting for some test files - for lib in "log" "utilities" "helpers" "search" "preexec" "colors"; do + for lib in "log" "utilities" "helpers" "search" "preexec" "colors" "command_duration"; do load "${BASH_IT?}/lib/${lib}.bash" || return # shellcheck disable=SC2015 # short-circuit if we've reached the requested library [[ "${lib}" == "${1:-}" ]] && return 0 || true diff --git a/themes/command_duration.theme.bash b/themes/command_duration.theme.bash deleted file mode 100644 index cf91785c..00000000 --- a/themes/command_duration.theme.bash +++ /dev/null @@ -1,69 +0,0 @@ -# shellcheck shell=bash - -if [ -z "$BASH_IT_COMMAND_DURATION" ] || [ "$BASH_IT_COMMAND_DURATION" != true ]; then - _command_duration() { - echo -n - } - return -fi - -# Define tmp dir and file -COMMAND_DURATION_TMPDIR="${TMPDIR:-/tmp}" -COMMAND_DURATION_FILE="${COMMAND_DURATION_FILE:-$COMMAND_DURATION_TMPDIR/bashit_theme_execution_$BASHPID}" - -COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-'  '} -COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-'1'} - -trap _command_duration_delete_temp_file EXIT HUP INT TERM - -_command_duration_delete_temp_file() { - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - rm -f "$COMMAND_DURATION_FILE" - fi -} - -_command_duration_pre_exec() { - date +%s.%1N > "$COMMAND_DURATION_FILE" -} - -_command_duration() { - local command_duration command_start current_time - local minutes seconds deciseconds - local command_start_sseconds current_time_seconds command_start_deciseconds current_time_deciseconds - current_time=$(date +%s.%1N) - - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - command_start=$(< "$COMMAND_DURATION_FILE") - command_start_sseconds=${command_start%.*} - current_time_seconds=${current_time%.*} - - command_start_deciseconds=$((10#${command_start#*.})) - current_time_deciseconds=$((10#${current_time#*.})) - - # seconds - command_duration=$((current_time_seconds - command_start_sseconds)) - - if ((current_time_deciseconds >= command_start_deciseconds)); then - deciseconds=$(((current_time_deciseconds - command_start_deciseconds))) - else - ((command_duration -= 1)) - deciseconds=$((10 - ((command_start_deciseconds - current_time_deciseconds)))) - fi - command rm "$COMMAND_DURATION_FILE" - else - command_duration=0 - fi - - if ((command_duration > 0)); then - minutes=$((command_duration / 60)) - seconds=$((command_duration % 60)) - fi - - if ((minutes > 0)); then - printf "%s%s%dm %ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$minutes" "$seconds" - elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then - printf "%s%s%d.%01ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$seconds" "$deciseconds" - fi -} - -preexec_functions+=(_command_duration_pre_exec)