From b87f3067b595bd0db448654e9b85e38cfd881a99 Mon Sep 17 00:00:00 2001 From: Nariyasu Heseri Date: Sat, 29 Jan 2022 03:17:50 +0900 Subject: [PATCH 01/22] plugin/battery: bug fix When `upower --enumerate | grep -i BAT` returns multiple lines of results (which are file paths), the added quotation (from commit 3cb5f3f7e66345a329cae8ad112f1ecbedc60dab) concatenates them all to provide an invalid path. Thus to make the plugin work as before the commit, take only the first line of the results. --- plugins/available/battery.plugin.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash index dc18167c..8b1a4e08 100644 --- a/plugins/available/battery.plugin.bash +++ b/plugins/available/battery.plugin.bash @@ -3,7 +3,7 @@ about-plugin 'display info about your battery charge level' function ac_adapter_connected() { if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT)" | grep 'state' | grep -q 'charging\|fully-charged' + upower -i "$(upower -e | grep -i BAT | head -n 1)" | grep 'state' | grep -q 'charging\|fully-charged' elif _command_exists acpi; then acpi -a | grep -q "on-line" elif _command_exists pmset; then @@ -17,7 +17,7 @@ function ac_adapter_connected() { function ac_adapter_disconnected() { if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT)" | grep 'state' | grep -q 'discharging' + upower -i "$(upower -e | grep -i BAT | head -n 1)" | grep 'state' | grep -q 'discharging' elif _command_exists acpi; then acpi -a | grep -q "off-line" elif _command_exists pmset; then @@ -36,7 +36,7 @@ function battery_percentage() { local command_output="no" if _command_exists upower; then - command_output=$(upower --show-info "$(upower --enumerate | grep -i BAT)" | grep percentage | grep -o "[0-9]\+" | head -1) + command_output=$(upower --show-info "$(upower --enumerate | grep -i BAT | head -n 1)" | grep percentage | grep -o "[0-9]\+" | head -1) elif _command_exists acpi; then command_output=$(acpi -b | awk -F, '/,/{gsub(/ /, "", $0); gsub(/%/,"", $0); print $2}') elif _command_exists pmset; then From c794f4f0e76dcac4e15bf8269c0da9b9670e6247 Mon Sep 17 00:00:00 2001 From: Nariyasu Heseri Date: Sat, 29 Jan 2022 15:50:36 +0900 Subject: [PATCH 02/22] plugin/battery: use `--max-count` of `grep` instead of `head` --- plugins/available/battery.plugin.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash index 8b1a4e08..d86a1f08 100644 --- a/plugins/available/battery.plugin.bash +++ b/plugins/available/battery.plugin.bash @@ -3,7 +3,7 @@ about-plugin 'display info about your battery charge level' function ac_adapter_connected() { if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT | head -n 1)" | grep 'state' | grep -q 'charging\|fully-charged' + upower -i "$(upower -e | grep --max-count=1 -i BAT)" | grep 'state' | grep -q 'charging\|fully-charged' elif _command_exists acpi; then acpi -a | grep -q "on-line" elif _command_exists pmset; then @@ -17,7 +17,7 @@ function ac_adapter_connected() { function ac_adapter_disconnected() { if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT | head -n 1)" | grep 'state' | grep -q 'discharging' + upower -i "$(upower -e | grep --max-count=1 -i BAT)" | grep 'state' | grep -q 'discharging' elif _command_exists acpi; then acpi -a | grep -q "off-line" elif _command_exists pmset; then @@ -36,7 +36,7 @@ function battery_percentage() { local command_output="no" if _command_exists upower; then - command_output=$(upower --show-info "$(upower --enumerate | grep -i BAT | head -n 1)" | grep percentage | grep -o "[0-9]\+" | head -1) + command_output=$(upower --show-info "$(upower --enumerate | grep --max-count=1 -i BAT)" | grep percentage | grep -o "[0-9]\+" | head -1) elif _command_exists acpi; then command_output=$(acpi -b | awk -F, '/,/{gsub(/ /, "", $0); gsub(/%/,"", $0); print $2}') elif _command_exists pmset; then From b0f23d8e98ee8048561693c3508bd72608e812e6 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sun, 16 Jan 2022 09:43:23 -0800 Subject: [PATCH 03/22] completion/alias: eliminate use of `eval` --- .../available/alias-completion.plugin.bash | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/plugins/available/alias-completion.plugin.bash b/plugins/available/alias-completion.plugin.bash index eb368d93..0ce2820e 100644 --- a/plugins/available/alias-completion.plugin.bash +++ b/plugins/available/alias-completion.plugin.bash @@ -1,26 +1,18 @@ # shellcheck shell=bash -# Load after the other completions to understand what needs to be completed -# BASH_IT_LOAD_PRIORITY: 365 - -cite about-plugin about-plugin 'Automatic completion of aliases' +# Load after the other completions to understand what needs to be completed +# BASH_IT_LOAD_PRIORITY: 800 + # References: # http://superuser.com/a/437508/119764 # http://stackoverflow.com/a/1793178/1228454 -# This needs to be a plugin so it gets executed after the completions and the aliases have been defined. -# Bash-it loads its components in the order -# 1) Aliases -# 2) Completions -# 3) Plugins -# 4) Custom scripts - # Automatically add completion for all aliases to commands having completion functions -function alias_completion { +function alias_completion() { local namespace="alias_completion" local tmp_file completion_loader alias_name alias_tokens line completions - local alias_arg_words new_completion compl_func compl_wrapper + local alias_arg_words new_completion compl_func compl_wrapper alias_defn # parse function based completion definitions, where capture group 2 => function and 3 => trigger local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' @@ -28,9 +20,13 @@ function alias_completion { local alias_regex="alias( -- | )([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" # create array of function completion triggers, keeping multi-word triggers together - eval "completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))" + IFS=$'\n' read -d '' -ra completions < <(complete -p) ((${#completions[@]} == 0)) && return 0 + completions=("${completions[@]##complete -* * -}") # strip all but last option plus trigger(s) + completions=("${completions[@]#complete -}") # strip last option and arg, leaving only trigger(s) + completions=("${completions[@]#? * }") # strip last option and arg, leaving only trigger(s) + # create temporary file for wrapper functions and completions tmp_file="$(mktemp -t "${namespace}-${RANDOM}XXXXXX")" || return 1 @@ -40,13 +36,16 @@ function alias_completion { # some aliases do have backslashes that needs to be interpreted # shellcheck disable=SC2162 while read line; do - eval "alias_tokens=($line)" 2> /dev/null || continue # some alias arg patterns cause an eval parse error - # shellcheck disable=SC2154 # see `eval` above - alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }" + line="${line#alias }" + alias_name="${line%%=*}" + alias_defn="${line#*=}" # alias definition + alias_cmd="${alias_defn%%[[:space:]]*}" # first word of alias + alias_cmd="${alias_cmd:1}" # lose opening quotation mark + alias_args="${alias_defn#*[[:space:]]}" # everything after first word + alias_args="${alias_args:0:-1}" # lose ending quotation mark # skip aliases to pipes, boolean control structures and other command lists - # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters) - eval "alias_arg_words=($alias_args)" 2> /dev/null || continue + [[ "${alias_args}" =~ [\|\&\;\)\(\n] ]] && continue # avoid expanding wildcards read -a alias_arg_words <<< "$alias_args" @@ -54,7 +53,7 @@ function alias_completion { if ! _bash-it-array-contains-element "$alias_cmd" "${completions[@]}"; then if [[ -n "$completion_loader" ]]; then # force loading of completions for the aliased command - eval "$completion_loader $alias_cmd" + "${completion_loader:?}" "${alias_cmd}" # 124 means completion loader was successful [[ $? -eq 124 ]] || continue completions+=("$alias_cmd") @@ -97,7 +96,7 @@ function alias_completion { new_completion="${new_completion% *} $alias_name" echo "$new_completion" >> "$tmp_file" fi - done < <(alias -p | sed -Ene "s/$alias_regex/\2 '\3' '\4'/p") + done < <(alias -p) # shellcheck source=/dev/null source "$tmp_file" && command rm -f "$tmp_file" } From d214621d39b4f2079b4bbcad4a516d19d0a3962d Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sun, 16 Jan 2022 10:14:27 -0800 Subject: [PATCH 04/22] completion/alias: `shfmt` && `shellcheck` --- plugins/available/alias-completion.plugin.bash | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/plugins/available/alias-completion.plugin.bash b/plugins/available/alias-completion.plugin.bash index 0ce2820e..a1d1cb89 100644 --- a/plugins/available/alias-completion.plugin.bash +++ b/plugins/available/alias-completion.plugin.bash @@ -3,7 +3,6 @@ about-plugin 'Automatic completion of aliases' # Load after the other completions to understand what needs to be completed # BASH_IT_LOAD_PRIORITY: 800 - # References: # http://superuser.com/a/437508/119764 # http://stackoverflow.com/a/1793178/1228454 @@ -11,21 +10,16 @@ about-plugin 'Automatic completion of aliases' # Automatically add completion for all aliases to commands having completion functions function alias_completion() { local namespace="alias_completion" - local tmp_file completion_loader alias_name alias_tokens line completions + local tmp_file completion_loader alias_name line completions local alias_arg_words new_completion compl_func compl_wrapper alias_defn - # parse function based completion definitions, where capture group 2 => function and 3 => trigger - local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' - # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments - local alias_regex="alias( -- | )([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" - # create array of function completion triggers, keeping multi-word triggers together IFS=$'\n' read -d '' -ra completions < <(complete -p) ((${#completions[@]} == 0)) && return 0 completions=("${completions[@]##complete -* * -}") # strip all but last option plus trigger(s) - completions=("${completions[@]#complete -}") # strip last option and arg, leaving only trigger(s) - completions=("${completions[@]#? * }") # strip last option and arg, leaving only trigger(s) + completions=("${completions[@]#complete -}") # strip anything missed + completions=("${completions[@]#? * }") # strip last option and arg, leaving only trigger(s) # create temporary file for wrapper functions and completions tmp_file="$(mktemp -t "${namespace}-${RANDOM}XXXXXX")" || return 1 @@ -38,11 +32,11 @@ function alias_completion() { while read line; do line="${line#alias }" alias_name="${line%%=*}" - alias_defn="${line#*=}" # alias definition + alias_defn="${line#*=}" # alias definition alias_cmd="${alias_defn%%[[:space:]]*}" # first word of alias - alias_cmd="${alias_cmd:1}" # lose opening quotation mark + alias_cmd="${alias_cmd:1}" # lose opening quotation mark alias_args="${alias_defn#*[[:space:]]}" # everything after first word - alias_args="${alias_args:0:-1}" # lose ending quotation mark + alias_args="${alias_args%\'}" # lose ending quotation mark # skip aliases to pipes, boolean control structures and other command lists [[ "${alias_args}" =~ [\|\&\;\)\(\n] ]] && continue From 7fcad6ed0d9427e51b94cc721a846666cef8ea82 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 15 Jan 2022 00:01:25 -0800 Subject: [PATCH 05/22] completion/alias: rename There is no reason for this to be in the `plugins` directory, it just needs to have a load priority sufficiently high that it runs after any aliases are defined. --- .../available/aliases.completion.bash | 0 profiles/default.bash_it | 2 +- .../aliases.completion.bats} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename plugins/available/alias-completion.plugin.bash => completion/available/aliases.completion.bash (100%) rename test/{plugins/alias-completion.plugin.bats => completion/aliases.completion.bats} (100%) diff --git a/plugins/available/alias-completion.plugin.bash b/completion/available/aliases.completion.bash similarity index 100% rename from plugins/available/alias-completion.plugin.bash rename to completion/available/aliases.completion.bash diff --git a/profiles/default.bash_it b/profiles/default.bash_it index 5e4f4631..9a55f6c7 100644 --- a/profiles/default.bash_it +++ b/profiles/default.bash_it @@ -1,10 +1,10 @@ # This is the default profile of Bash-it # plugins -plugins alias-completion plugins base # completion +completion aliases completion bash-it completion system diff --git a/test/plugins/alias-completion.plugin.bats b/test/completion/aliases.completion.bats similarity index 100% rename from test/plugins/alias-completion.plugin.bats rename to test/completion/aliases.completion.bats From b0862899d7cbd8cbfcc9465e09f1aa9b004470e0 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sun, 16 Jan 2022 10:23:02 -0800 Subject: [PATCH 06/22] completion/alias: fix tests --- test/completion/aliases.completion.bats | 7 ++++--- test/fixtures/bash_it/profiles/test-bad-component.bash_it | 2 +- test/fixtures/bash_it/profiles/test-bad-type.bash_it | 4 ++-- test/install/install.bats | 2 +- test/lib/helpers.bats | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/completion/aliases.completion.bats b/test/completion/aliases.completion.bats index 20d13cf2..813a7bbd 100644 --- a/test/completion/aliases.completion.bats +++ b/test/completion/aliases.completion.bats @@ -3,25 +3,26 @@ load ../test_helper load ../test_helper_libs +# Load something, anything... load ../../completion/available/capistrano.completion @test "alias-completion: See that aliases with double quotes and brackets do not break the plugin" { alias gtest="git log --graph --pretty=format:'%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset' --abbrev-commit --date=relative" - load ../../plugins/available/alias-completion.plugin + run load ../../completion/available/aliases.completion assert_success } @test "alias-completion: See that aliases with single quotes and brackets do not break the plugin" { alias gtest='git log --graph --pretty=format:"%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset" --abbrev-commit --date=relative' - load ../../plugins/available/alias-completion.plugin + run load ../../completion/available/aliases.completion assert_success } @test "alias-completion: See that having aliased rm command does not output unnecessary output" { alias rm='rm -v' - load ../../plugins/available/alias-completion.plugin + run load ../../completion/available/aliases.completion refute_output } diff --git a/test/fixtures/bash_it/profiles/test-bad-component.bash_it b/test/fixtures/bash_it/profiles/test-bad-component.bash_it index 8640265c..068c4b63 100644 --- a/test/fixtures/bash_it/profiles/test-bad-component.bash_it +++ b/test/fixtures/bash_it/profiles/test-bad-component.bash_it @@ -1,8 +1,8 @@ # plugins -plugins alias-completion plugins base # completion +completion aliases completion bash-it completion system diff --git a/test/fixtures/bash_it/profiles/test-bad-type.bash_it b/test/fixtures/bash_it/profiles/test-bad-type.bash_it index ed2d2373..102c52ea 100644 --- a/test/fixtures/bash_it/profiles/test-bad-type.bash_it +++ b/test/fixtures/bash_it/profiles/test-bad-type.bash_it @@ -1,10 +1,10 @@ # plugins -plugins alias-completion plugins base # Bad type -pluugins alias-completion +compleetion aliases # completion +completion aliases completion bash-it completion system diff --git a/test/install/install.bats b/test/install/install.bats index 262bf4f0..b3aee5a7 100644 --- a/test/install/install.bats +++ b/test/install/install.bats @@ -29,7 +29,7 @@ function local_setup { assert_link_exist "$BASH_IT/enabled/150---general.aliases.bash" assert_link_exist "$BASH_IT/enabled/250---base.plugin.bash" - assert_link_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_exist "$BASH_IT/enabled/325---system.completion.bash" } diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats index bd339d04..8c340c58 100755 --- a/test/lib/helpers.bats +++ b/test/lib/helpers.bats @@ -296,7 +296,7 @@ function local_setup { assert_link_exist "$BASH_IT/enabled/150---general.aliases.bash" assert_link_exist "$BASH_IT/enabled/250---base.plugin.bash" - assert_link_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_exist "$BASH_IT/enabled/325---system.completion.bash" } @@ -356,7 +356,7 @@ function local_setup { run _bash-it-profile-load "test" assert_link_not_exist "$BASH_IT/enabled/150---general.aliases.bash" assert_link_not_exist "$BASH_IT/enabled/250---base.plugin.bash" - assert_link_not_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_not_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_not_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_not_exist "$BASH_IT/enabled/325---system.completion.bash" } @@ -384,7 +384,7 @@ function local_setup { @test "helpers: profile load corrupted profile file: bad subdirectory" { run _bash-it-profile-load "test-bad-type" - assert_line -n 1 -p "Bad line(#5) in profile, aborting load..." + assert_line -n 1 -p "Bad line(#4) in profile, aborting load..." } @test "helpers: profile rm sanity" { From 880488ec9a0de18714351b7f6284838c9d2185f5 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 26 Jan 2022 10:14:54 -0800 Subject: [PATCH 07/22] completion/alias: add stub file - put a loader to remove the symlink at `enabled/***---alias-completion.plugin.bash`. --- plugins/available/alias-completion.plugin.bash | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 plugins/available/alias-completion.plugin.bash diff --git a/plugins/available/alias-completion.plugin.bash b/plugins/available/alias-completion.plugin.bash new file mode 100644 index 00000000..84c59a1e --- /dev/null +++ b/plugins/available/alias-completion.plugin.bash @@ -0,0 +1,5 @@ +# shellcheck shell=bash +# stub for renamed file + +_enable-completion aliases && _disable-plugin alias-completion +source "${BASH_IT?}/completion/aliases.completion.bash" From cade0a1e7a40c929907a9b2c50ca68458a6bd9e5 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Tue, 1 Feb 2022 10:15:35 -0800 Subject: [PATCH 08/22] plugin/battery: split `upower` to two variables --- plugins/available/battery.plugin.bash | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash index d86a1f08..1f758e0c 100644 --- a/plugins/available/battery.plugin.bash +++ b/plugins/available/battery.plugin.bash @@ -2,8 +2,10 @@ about-plugin 'display info about your battery charge level' function ac_adapter_connected() { + local batteries if _command_exists upower; then - upower -i "$(upower -e | grep --max-count=1 -i BAT)" | grep 'state' | grep -q 'charging\|fully-charged' + batteries="$(upower -e | grep --max-count=1 -i BAT)" + upower -i "${batteries}" | grep 'state' | grep -q 'charging\|fully-charged' elif _command_exists acpi; then acpi -a | grep -q "on-line" elif _command_exists pmset; then @@ -16,8 +18,10 @@ function ac_adapter_connected() { } function ac_adapter_disconnected() { + local batteries if _command_exists upower; then - upower -i "$(upower -e | grep --max-count=1 -i BAT)" | grep 'state' | grep -q 'discharging' + batteries="$(upower -e | grep --max-count=1 -i BAT)" + upower -i "${batteries}" | grep 'state' | grep -q 'discharging' elif _command_exists acpi; then acpi -a | grep -q "off-line" elif _command_exists pmset; then @@ -33,16 +37,17 @@ function battery_percentage() { about 'displays battery charge as a percentage of full (100%)' group 'battery' - local command_output="no" + local command_output batteries if _command_exists upower; then - command_output=$(upower --show-info "$(upower --enumerate | grep --max-count=1 -i BAT)" | grep percentage | grep -o "[0-9]\+" | head -1) + batteries="$(upower --enumerate | grep --max-count=1 -i BAT)" + command_output="$(upower --show-info "${batteries:-}" | grep percentage | grep -o '[0-9]\+' | head -1)" elif _command_exists acpi; then command_output=$(acpi -b | awk -F, '/,/{gsub(/ /, "", $0); gsub(/%/,"", $0); print $2}') elif _command_exists pmset; then - command_output=$(pmset -g ps | sed -n 's/.*[[:blank:]]+*\(.*%\).*/\1/p' | grep -o "[0-9]\+" | head -1) + command_output=$(pmset -g ps | sed -n 's/.*[[:blank:]]+*\(.*%\).*/\1/p' | grep -o '[0-9]\+' | head -1) elif _command_exists ioreg; then - command_output=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%05.2f"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}' | grep -o "[0-9]\+" | head -1) + command_output=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%05.2f"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}' | grep -o '[0-9]\+' | head -1) elif _command_exists WMIC; then command_output=$(WMIC PATH Win32_Battery Get EstimatedChargeRemaining /Format:List | grep -o '[0-9]\+' | head -1) else From 23f7916a4d38d162007a94015d2bb6abd5b0d855 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Tue, 1 Feb 2022 10:15:54 -0800 Subject: [PATCH 09/22] test/battery: add multiple-battery edge case --- test/plugins/battery.plugin.bats | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) mode change 100644 => 100755 test/plugins/battery.plugin.bats diff --git a/test/plugins/battery.plugin.bats b/test/plugins/battery.plugin.bats old mode 100644 new mode 100755 index eac6d021..7ca962d9 --- a/test/plugins/battery.plugin.bats +++ b/test/plugins/battery.plugin.bats @@ -193,11 +193,19 @@ function setup_acpi { # Creates a `upower` function that simulates output like the real `upower` command. # The passed in parameter is used for the remaining battery percentage. function setup_upower { - percent="$1" + percent="$1" - function upower { - printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" - } + function upower { + case $1 in + '-e'|'--enumerate') + echo "/org/freedesktop/UPower/devices/battery_BAT0" + echo "/org/freedesktop/UPower/devices/mouse_hid_${RANDOM}_battery" + ;; + '-i'|'--show-info') + printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" + ;; + esac + } } @test 'plugins battery: battery-percentage with upower, 100%' { From 302bae9c5fb75665d8fefa001cfe101db4947ad9 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Thu, 3 Feb 2022 13:53:54 -0800 Subject: [PATCH 10/22] test/battery: require matching battery identifier --- test/plugins/battery.plugin.bats | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/plugins/battery.plugin.bats b/test/plugins/battery.plugin.bats index 7ca962d9..f06fa008 100755 --- a/test/plugins/battery.plugin.bats +++ b/test/plugins/battery.plugin.bats @@ -194,15 +194,22 @@ function setup_acpi { # The passed in parameter is used for the remaining battery percentage. function setup_upower { percent="$1" + BAT0="/org/freedesktop/UPower/devices/battery_BAT$RANDOM" + function upower { case $1 in '-e'|'--enumerate') - echo "/org/freedesktop/UPower/devices/battery_BAT0" + echo "$BAT0" echo "/org/freedesktop/UPower/devices/mouse_hid_${RANDOM}_battery" ;; '-i'|'--show-info') - printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" + if [[ $2 == "$BAT0" ]] + then + printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" + else + false + fi ;; esac } From 43df0fe130f00444b836a24f0670a6d5df50ba0e Mon Sep 17 00:00:00 2001 From: John D Pell Date: Thu, 3 Feb 2022 22:46:58 -0800 Subject: [PATCH 11/22] completion/aliases: rename init function Use the callback naming convention for the init function, for later use. --- completion/available/aliases.completion.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/completion/available/aliases.completion.bash b/completion/available/aliases.completion.bash index a1d1cb89..bdcaf917 100644 --- a/completion/available/aliases.completion.bash +++ b/completion/available/aliases.completion.bash @@ -1,6 +1,6 @@ # shellcheck shell=bash about-plugin 'Automatic completion of aliases' -# Load after the other completions to understand what needs to be completed +# Load after all aliases and completions to understand what needs to be completed # BASH_IT_LOAD_PRIORITY: 800 # References: @@ -8,7 +8,7 @@ about-plugin 'Automatic completion of aliases' # http://stackoverflow.com/a/1793178/1228454 # Automatically add completion for all aliases to commands having completion functions -function alias_completion() { +function _bash-it-component-completion-callback-on-init-aliases() { local namespace="alias_completion" local tmp_file completion_loader alias_name line completions local alias_arg_words new_completion compl_func compl_wrapper alias_defn @@ -95,4 +95,4 @@ function alias_completion() { source "$tmp_file" && command rm -f "$tmp_file" } -alias_completion +_bash-it-component-completion-callback-on-init-aliases From 0d346b204fb424f2c1dcbeb3a8169131deb41e3b Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 29 Jan 2022 22:13:50 -0800 Subject: [PATCH 12/22] main: Glob for *.bash properly when path contains spaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `shfmt`, `shellcheck` - Clean up legacy/compatibility code to simpler control flow - Move theme stuff down to where themes are handled - Don't use `**` as _Bash It_ has never before set `globstar`; this eliminates varying behavior by environment; this alsö fixes users having any not-enabled themes under their custom dir. - Lose weird Mac-specific alternate shell startup file (Bash loads startup files on Mac the same as it does on any other *nix system.) - Place `composure.sh` init all in one place - remove 10-years-deprecated backwards compatibility: Deprecated in `b59ee658f78ec6ff8c6c2754216e0322b7fe18e2` dated 2011-10-29. --- bash_it.sh | 135 +++++++++++++++++++++-------------------------------- 1 file changed, 52 insertions(+), 83 deletions(-) diff --git a/bash_it.sh b/bash_it.sh index 03fd0bf5..b47b9f63 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -1,145 +1,114 @@ #!/usr/bin/env bash +# shellcheck source-path=SCRIPTDIR/lib source-path=SCRIPTDIR/scripts +# shellcheck disable=SC2034 +# # Initialize Bash It BASH_IT_LOG_PREFIX="core: main: " - -# Only set $BASH_IT if it's not already set -if [ -z "${BASH_IT:-}" ]; then - # Setting $BASH to maintain backwards compatibility - export BASH_IT=$BASH - BASH="$(bash -c 'echo $BASH')" - export BASH - BASH_IT_OLD_BASH_SETUP=true -fi +: "${BASH_IT:=${BASH_SOURCE%/*}}" +: "${BASH_IT_CUSTOM:=${BASH_IT}/custom}" +: "${CUSTOM_THEME_DIR:="${BASH_IT_CUSTOM}/themes"}" +: "${BASH_IT_BASHRC:=${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}}" # Load composure first, so we support function metadata -# shellcheck disable=SC1090 -source "${BASH_IT}"/vendor/github.com/erichs/composure/composure.sh - -# Declare our end-of-main finishing hook -declare -a _bash_it_library_finalize_hook - -# We need to load logging module early in order to be able to log -# shellcheck source-path=SCRIPTDIR/lib -source "${BASH_IT}/lib/log.bash" - -# We can only log it now -[ -z "${BASH_IT_OLD_BASH_SETUP:-}" ] || _log_warning "BASH_IT variable not initialized, please upgrade your bash-it version and reinstall it!" - -# For backwards compatibility, look in old BASH_THEME location -if [ -z "${BASH_IT_THEME:-}" ]; then - _log_warning "BASH_IT_THEME variable not initialized, please upgrade your bash-it version and reinstall it!" - export BASH_IT_THEME="${BASH_THEME:-}" - unset BASH_THEME -fi - +# shellcheck source-path=SCRIPTDIR/vendor/github.com/erichs/composure +source "${BASH_IT}/vendor/github.com/erichs/composure/composure.sh" # support 'plumbing' metadata cite _about _param _example _group _author _version cite about-alias about-plugin about-completion +# Declare our end-of-main finishing hook, but don't use `declare`/`typeset` +_bash_it_library_finalize_hook=() + +# We need to load logging module early in order to be able to log +source "${BASH_IT}/lib/log.bash" + # libraries, but skip appearance (themes) for now _log_debug "Loading libraries(except appearance)..." -LIB="${BASH_IT}/lib/*.bash" APPEARANCE_LIB="${BASH_IT}/lib/appearance.bash" -for _bash_it_config_file in $LIB; do - if [ "$_bash_it_config_file" != "$APPEARANCE_LIB" ]; then - filename=${_bash_it_config_file##*/} - filename=${filename%.bash} - BASH_IT_LOG_PREFIX="lib: ${filename}: " - _log_debug "Loading library file..." - # shellcheck disable=SC1090 - source "$_bash_it_config_file" - fi +for _bash_it_main_file_lib in "${BASH_IT}/lib"/*.bash; do + [[ "$_bash_it_main_file_lib" == "$APPEARANCE_LIB" ]] && continue + filename="${_bash_it_main_file_lib##*/}" + filename="${filename%.bash}" + BASH_IT_LOG_PREFIX="lib: ${filename}: " + _log_debug "Loading library file..." + # shellcheck disable=SC1090 + source "$_bash_it_main_file_lib" + BASH_IT_LOG_PREFIX="core: main: " done -BASH_IT_LOG_PREFIX="core: main: " -# Load the global "enabled" directory -# "family" param is empty so that files get sources in glob order -# shellcheck source=./scripts/reloader.bash -source "${BASH_IT}/scripts/reloader.bash" - -# Load enabled aliases, completion, plugins -for file_type in "aliases" "plugins" "completion"; do - # shellcheck source=./scripts/reloader.bash - source "${BASH_IT}/scripts/reloader.bash" "skip" "$file_type" +# Load the global "enabled" directory, then enabled aliases, completion, plugins +# "file_type" param is empty so that files get sourced in glob order +for file_type in "" "aliases" "plugins" "completion"; do + BASH_IT_LOG_PREFIX="core: reloader: " + source "${BASH_IT}/scripts/reloader.bash" "${file_type:+skip}" "$file_type" + BASH_IT_LOG_PREFIX="core: main: " done # Load theme, if a theme was set -if [[ -n "${BASH_IT_THEME}" ]]; then - _log_debug "Loading \"${BASH_IT_THEME}\" theme..." +# shellcheck source-path=SCRIPTDIR/themes +if [[ -n "${BASH_IT_THEME:-}" ]]; then + _log_debug "Loading theme '${BASH_IT_THEME}'." BASH_IT_LOG_PREFIX="themes: githelpers: " - # shellcheck source=./themes/githelpers.theme.bash source "${BASH_IT}/themes/githelpers.theme.bash" BASH_IT_LOG_PREFIX="themes: p4helpers: " - # shellcheck source=./themes/p4helpers.theme.bash source "${BASH_IT}/themes/p4helpers.theme.bash" BASH_IT_LOG_PREFIX="themes: command_duration: " - # shellcheck source=./themes/command_duration.theme.bash source "${BASH_IT}/themes/command_duration.theme.bash" BASH_IT_LOG_PREFIX="themes: base: " - # shellcheck source=./themes/base.theme.bash source "${BASH_IT}/themes/base.theme.bash" BASH_IT_LOG_PREFIX="lib: appearance: " # appearance (themes) now, after all dependencies - # shellcheck source=./lib/appearance.bash + # shellcheck source=SCRIPTDIR/lib/appearance.bash source "$APPEARANCE_LIB" + BASH_IT_LOG_PREFIX="core: main: " fi -BASH_IT_LOG_PREFIX="core: main: " _log_debug "Loading custom aliases, completion, plugins..." for file_type in "aliases" "completion" "plugins"; do - if [ -e "${BASH_IT}/${file_type}/custom.${file_type}.bash" ]; then + if [[ -s "${BASH_IT}/${file_type}/custom.${file_type}.bash" ]]; then BASH_IT_LOG_PREFIX="${file_type}: custom: " _log_debug "Loading component..." # shellcheck disable=SC1090 source "${BASH_IT}/${file_type}/custom.${file_type}.bash" fi + BASH_IT_LOG_PREFIX="core: main: " done # Custom -BASH_IT_LOG_PREFIX="core: main: " _log_debug "Loading general custom files..." -CUSTOM="${BASH_IT_CUSTOM:=${BASH_IT}/custom}/*.bash ${BASH_IT_CUSTOM:=${BASH_IT}/custom}/**/*.bash" -for _bash_it_config_file in $CUSTOM; do - if [ -e "${_bash_it_config_file}" ]; then - filename=$(basename "${_bash_it_config_file}") - filename=${filename%*.bash} - # shellcheck disable=SC2034 +for _bash_it_main_file_custom in "${BASH_IT_CUSTOM}"/*.bash "${BASH_IT_CUSTOM}"/*/*.bash; do + if [[ -s "${_bash_it_main_file_custom}" ]]; then + filename="${_bash_it_main_file_custom##*/}" + filename="${filename%*.bash}" BASH_IT_LOG_PREFIX="custom: $filename: " _log_debug "Loading custom file..." # shellcheck disable=SC1090 - source "$_bash_it_config_file" + source "$_bash_it_main_file_custom" fi + BASH_IT_LOG_PREFIX="core: main: " done -unset _bash_it_config_file if [[ -n "${PROMPT:-}" ]]; then - export PS1="\[""$PROMPT""\]" + PS1="${PROMPT}" fi # Adding Support for other OSes -PREVIEW="less" - -if [ -s /usr/bin/gloobus-preview ]; then +if _command_exists gloobus-preview; then PREVIEW="gloobus-preview" -elif [ -s /Applications/Preview.app ]; then - # shellcheck disable=SC2034 +elif [[ -d /Applications/Preview.app ]]; then PREVIEW="/Applications/Preview.app" +else + PREVIEW="less" fi # BASH_IT_RELOAD_LEGACY is set. -if ! _command_exists reload && [[ -n "${BASH_IT_RELOAD_LEGACY:-}" ]]; then - case $OSTYPE in - darwin*) - alias reload='source ~/.bash_profile' - ;; - *) - alias reload='source ~/.bashrc' - ;; - esac +if [[ -n "${BASH_IT_RELOAD_LEGACY:-}" ]] && ! _command_exists reload; then + # shellcheck disable=SC2139 + alias reload="builtin source '${BASH_IT_BASHRC?}'" fi for _bash_it_library_finalize_f in "${_bash_it_library_finalize_hook[@]:-}"; do eval "${_bash_it_library_finalize_f?}" # Use `eval` to achieve the same behavior as `$PROMPT_COMMAND`. done -unset "${!_bash_it_library_finalize_@}" +unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}" filename file_type From bc95eceb10db21859c847a6ca77eb99611409918 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 16 Oct 2021 14:49:43 -0700 Subject: [PATCH 13/22] main: adopt `_bash-it-log-prefix-by-path()` --- bash_it.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/bash_it.sh b/bash_it.sh index b47b9f63..b890f021 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -27,9 +27,7 @@ _log_debug "Loading libraries(except appearance)..." APPEARANCE_LIB="${BASH_IT}/lib/appearance.bash" for _bash_it_main_file_lib in "${BASH_IT}/lib"/*.bash; do [[ "$_bash_it_main_file_lib" == "$APPEARANCE_LIB" ]] && continue - filename="${_bash_it_main_file_lib##*/}" - filename="${filename%.bash}" - BASH_IT_LOG_PREFIX="lib: ${filename}: " + _bash-it-log-prefix-by-path "${_bash_it_main_file_lib}" _log_debug "Loading library file..." # shellcheck disable=SC1090 source "$_bash_it_main_file_lib" @@ -66,11 +64,13 @@ fi _log_debug "Loading custom aliases, completion, plugins..." for file_type in "aliases" "completion" "plugins"; do - if [[ -s "${BASH_IT}/${file_type}/custom.${file_type}.bash" ]]; then - BASH_IT_LOG_PREFIX="${file_type}: custom: " + _bash_it_main_file_custom="${BASH_IT}/${file_type}/custom.${file_type}.bash" + if [[ -s "${_bash_it_main_file_custom}" ]]; then + _bash-it-log-prefix-by-path "${_bash_it_main_file_custom}" _log_debug "Loading component..." + # shellcheck source-path=SCRIPTDIR/aliases source-path=SCRIPTDIR/completions source-path=SCRIPTDIR/plugins # shellcheck disable=SC1090 - source "${BASH_IT}/${file_type}/custom.${file_type}.bash" + source "${_bash_it_main_file_custom}" fi BASH_IT_LOG_PREFIX="core: main: " done @@ -79,9 +79,7 @@ done _log_debug "Loading general custom files..." for _bash_it_main_file_custom in "${BASH_IT_CUSTOM}"/*.bash "${BASH_IT_CUSTOM}"/*/*.bash; do if [[ -s "${_bash_it_main_file_custom}" ]]; then - filename="${_bash_it_main_file_custom##*/}" - filename="${filename%*.bash}" - BASH_IT_LOG_PREFIX="custom: $filename: " + _bash-it-log-prefix-by-path "${_bash_it_main_file_custom}" _log_debug "Loading custom file..." # shellcheck disable=SC1090 source "$_bash_it_main_file_custom" @@ -111,4 +109,4 @@ fi for _bash_it_library_finalize_f in "${_bash_it_library_finalize_hook[@]:-}"; do eval "${_bash_it_library_finalize_f?}" # Use `eval` to achieve the same behavior as `$PROMPT_COMMAND`. done -unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}" filename file_type +unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}" file_type From 1480cdfa340a92da331acd94f855c6de9e2d7f99 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 26 Jan 2022 14:21:47 -0800 Subject: [PATCH 14/22] completion/system: correctly load version when not linked - Load the correct version of `bash-completion` even when not "linked". --- completion/available/system.completion.bash | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/completion/available/system.completion.bash b/completion/available/system.completion.bash index af7ea70d..bb1d14eb 100644 --- a/completion/available/system.completion.bash +++ b/completion/available/system.completion.bash @@ -14,31 +14,24 @@ else __bash_it_restore_nounset=false fi +# shellcheck disable=SC1090 disable=SC1091 if [[ -r "${BASH_COMPLETION:-}" ]]; then - # shellcheck disable=SC1090 source "${BASH_COMPLETION}" - elif [[ -r /etc/bash_completion ]]; then - # shellcheck disable=SC1091 source /etc/bash_completion - # Some distribution makes use of a profile.d script to import completion. elif [[ -r /etc/profile.d/bash_completion.sh ]]; then - # shellcheck disable=SC1091 source /etc/profile.d/bash_completion.sh - elif _bash_it_homebrew_check; then - : "${BASH_COMPLETION_COMPAT_DIR:=$BASH_IT_HOMEBREW_PREFIX/etc/bash_completion.d}" - + : "${BASH_COMPLETION_COMPAT_DIR:=${BASH_IT_HOMEBREW_PREFIX}/etc/bash_completion.d}" case "${BASH_VERSION}" in 1* | 2* | 3.0* | 3.1*) _log_warning "Cannot load completion due to version of shell. Are you using Bash 3.2+?" ;; 3.2* | 4.0* | 4.1*) # Import version 1.x of bash-completion, if installed. - BASH_COMPLETION="$BASH_IT_HOMEBREW_PREFIX/opt/bash-completion@1/etc/bash_completion" + BASH_COMPLETION="${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@1/etc/bash_completion" if [[ -r "$BASH_COMPLETION" ]]; then - # shellcheck disable=SC1090 source "$BASH_COMPLETION" else unset BASH_COMPLETION @@ -46,9 +39,8 @@ elif _bash_it_homebrew_check; then ;; 4.2* | 5* | *) # homebrew/versions/bash-completion2 (required for projects.completion.bash) is installed to this path - if [[ -r "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" ]]; then - # shellcheck disable=SC1091 - source "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" + if [[ -r "${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@2/etc/profile.d/bash_completion.sh" ]]; then + source "${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@2/etc/profile.d/bash_completion.sh" fi ;; esac From d6555f369a067470451760f42e40ec7d7abd0acb Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 29 Jan 2022 23:16:40 -0800 Subject: [PATCH 15/22] lib/preview: refactor into a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows future use like `bash-it preview`. Alsö, allows to use `$BASH_PREVIEW` to specify a particular theme to preview instead of just doing all of them. --- clean_files.txt | 1 + lib/preview.bash | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/clean_files.txt b/clean_files.txt index 8f9c173a..49e51abc 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -85,6 +85,7 @@ lib/colors.bash lib/helpers.bash lib/log.bash lib/preexec.bash +lib/preview.bash lib/search.bash lib/utilities.bash diff --git a/lib/preview.bash b/lib/preview.bash index 418839cd..60659df5 100644 --- a/lib/preview.bash +++ b/lib/preview.bash @@ -1,19 +1,30 @@ -if [[ "${BASH_PREVIEW:-}" ]]; -then - unset BASH_PREVIEW #Prevent infinite looping - echo " +# shellcheck shell=bash +# +# Displays the prompt from each _Bash It_ theme. - Previewing Bash-it Themes +function _bash-it-preview() { + local BASH_IT_THEME BASH_IT_LOG_LEVEL + local themes theme - " + printf '\n\n\t%s\n\n' "Previewing Bash-it Themes" - THEMES="$BASH_IT/themes/*/*.theme.bash" - for theme in $THEMES - do - BASH_IT_THEME=${theme%.theme.bash} - BASH_IT_THEME=${BASH_IT_THEME##*/} - echo " - $BASH_IT_THEME" - echo "" | bash --init-file "${BASH_IT}/bash_it.sh" -i - done + if [[ -n "${1:-}" && -s "${BASH_IT?}/themes/${1}/${1}.theme.bash" ]]; then + themes=("${1}") + else + themes=("${BASH_IT?}/themes"/*/*.theme.bash) + fi + + # shellcheck disable=SC2034 + for theme in "${themes[@]}"; do + BASH_IT_THEME="${theme%.theme.bash}" + BASH_IT_THEME="${BASH_IT_THEME##*/}" + BASH_IT_LOG_LEVEL=0 + + bash --init-file "${BASH_IT_BASHRC:-${BASH_IT?}/bash_it.sh}" -i <<< '_bash-it-flash-term "${#BASH_IT_THEME}" "${BASH_IT_THEME}"' + done +} + +if [[ -n "${BASH_PREVIEW:-}" ]]; then + _bash-it-preview "${BASH_PREVIEW}" "$@" + unset BASH_PREVIEW #Prevent infinite looping fi From a9a40a3cad024add8fbbace487e4005389674dff Mon Sep 17 00:00:00 2001 From: John D Pell Date: Tue, 25 Jan 2022 12:57:23 -0800 Subject: [PATCH 16/22] lib/helpers: add `preview` to `bash-it` spaghetti --- completion/available/bash-it.completion.bash | 4 ++-- docs/themes.rst | 2 +- lib/helpers.bash | 8 +++++++- test/completion/bash-it.completion.bats | 12 ++++++------ 4 files changed, 16 insertions(+), 10 deletions(-) mode change 100644 => 100755 completion/available/bash-it.completion.bash diff --git a/completion/available/bash-it.completion.bash b/completion/available/bash-it.completion.bash old mode 100644 new mode 100755 index 1f83d5c8..aa00a06e --- a/completion/available/bash-it.completion.bash +++ b/completion/available/bash-it.completion.bash @@ -13,7 +13,7 @@ function _bash-it() { prev="${COMP_WORDS[COMP_CWORD - 1]}" verb="${COMP_WORDS[1]}" file_type="${COMP_WORDS[2]:-}" - candidates=('disable' 'enable' 'help' 'migrate' 'reload' 'restart' 'profile' 'doctor' 'search' 'show' 'update' 'version') + candidates=('disable' 'enable' 'help' 'migrate' 'reload' 'restart' 'preview' 'profile' 'doctor' 'search' 'show' 'update' 'version') case "${verb}" in show) candidates=('aliases' 'completions' 'plugins') @@ -58,7 +58,7 @@ function _bash-it() { fi _compreply_candidates ;; - migrate | reload | restart | search | version) ;; + migrate | reload | restart | preview | search | version) ;; enable | disable) if [[ "${verb}" == "enable" ]]; then suffix="disabled" diff --git a/docs/themes.rst b/docs/themes.rst index 5b796389..8cfbeb23 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -22,7 +22,7 @@ Examples: # Disable theming export BASH_IT_THEME="" -You can easily preview the themes in your own shell using ``BASH_PREVIEW=true bash-it reload``. +You can easily preview the themes in your own shell using ``bash-it preview``. If you've created your own custom prompts, we'd love it if you shared them with everyone else! Just submit a Pull Request. You can see theme screenshots on `wiki/Themes `_. diff --git a/lib/helpers.bash b/lib/helpers.bash index 66cdec74..4728541a 100644 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -98,7 +98,7 @@ alias reload_plugins="$(_make_reload_alias plugin plugins)" function bash-it() { about 'Bash-it help and maintenance' - param '1: verb [one of: help | show | enable | disable | migrate | update | search | version | reload | restart | doctor ] ' + param '1: verb [one of: help | show | enable | disable | migrate | update | search | preview | version | reload | restart | doctor ] ' param '2: component type [one of: alias(es) | completion(s) | plugin(s) ] or search term(s)' param '3: specific component [optional]' example '$ bash-it show plugins' @@ -108,6 +108,8 @@ function bash-it() { example '$ bash-it migrate' example '$ bash-it update' example '$ bash-it search [-|@]term1 [-|@]term2 ... [ -e/--enable ] [ -d/--disable ] [ -r/--refresh ] [ -c/--no-color ]' + example '$ bash-it preview' + example '$ bash-it preview essential' example '$ bash-it version' example '$ bash-it reload' example '$ bash-it restart' @@ -142,6 +144,10 @@ function bash-it() { _bash-it-search "$component" "$@" return ;; + preview) + _bash-it-preview "$component" "$@" + return + ;; update) func="_bash-it-update-$component" ;; diff --git a/test/completion/bash-it.completion.bats b/test/completion/bash-it.completion.bats index f2336185..087a926d 100755 --- a/test/completion/bash-it.completion.bats +++ b/test/completion/bash-it.completion.bats @@ -81,32 +81,32 @@ function __check_completion () { @test "completion bash-it: show options" { run __check_completion 'bash-it ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bash-ti - show options" { run __check_completion 'bash-ti ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: shit - show options" { run __check_completion 'shit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bashit - show options" { run __check_completion 'bashit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: batshit - show options" { run __check_completion 'batshit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bash_it - show options" { run __check_completion 'bash_it ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: profile - show options" { From 00e3955dd38bd7db49c20fc6cb8c48faabc016c5 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Tue, 25 Jan 2022 12:58:22 -0800 Subject: [PATCH 17/22] lib/preview: add full completion --- completion/available/bash-it.completion.bash | 6 ++++- lib/preview.bash | 24 ++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) mode change 100755 => 100644 completion/available/bash-it.completion.bash diff --git a/completion/available/bash-it.completion.bash b/completion/available/bash-it.completion.bash old mode 100755 new mode 100644 index aa00a06e..2259e37b --- a/completion/available/bash-it.completion.bash +++ b/completion/available/bash-it.completion.bash @@ -58,7 +58,11 @@ function _bash-it() { fi _compreply_candidates ;; - migrate | reload | restart | preview | search | version) ;; + migrate | reload | restart | search | version) ;; + preview) + _bash-it-preview # completes itself + return 0 + ;; enable | disable) if [[ "${verb}" == "enable" ]]; then suffix="disabled" diff --git a/lib/preview.bash b/lib/preview.bash index 60659df5..96fafae7 100644 --- a/lib/preview.bash +++ b/lib/preview.bash @@ -4,22 +4,26 @@ function _bash-it-preview() { local BASH_IT_THEME BASH_IT_LOG_LEVEL - local themes theme + local themes IFS=$'\n' cur - printf '\n\n\t%s\n\n' "Previewing Bash-it Themes" - - if [[ -n "${1:-}" && -s "${BASH_IT?}/themes/${1}/${1}.theme.bash" ]]; then - themes=("${1}") + if [[ $# -gt '0' ]]; then + themes=("$@") else themes=("${BASH_IT?}/themes"/*/*.theme.bash) + themes=("${themes[@]##*/}") + themes=("${themes[@]%.theme.bash}") fi - # shellcheck disable=SC2034 - for theme in "${themes[@]}"; do - BASH_IT_THEME="${theme%.theme.bash}" - BASH_IT_THEME="${BASH_IT_THEME##*/}" - BASH_IT_LOG_LEVEL=0 + if [[ ${COMP_CWORD:-} -gt '0' ]]; then + cur="${COMP_WORDS[COMP_CWORD]}" + read -d '' -ra COMPREPLY < <(compgen -W "all${IFS}${themes[*]}" -- "${cur}") + return + fi + printf '\n\n\t%s\n\n' "Previewing Bash-it Themes" + # shellcheck disable=SC2034 + for BASH_IT_THEME in "${themes[@]}"; do + BASH_IT_LOG_LEVEL=0 bash --init-file "${BASH_IT_BASHRC:-${BASH_IT?}/bash_it.sh}" -i <<< '_bash-it-flash-term "${#BASH_IT_THEME}" "${BASH_IT_THEME}"' done } From 8052911861883c9e3d1187529a72b72921f27746 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 27 Dec 2021 14:16:58 -0800 Subject: [PATCH 18/22] plugin/history: don't use `export` ...so the plugin is friendly to variables already marked read-only. --- plugins/available/history.plugin.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/available/history.plugin.bash b/plugins/available/history.plugin.bash index be253e4a..4c8cdaba 100644 --- a/plugins/available/history.plugin.bash +++ b/plugins/available/history.plugin.bash @@ -5,11 +5,11 @@ about-plugin 'improve history handling with sane defaults' # variable when the shell exits, rather than overwriting the file. shopt -s histappend -# erase duplicates; alternative option: export HISTCONTROL=ignoredups -export HISTCONTROL=${HISTCONTROL:-ignorespace:erasedups} +# erase duplicates; alternative option: HISTCONTROL=ignoredups +: "${HISTCONTROL:=ignorespace:erasedups}" # resize history to 100x the default (500) -export HISTSIZE=${HISTSIZE:-50000} +: "${HISTSIZE:=50000}" # Flush history to disk after each command. export PROMPT_COMMAND="history -a;${PROMPT_COMMAND}" From 267a721ac607ea85fd262a0b4b490254854bab69 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 27 Dec 2021 14:21:44 -0800 Subject: [PATCH 19/22] plugin/history-eternal: Use `readonly` instead of `export` ...and hide errors relating to setting already-readonly variables. `plugin/history-eternal` does not need to force loading after `plugin/history` because both plugins will play nicely with read-only variables, and since we're overwritting and marking read-only then the intended result survives no matter which loads first. plugin/history-eternal: require Bash v4.3+ Unlimited history is only possible in _Bash_ version 4.3 and up --- plugins/available/history-eternal.plugin.bash | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/available/history-eternal.plugin.bash b/plugins/available/history-eternal.plugin.bash index a18283d3..829868df 100644 --- a/plugins/available/history-eternal.plugin.bash +++ b/plugins/available/history-eternal.plugin.bash @@ -1,20 +1,22 @@ # shellcheck shell=bash about-plugin 'eternal bash history' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 +if [[ ${BASH_VERSINFO[0]} -lt 4 ]] || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then + _log_warning "Bash version 4.3 introduced the 'unlimited' history size capability." + return 1 +fi # Modify history sizes before changing location to avoid unintentionally # truncating the history file early. # "Numeric values less than zero result in every command being saved on the history list (there is no limit)" -export HISTSIZE=-1 +readonly HISTSIZE=-1 2> /dev/null || true # "Non-numeric values and numeric values less than zero inhibit truncation" -export HISTFILESIZE='unlimited' +readonly HISTFILESIZE='unlimited' 2> /dev/null || true # Use a custom history file location so history is not truncated # if the environment ever loses this "eternal" configuration. HISTDIR="${XDG_STATE_HOME:-${HOME?}/.local/state}/bash" [[ -d ${HISTDIR?} ]] || mkdir -p "${HISTDIR?}" -export HISTFILE="${HISTDIR?}/history" +readonly HISTFILE="${HISTDIR?}/history" 2> /dev/null || true From f6119567e835b2048ca7ac015663381151e45b8e Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 27 Dec 2021 16:38:46 -0800 Subject: [PATCH 20/22] plugin/history*search: no need to load after `plugin/history` There's no need for these plugins to load after `plugin/history`. None of the history plugins depend upon each other loading before, after, or at all. --- plugins/available/history-search.plugin.bash | 3 --- plugins/available/history-substring-search.plugin.bash | 3 --- 2 files changed, 6 deletions(-) diff --git a/plugins/available/history-search.plugin.bash b/plugins/available/history-search.plugin.bash index 341ce2af..96941993 100644 --- a/plugins/available/history-search.plugin.bash +++ b/plugins/available/history-search.plugin.bash @@ -1,9 +1,6 @@ # shellcheck shell=bash about-plugin 'search history using the prefix already entered' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 - # enter a few characters and press UpArrow/DownArrow # to search backwards/forwards through the history if [[ ${SHELLOPTS} =~ (vi|emacs) ]]; then diff --git a/plugins/available/history-substring-search.plugin.bash b/plugins/available/history-substring-search.plugin.bash index 586ceb50..dde32720 100644 --- a/plugins/available/history-substring-search.plugin.bash +++ b/plugins/available/history-substring-search.plugin.bash @@ -1,9 +1,6 @@ # shellcheck shell=bash about-plugin 'search history using the substring already entered' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 - # enter a few characters and press UpArrow/DownArrow # to search backwards/forwards through the history if [[ ${SHELLOPTS} =~ (vi|emacs) ]]; then From 5d5858058ec61abefcfb122f90bd0eee3d8276f5 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 24 Jan 2022 21:37:04 -0800 Subject: [PATCH 21/22] lib/history: new functions `_bash-it-history-auto-*()` Two new functions `_bash-it-history-auto-save()` and `_bash-it-history-auto-load()`, which append new history to disk and load new history from disk, respectively. See bash-it/bash-it#1595 for discussion. --- clean_files.txt | 1 + lib/history.bash | 49 +++++++++++++++++++++++++++ plugins/available/history.plugin.bash | 9 +++-- themes/base.theme.bash | 5 +-- 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 lib/history.bash diff --git a/clean_files.txt b/clean_files.txt index 8f9c173a..70b1175c 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -83,6 +83,7 @@ completion/available/wpscan.completion.bash # libraries lib/colors.bash lib/helpers.bash +lib/history.bash lib/log.bash lib/preexec.bash lib/search.bash diff --git a/lib/history.bash b/lib/history.bash new file mode 100644 index 00000000..7bdbbd5e --- /dev/null +++ b/lib/history.bash @@ -0,0 +1,49 @@ +# shellcheck shell=bash +# +# Functions for working with Bash's command history. + +function _bash-it-history-init() { + safe_append_preexec '_bash-it-history-auto-save' + safe_append_prompt_command '_bash-it-history-auto-load' +} + +function _bash-it-history-auto-save() { + case $HISTCONTROL in + *'noauto'* | *'autoload'*) + : # Do nothing, as configured. + ;; + *'auto'*) + # Append new history from this session to the $HISTFILE + history -a + ;; + *) + # Append *only* if shell option `histappend` has been enabled. + shopt -q histappend && history -a && return + ;; + esac +} + +function _bash-it-history-auto-load() { + case $HISTCONTROL in + *'noauto'*) + : # Do nothing, as configured. + ;; + *'autosave'*) + # Append new history from this session to the $HISTFILE + history -a + ;; + *'autoloadnew'*) + # Read new entries from $HISTFILE + history -n + ;; + *'auto'*) + # Blank in-memory history, then read entire $HISTFILE fresh from disk. + history -a && history -c && history -r + ;; + *) + : # Do nothing, default. + ;; + esac +} + +_bash_it_library_finalize_hook+=('_bash-it-history-init') diff --git a/plugins/available/history.plugin.bash b/plugins/available/history.plugin.bash index 4c8cdaba..d9e930c3 100644 --- a/plugins/available/history.plugin.bash +++ b/plugins/available/history.plugin.bash @@ -5,15 +5,14 @@ about-plugin 'improve history handling with sane defaults' # variable when the shell exits, rather than overwriting the file. shopt -s histappend -# erase duplicates; alternative option: HISTCONTROL=ignoredups -: "${HISTCONTROL:=ignorespace:erasedups}" +# 'ignorespace': don't save command lines which begin with a space to history +# 'erasedups' (alternative 'ignoredups'): don't save duplicates to history +# 'autoshare': automatically share history between multiple running shells +: "${HISTCONTROL:=ignorespace:erasedups:autoshare}" # resize history to 100x the default (500) : "${HISTSIZE:=50000}" -# Flush history to disk after each command. -export PROMPT_COMMAND="history -a;${PROMPT_COMMAND}" - function top-history() { about 'print the name and count of the most commonly run tools' diff --git a/themes/base.theme.bash b/themes/base.theme.bash index a7e99961..d7479b3f 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -584,6 +584,7 @@ function aws_profile { } function _save-and-reload-history() { - local autosave=${1:-0} - [[ $autosave -eq 1 ]] && history -a && history -c && history -r + local autosave="${1:-${HISTORY_AUTOSAVE:-0}}" + [[ ${autosave} -eq 1 ]] && local HISTCONTROL="${HISTCONTROL:-}${HISTCONTROL:+:}autoshare" + _bash-it-history-auto-save && _bash-it-history-auto-load } From 146107926e6d428699d8718068172d340f3e717e Mon Sep 17 00:00:00 2001 From: John D Pell Date: Fri, 28 Jan 2022 13:59:50 -0800 Subject: [PATCH 22/22] main: variable name cleanup --- bash_it.sh | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bash_it.sh b/bash_it.sh index b890f021..78d19b87 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -35,10 +35,10 @@ for _bash_it_main_file_lib in "${BASH_IT}/lib"/*.bash; do done # Load the global "enabled" directory, then enabled aliases, completion, plugins -# "file_type" param is empty so that files get sourced in glob order -for file_type in "" "aliases" "plugins" "completion"; do +# "_bash_it_main_file_type" param is empty so that files get sourced in glob order +for _bash_it_main_file_type in "" "aliases" "plugins" "completion"; do BASH_IT_LOG_PREFIX="core: reloader: " - source "${BASH_IT}/scripts/reloader.bash" "${file_type:+skip}" "$file_type" + source "${BASH_IT}/scripts/reloader.bash" "${_bash_it_main_file_type:+skip}" "$_bash_it_main_file_type" BASH_IT_LOG_PREFIX="core: main: " done @@ -63,12 +63,11 @@ if [[ -n "${BASH_IT_THEME:-}" ]]; then fi _log_debug "Loading custom aliases, completion, plugins..." -for file_type in "aliases" "completion" "plugins"; do - _bash_it_main_file_custom="${BASH_IT}/${file_type}/custom.${file_type}.bash" +for _bash_it_main_file_type in "aliases" "completion" "plugins"; do + _bash_it_main_file_custom="${BASH_IT}/${_bash_it_main_file_type}/custom.${_bash_it_main_file_type}.bash" if [[ -s "${_bash_it_main_file_custom}" ]]; then _bash-it-log-prefix-by-path "${_bash_it_main_file_custom}" _log_debug "Loading component..." - # shellcheck source-path=SCRIPTDIR/aliases source-path=SCRIPTDIR/completions source-path=SCRIPTDIR/plugins # shellcheck disable=SC1090 source "${_bash_it_main_file_custom}" fi @@ -109,4 +108,4 @@ fi for _bash_it_library_finalize_f in "${_bash_it_library_finalize_hook[@]:-}"; do eval "${_bash_it_library_finalize_f?}" # Use `eval` to achieve the same behavior as `$PROMPT_COMMAND`. done -unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}" file_type +unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}"