From 5478617a897376ea2a0721e3cd1f46ac6bbcce5b Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 25 Oct 2021 11:09:27 -0700 Subject: [PATCH 1/6] lib/search: code style cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Couldn't even `shellcheck` until I did a first pass...too much noise! ♥ --- lib/search.bash | 91 +++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 45 deletions(-) mode change 100755 => 100644 lib/search.bash diff --git a/lib/search.bash b/lib/search.bash old mode 100755 new mode 100644 index 8bd95b8e6d..20106c29c7 --- a/lib/search.bash +++ b/lib/search.bash @@ -53,29 +53,32 @@ _bash-it-search() { _param '2: [ term2 ]...' _example '$ _bash-it-search @git ruby -rvm rake bundler' - [[ -z "$(type _bash-it-array-contains-element 2>/dev/null)" ]] && source "${BASH_IT}/lib/utilities.bash" - local component - export BASH_IT_SEARCH_USE_COLOR=true - declare -a BASH_IT_COMPONENTS=(aliases plugins completions) + local BASH_IT_SEARCH_USE_COLOR="${BASH_IT_SEARCH_USE_COLOR:=true}" + local -a BASH_IT_COMPONENTS=(aliases plugins completions) - if [[ -z "$*" ]] ; then + if [[ $# -eq 0 ]] ; then _bash-it-search-help return 0 fi local -a args=() - for word in $@; do - if [[ ${word} == "--help" || ${word} == "-h" ]]; then + for word in "$@"; do + case "${word}" in + '-h'|'--help') _bash-it-search-help return 0 - elif [[ ${word} == "--refresh" || ${word} == "-r" ]]; then + ;; + '-r'|'--refresh') _bash-it-clean-component-cache - elif [[ ${word} == "--no-color" || ${word} == '-c' ]]; then - export BASH_IT_SEARCH_USE_COLOR=false - else - args=(${args[@]} ${word}) - fi + ;; + '-c'|'--no-color') + BASH_IT_SEARCH_USE_COLOR=false + ;; + *) + args+=("${word}") + ;; + esac done if [[ ${#args} -gt 0 ]]; then @@ -196,9 +199,8 @@ _bash-it-search-component() { local -a search_commands=(enable disable) for search_command in "${search_commands[@]}"; do if $(_bash-it-array-contains-element "--${search_command}" "$@"); then - component_singular=${component} - component_singular=${component_singular/es/} # aliases -> alias - component_singular=${component_singular/ns/n} # plugins -> plugin + component_singular="${component/es/}" # aliases -> alias + component_singular="${component_singular/ns/n}" # plugins -> plugin action="${search_command}" action_func="_${action}-${component_singular}" @@ -206,7 +208,7 @@ _bash-it-search-component() { fi done - local -a terms=($@) # passed on the command line + local -a terms=("$@") # passed on the command line unset exact_terms unset partial_terms @@ -225,26 +227,26 @@ _bash-it-search-component() { if [[ "${term:0:2}" == "--" ]] ; then continue elif [[ "${term:0:1}" == "-" ]] ; then - negative_terms=(${negative_terms[@]} "${search_term}") + negative_terms+=("${search_term}") elif [[ "${term:0:1}" == "@" ]] ; then if $(_bash-it-array-contains-element "${search_term}" "${component_list[@]}"); then - exact_terms=(${exact_terms[@]} "${search_term}") + exact_terms+=( "${search_term}") fi else - partial_terms=(${partial_terms[@]} $(_bash-it-component-list-matching "${component}" "${term}") ) + partial_terms+=($(_bash-it-component-list-matching "${component}" "${term}") ) fi done - local -a total_matches=( $(_bash-it-array-dedup ${exact_terms[@]} ${partial_terms[@]}) ) + local -a total_matches=( $(_bash-it-array-dedup "${exact_terms[@]}" "${partial_terms[@]}") ) unset matches declare -a matches=() - for match in ${total_matches[@]}; do + for match in "${total_matches[@]}"; do local include_match=true if [[ ${#negative_terms[@]} -gt 0 ]]; then ( _bash-it-component-term-matches-negation "${match}" "${negative_terms[@]}" ) && include_match=false fi - ( ${include_match} ) && matches=(${matches[@]} "${match}") + ( ${include_match} ) && matches+=("${match}") done _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]}" unset matches final_matches terms @@ -254,38 +256,37 @@ _bash-it-search-result() { local component="$1"; shift local action="$1"; shift local action_func="$1"; shift - local -a matches=($@) + local -a matches=("$@") local color_component color_enable color_disable color_off color_sep=':' - ( ${BASH_IT_SEARCH_USE_COLOR} ) && { + if ${BASH_IT_SEARCH_USE_COLOR} + then color_component='\e[1;34m' color_enable='\e[1;32m' suffix_enable='' suffix_disable='' color_disable='\e[0;0m' color_off='\e[0;0m' - } - - ( ${BASH_IT_SEARCH_USE_COLOR} ) || { + else color_component='' suffix_enable=' ✓ ︎' suffix_disable=' ' color_enable='' color_disable='' color_off='' - } + fi local match - local modified=0 + local -i modified=0 if [[ "${#matches[@]}" -gt 0 ]] ; then printf "${color_component}%13s${color_sep} ${color_off}" "${component}" for match in "${matches[@]}"; do - local enabled=0 + local -i enabled=0 ( _bash-it-component-item-is-enabled "${component}" "${match}" ) && enabled=1 local match_color compatible_action suffix opposite_suffix @@ -305,28 +306,27 @@ _bash-it-search-result() { } local m="${match}${suffix}" - local len - len=${#m} + local -i len=${#m} printf " ${match_color}${match}${suffix}" # print current state if [[ "${action}" == "${compatible_action}" ]]; then - if [[ ${action} == "enable" && ${BASH_IT_SEARCH_USE_COLOR} == false ]]; then - _bash-it-flash-term ${len} "${match}${suffix}" + if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == false ]]; then + _bash-it-flash-term "${len}" "${match}${suffix}" else _bash-it-erase-term ${len} fi modified=1 - result=$(${action_func} ${match}) + result=$("${action_func}" "${match}") local temp="color_${compatible_action}" - match_color=${!temp} - _bash-it-rewind ${len} + match_color="${!temp}" + _bash-it-rewind "${len}" printf "${match_color}${match}${opposite_suffix}" fi printf "${color_off}" done - [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache ${component} + [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache "${component}" printf "\n" fi } @@ -337,24 +337,25 @@ _bash-it-rewind() { } _bash-it-flash-term() { - local len="$1" - local match="$2" + local -i len="${1:-0}" + local match="${2:-}" local delay=0.1 local color - for color in ${text_black} ${echo_bold_blue} ${bold_yellow} ${bold_red} ${echo_bold_green} ; do - sleep ${delay} + for color in "${text_black}" "${echo_bold_blue}" "${bold_yellow}" "${bold_red}" "${echo_bold_green}" + do + sleep "${delay}" _bash-it-rewind "${len}" printf "${color}${match}" done } _bash-it-erase-term() { - local len="$1" + local -i len="${1:-0}" _bash-it-rewind ${len} for a in {0..30}; do [[ ${a} -gt ${len} ]] && break - printf "%.*s" $a " " + printf "%.*s" "$a" " " sleep 0.05 done } From afeb4d6e11d29ee0b3410c1a00043e45ad235591 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 8 Sep 2021 17:26:23 -0700 Subject: [PATCH 2/6] lib/search: `shellcheck` SC2076 SC2091 SC2004 SC2086 SC2207 --- lib/search.bash | 75 +++++++++++++++++++++++++------------------- test/lib/search.bats | 30 +++++++++--------- 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/lib/search.bash b/lib/search.bash index 20106c29c7..74764b2aa5 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +# shellcheck shell=bash # # Search by Konstantin Gredeskoul «github.com/kigster» #——————————————————————————————————————————————————————————————————————————————— @@ -91,7 +91,7 @@ _bash-it-search() { } _bash-it-search-help() { - printf "${echo_normal} + printf '%b' "${echo_normal} ${echo_underline_yellow}USAGE${echo_normal} bash-it search [-|@]term1 [-|@]term2 ... \\ @@ -177,28 +177,29 @@ _bash-it-component-term-matches-negation() { local match="$1"; shift local negative for negative in "$@"; do - [[ "${match}" =~ "${negative}" ]] && return 0 + [[ "${match}" =~ ${negative} ]] && return 0 done return 1 } _bash-it-search-component() { - local component="$1" - shift - _about 'searches for given terms amongst a given component' _param '1: component type, one of: [ aliases | plugins | completions ]' _param '2: term1 term2 @term3' _param '3: [-]term4 [-]term5 ...' _example '$ _bash-it-search-component aliases @git rake bundler -chruby' + local component="$1" + shift + # if one of the search terms is --enable or --disable, we will apply # this action to the matches further ` down. local component_singular action action_func - local -a search_commands=(enable disable) + local -a search_commands=('enable' 'disable') for search_command in "${search_commands[@]}"; do - if $(_bash-it-array-contains-element "--${search_command}" "$@"); then + if _bash-it-array-contains-element "--${search_command}" "$@" + then component_singular="${component/es/}" # aliases -> alias component_singular="${component_singular/ns/n}" # plugins -> plugin @@ -210,17 +211,17 @@ _bash-it-search-component() { local -a terms=("$@") # passed on the command line - unset exact_terms - unset partial_terms - unset negative_terms - local -a exact_terms=() # terms that should be included only if they match exactly local -a partial_terms=() # terms that should be included if they match partially local -a negative_terms=() # negated partial terms that should be excluded - unset component_list - local -a component_list=( $(_bash-it-component-list "${component}") ) - local term + local term line + + local -a component_list=() + while IFS='' read -r line + do + component_list+=("$line") + done < <(_bash-it-component-list "${component}") for term in "${terms[@]}"; do local search_term="${term:1}" @@ -229,27 +230,35 @@ _bash-it-search-component() { elif [[ "${term:0:1}" == "-" ]] ; then negative_terms+=("${search_term}") elif [[ "${term:0:1}" == "@" ]] ; then - if $(_bash-it-array-contains-element "${search_term}" "${component_list[@]}"); then + if _bash-it-array-contains-element "${search_term}" "${component_list[@]:-}" + then exact_terms+=( "${search_term}") fi else - partial_terms+=($(_bash-it-component-list-matching "${component}" "${term}") ) + while IFS='' read -r line + do + partial_terms+=( "$line" ) + done < <(_bash-it-component-list-matching "${component}" "${term}") + fi done - local -a total_matches=( $(_bash-it-array-dedup "${exact_terms[@]}" "${partial_terms[@]}") ) + local -a total_matches=() + while IFS='' read -r line + do + total_matches+=("$line") + done < <(_bash-it-array-dedup "${exact_terms[@]:-}" "${partial_terms[@]:-}") - unset matches - declare -a matches=() + local -a matches=() for match in "${total_matches[@]}"; do local include_match=true if [[ ${#negative_terms[@]} -gt 0 ]]; then - ( _bash-it-component-term-matches-negation "${match}" "${negative_terms[@]}" ) && include_match=false + ( _bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}" ) && include_match=false fi ( ${include_match} ) && matches+=("${match}") done - _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]}" - unset matches final_matches terms + + _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]:-}" } _bash-it-search-result() { @@ -291,14 +300,14 @@ _bash-it-search-result() { local match_color compatible_action suffix opposite_suffix - (( ${enabled} )) && { + (( enabled )) && { match_color=${color_enable} suffix=${suffix_enable} opposite_suffix=${suffix_disable} compatible_action="disable" } - (( ${enabled} )) || { + (( enabled )) || { match_color=${color_disable} suffix=${suffix_disable} opposite_suffix=${suffix_enable} @@ -308,22 +317,22 @@ _bash-it-search-result() { local m="${match}${suffix}" local -i len=${#m} - printf " ${match_color}${match}${suffix}" # print current state + printf '%b' " ${match_color}${match}${suffix}" # print current state if [[ "${action}" == "${compatible_action}" ]]; then if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == false ]]; then _bash-it-flash-term "${len}" "${match}${suffix}" else - _bash-it-erase-term ${len} + _bash-it-erase-term "${len}" fi modified=1 result=$("${action_func}" "${match}") local temp="color_${compatible_action}" match_color="${!temp}" _bash-it-rewind "${len}" - printf "${match_color}${match}${opposite_suffix}" + printf '%b' "${match_color}${match}${opposite_suffix}" fi - printf "${color_off}" + printf '%b' "${color_off}" done [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache "${component}" @@ -332,8 +341,8 @@ _bash-it-search-result() { } _bash-it-rewind() { - local len="$1" - printf "\033[${len}D" + local -i len="$1" + printf '%b' "\033[${len}D" } _bash-it-flash-term() { @@ -346,13 +355,13 @@ _bash-it-flash-term() { do sleep "${delay}" _bash-it-rewind "${len}" - printf "${color}${match}" + printf '%b' "${color}${match}" done } _bash-it-erase-term() { local -i len="${1:-0}" - _bash-it-rewind ${len} + _bash-it-rewind "${len}" for a in {0..30}; do [[ ${a} -gt ${len} ]] && break printf "%.*s" "$a" " " diff --git a/test/lib/search.bats b/test/lib/search.bats index c8a9502771..4d2ed614c9 100644 --- a/test/lib/search.bats +++ b/test/lib/search.bats @@ -28,42 +28,42 @@ function local_teardown { @test "search: plugin base" { export BASH_IT_SEARCH_USE_COLOR=false run _bash-it-search-component 'plugins' 'base' - assert_line -n 0 ' plugins: base ' + assert_line -n 0 ' plugins: base ' } @test "search: git" { run _bash-it-search 'git' --no-color - assert_line -n 0 ' aliases: git gitsvn ' + assert_line -n 0 ' aliases: git gitsvn ' assert_line -n 1 -p ' plugins:' for plugin in "autojump" "git" "gitstatus" "git-subrepo" "jgitflow" "jump" do echo $plugin assert_line -n 1 -p $plugin done - assert_line -n 2 ' completions: git git_flow git_flow_avh github-cli ' + assert_line -n 2 ' completions: git git_flow git_flow_avh github-cli ' } @test "search: ruby gem bundle rake rails" { run _bash-it-search rails ruby gem bundler rake --no-color - assert_line -n 0 ' aliases: bundler rails ' - assert_line -n 1 ' plugins: chruby chruby-auto rails ruby ' - assert_line -n 2 ' completions: bundler gem rake ' + assert_line -n 0 ' aliases: bundler rails ' + assert_line -n 1 ' plugins: chruby chruby-auto rails ruby ' + assert_line -n 2 ' completions: bundler gem rake ' } @test "search: rails ruby gem bundler rake -chruby" { run _bash-it-search rails ruby gem bundler rake -chruby --no-color - assert_line -n 0 ' aliases: bundler rails ' - assert_line -n 1 ' plugins: rails ruby ' - assert_line -n 2 ' completions: bundler gem rake ' + assert_line -n 0 ' aliases: bundler rails ' + assert_line -n 1 ' plugins: rails ruby ' + assert_line -n 2 ' completions: bundler gem rake ' } @test "search: @git" { run _bash-it-search '@git' --no-color - assert_line -n 0 ' aliases: git ' - assert_line -n 1 ' plugins: git ' - assert_line -n 2 ' completions: git ' + assert_line -n 0 ' aliases: git ' + assert_line -n 1 ' plugins: git ' + assert_line -n 2 ' completions: git ' } @test "search: @git --enable / --disable" { @@ -76,7 +76,7 @@ function local_teardown { run _bash-it-search '@git' --disable --no-color run _bash-it-search '@git' --no-color - assert_line -n 0 ' aliases: git ' - assert_line -n 0 ' aliases: git ' - assert_line -n 2 ' completions: git ' + assert_line -n 0 ' aliases: git ' + assert_line -n 1 ' plugins: git ' + assert_line -n 2 ' completions: git ' } From 64efe5239475a5753765aa906a2595ae743406bb Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sat, 9 Oct 2021 22:41:42 -0700 Subject: [PATCH 3/6] lib/search: fix `_bash-it-flash-term()` 1. `$text_black` isn't a parameter provided by _Bash It_. Typo? 2. `$bold_yellow` is meant for prompt strings and putputs `\[`; ditto `$bold_red`. 3. The color was never returned to normal after. --- lib/search.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/search.bash b/lib/search.bash index 74764b2aa5..d74ece44e1 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -351,7 +351,7 @@ _bash-it-flash-term() { local delay=0.1 local color - for color in "${text_black}" "${echo_bold_blue}" "${bold_yellow}" "${bold_red}" "${echo_bold_green}" + for color in "${echo_black-}" "${echo_bold_blue-}" "${echo_bold_yellow-}" "${echo_bold_red-}" "${echo_bold_green-}" "${echo_normal-}" do sleep "${delay}" _bash-it-rewind "${len}" From 8939e943c5589534606831bea66c8968af980ba1 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 25 Oct 2021 11:11:39 -0700 Subject: [PATCH 4/6] lib/search: fix usage statement `_bash-it-search()` SC2154 --- lib/search.bash | 57 +++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/search.bash b/lib/search.bash index d74ece44e1..2510aa2f45 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -91,8 +91,8 @@ _bash-it-search() { } _bash-it-search-help() { - printf '%b' "${echo_normal} -${echo_underline_yellow}USAGE${echo_normal} + printf '%b' "${echo_normal-} +${echo_underline_yellow-}USAGE${echo_normal-} bash-it search [-|@]term1 [-|@]term2 ... \\ [ --enable | -e ] \\ @@ -101,9 +101,9 @@ ${echo_underline_yellow}USAGE${echo_normal} [ --refresh | -r ] \\ [ --help | -h ] -${echo_underline_yellow}DESCRIPTION${echo_normal} +${echo_underline_yellow-}DESCRIPTION${echo_normal-} - Use ${echo_bold_green}search${echo_normal} bash-it command to search for a list of terms or term negations + Use ${echo_bold_green-}search${echo_normal-} bash-it command to search for a list of terms or term negations across all components: aliases, completions and plugins. Components that are enabled are shown in green (or with a check box if --no-color option is used). @@ -120,42 +120,42 @@ ${echo_underline_yellow}DESCRIPTION${echo_normal} * To perform an exact match, use character '@' in front of the term, eg. '@git' would only match aliases, plugins and completions named 'git'. -${echo_underline_yellow}FLAGS${echo_normal} - --enable | -e ${echo_purple}Enable all matching componenents.${echo_normal} - --disable | -d ${echo_purple}Disable all matching componenents.${echo_normal} - --help | -h ${echo_purple}Print this help.${echo_normal} - --refresh | -r ${echo_purple}Force a refresh of the search cache.${echo_normal} - --no-color | -c ${echo_purple}Disable color output and use monochrome text.${echo_normal} +${echo_underline_yellow-}FLAGS${echo_normal-} + --enable | -e ${echo_purple-}Enable all matching componenents.${echo_normal-} + --disable | -d ${echo_purple-}Disable all matching componenents.${echo_normal-} + --help | -h ${echo_purple-}Print this help.${echo_normal-} + --refresh | -r ${echo_purple-}Force a refresh of the search cache.${echo_normal-} + --no-color | -c ${echo_purple-}Disable color output and use monochrome text.${echo_normal-} -${echo_underline_yellow}EXAMPLES${echo_normal} +${echo_underline_yellow-}EXAMPLES${echo_normal-} - For example, ${echo_bold_green}bash-it search git${echo_normal} would match any alias, completion + For example, ${echo_bold_green-}bash-it search git${echo_normal-} would match any alias, completion or plugin that has the word 'git' in either the module name or it's description. You should see something like this when you run this command: - ${echo_bold_green}❯ bash-it search git${echo_bold_blue} - ${echo_bold_yellow}aliases: ${echo_bold_green}git ${echo_normal}gitsvn - ${echo_bold_yellow}plugins: ${echo_normal}autojump ${echo_bold_green}git ${echo_normal}git-subrepo jgitflow jump - ${echo_bold_yellow}completions: ${echo_bold_green}git ${echo_normal}git_flow git_flow_avh${echo_normal} + ${echo_bold_green-}❯ bash-it search git${echo_bold_blue-} + ${echo_bold_yellow-}aliases: ${echo_bold_green-}git ${echo_normal-}gitsvn + ${echo_bold_yellow-}plugins: ${echo_normal-}autojump ${echo_bold_green-}git ${echo_normal-}git-subrepo jgitflow jump + ${echo_bold_yellow-}completions: ${echo_bold_green-}git ${echo_normal-}git_flow git_flow_avh${echo_normal-} You can exclude some terms by prefixing a term with a minus, eg: - ${echo_bold_green}❯ bash-it search git -flow -svn${echo_bold_blue} - ${echo_bold_yellow}aliases: ${echo_normal}git - ${echo_bold_yellow}plugins: ${echo_normal}autojump git git-subrepo jump - ${echo_bold_yellow}completions: ${echo_normal}git${echo_normal} + ${echo_bold_green-}❯ bash-it search git -flow -svn${echo_bold_blue-} + ${echo_bold_yellow-}aliases: ${echo_normal-}git + ${echo_bold_yellow-}plugins: ${echo_normal-}autojump git git-subrepo jump + ${echo_bold_yellow-}completions: ${echo_normal-}git${echo_normal-} Finally, if you prefix a term with '@' symbol, that indicates an exact match. Note, that we also pass the '--enable' flag, which would ensure that all matches are automatically enabled. The example is below: - ${echo_bold_green}❯ bash-it search @git --enable${echo_bold_blue} - ${echo_bold_yellow}aliases: ${echo_normal}git - ${echo_bold_yellow}plugins: ${echo_normal}git - ${echo_bold_yellow}completions: ${echo_normal}git${echo_normal} + ${echo_bold_green-}❯ bash-it search @git --enable${echo_bold_blue-} + ${echo_bold_yellow-}aliases: ${echo_normal-}git + ${echo_bold_yellow-}plugins: ${echo_normal-}git + ${echo_bold_yellow-}completions: ${echo_normal-}git${echo_normal-} -${echo_underline_yellow}SUMMARY${echo_normal} +${echo_underline_yellow-}SUMMARY${echo_normal-} Take advantage of the search functionality to discover what Bash-It can do for you. Try searching for partial term matches, mix and match with the @@ -168,9 +168,9 @@ ${echo_underline_yellow}SUMMARY${echo_normal} } _bash-it-is-partial-match() { - local component="$1" - local term="$2" - _bash-it-component-help "${component}" | _bash-it-egrep -i -q -- "${term}" + local component="${1?}" + local term="${2?}" + _bash-it-component-help "${component}" | "_bash-it-egrep -i -q -- "${term}" } _bash-it-component-term-matches-negation() { @@ -325,6 +325,7 @@ _bash-it-search-result() { _bash-it-erase-term "${len}" fi modified=1 + # shellcheck disable=SC2034 # no idea if `$result` is ever used result=$("${action_func}" "${match}") local temp="color_${compatible_action}" match_color="${!temp}" From b8694ee140a92568c878cc9da1556f520810c472 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 26 Jan 2022 10:24:51 -0800 Subject: [PATCH 5/6] lib/search: `shfmt` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My apologies to future `git blame` hunters ♥ --- clean_files.txt | 1 + lib/search.bash | 425 ++++++++++++++++++++++++------------------------ 2 files changed, 212 insertions(+), 214 deletions(-) diff --git a/clean_files.txt b/clean_files.txt index 06b19f5d42..f74f40ebb4 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -83,6 +83,7 @@ completion/available/wpscan.completion.bash lib/helpers.bash lib/log.bash lib/preexec.bash +lib/search.bash lib/utilities.bash # plugins diff --git a/lib/search.bash b/lib/search.bash index 2510aa2f45..98db13c8a6 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -47,51 +47,51 @@ # completions: git # -_bash-it-search() { - _about 'searches for given terms amongst bash-it plugins, aliases and completions' - _param '1: term1' - _param '2: [ term2 ]...' - _example '$ _bash-it-search @git ruby -rvm rake bundler' - - local component - local BASH_IT_SEARCH_USE_COLOR="${BASH_IT_SEARCH_USE_COLOR:=true}" - local -a BASH_IT_COMPONENTS=(aliases plugins completions) - - if [[ $# -eq 0 ]] ; then - _bash-it-search-help - return 0 - fi - - local -a args=() - for word in "$@"; do +function _bash-it-search() { + _about 'searches for given terms amongst bash-it plugins, aliases and completions' + _param '1: term1' + _param '2: [ term2 ]...' + _example '$ _bash-it-search @git ruby -rvm rake bundler' + + local component + local BASH_IT_SEARCH_USE_COLOR="${BASH_IT_SEARCH_USE_COLOR:=true}" + local -a BASH_IT_COMPONENTS=(aliases plugins completions) + + if [[ $# -eq 0 ]]; then + _bash-it-search-help + return 0 + fi + + local -a args=() + for word in "$@"; do case "${word}" in - '-h'|'--help') - _bash-it-search-help - return 0 - ;; - '-r'|'--refresh') - _bash-it-clean-component-cache - ;; - '-c'|'--no-color') - BASH_IT_SEARCH_USE_COLOR=false - ;; - *) - args+=("${word}") - ;; + '-h' | '--help') + _bash-it-search-help + return 0 + ;; + '-r' | '--refresh') + _bash-it-clean-component-cache + ;; + '-c' | '--no-color') + BASH_IT_SEARCH_USE_COLOR=false + ;; + *) + args+=("${word}") + ;; esac - done + done - if [[ ${#args} -gt 0 ]]; then - for component in "${BASH_IT_COMPONENTS[@]}" ; do - _bash-it-search-component "${component}" "${args[@]}" - done - fi + if [[ ${#args} -gt 0 ]]; then + for component in "${BASH_IT_COMPONENTS[@]}"; do + _bash-it-search-component "${component}" "${args[@]}" + done + fi - return 0 + return 0 } -_bash-it-search-help() { - printf '%b' "${echo_normal-} +function _bash-it-search-help() { + printf '%b' "${echo_normal-} ${echo_underline_yellow-}USAGE${echo_normal-} bash-it search [-|@]term1 [-|@]term2 ... \\ @@ -167,205 +167,202 @@ ${echo_underline_yellow-}SUMMARY${echo_normal-} " } -_bash-it-is-partial-match() { - local component="${1?}" - local term="${2?}" - _bash-it-component-help "${component}" | "_bash-it-egrep -i -q -- "${term}" +function _bash-it-is-partial-match() { + local component="${1?}" + local term="${2?}" + _bash-it-component-help "${component}" | _bash-it-egrep -i -q -- "${term}" } -_bash-it-component-term-matches-negation() { - local match="$1"; shift - local negative - for negative in "$@"; do - [[ "${match}" =~ ${negative} ]] && return 0 - done +function _bash-it-component-term-matches-negation() { + local match="$1" + shift + local negative + for negative in "$@"; do + [[ "${match}" =~ ${negative} ]] && return 0 + done - return 1 + return 1 } -_bash-it-search-component() { - _about 'searches for given terms amongst a given component' - _param '1: component type, one of: [ aliases | plugins | completions ]' - _param '2: term1 term2 @term3' - _param '3: [-]term4 [-]term5 ...' - _example '$ _bash-it-search-component aliases @git rake bundler -chruby' - - local component="$1" - shift - - # if one of the search terms is --enable or --disable, we will apply - # this action to the matches further ` down. - local component_singular action action_func - local -a search_commands=('enable' 'disable') - for search_command in "${search_commands[@]}"; do - if _bash-it-array-contains-element "--${search_command}" "$@" - then - component_singular="${component/es/}" # aliases -> alias - component_singular="${component_singular/ns/n}" # plugins -> plugin - - action="${search_command}" - action_func="_${action}-${component_singular}" - break - fi - done - - local -a terms=("$@") # passed on the command line - - local -a exact_terms=() # terms that should be included only if they match exactly - local -a partial_terms=() # terms that should be included if they match partially - local -a negative_terms=() # negated partial terms that should be excluded - - local term line - - local -a component_list=() - while IFS='' read -r line - do +function _bash-it-search-component() { + _about 'searches for given terms amongst a given component' + _param '1: component type, one of: [ aliases | plugins | completions ]' + _param '2: term1 term2 @term3' + _param '3: [-]term4 [-]term5 ...' + _example '$ _bash-it-search-component aliases @git rake bundler -chruby' + + local component="$1" + shift + + # if one of the search terms is --enable or --disable, we will apply + # this action to the matches further ` down. + local component_singular= action= action_func= + local -a search_commands=('enable' 'disable') + for search_command in "${search_commands[@]}"; do + if _bash-it-array-contains-element "--${search_command}" "$@"; then + component_singular="${component/es/}" # aliases -> alias + component_singular="${component_singular/ns/n}" # plugins -> plugin + + action="${search_command}" + action_func="_${action}-${component_singular}" + break + fi + done + + local -a terms=("$@") # passed on the command line + + local -a exact_terms=() # terms that should be included only if they match exactly + local -a partial_terms=() # terms that should be included if they match partially + local -a negative_terms=() # negated partial terms that should be excluded + + local term line + + local -a component_list=() + while IFS='' read -r line; do component_list+=("$line") done < <(_bash-it-component-list "${component}") - for term in "${terms[@]}"; do - local search_term="${term:1}" - if [[ "${term:0:2}" == "--" ]] ; then - continue - elif [[ "${term:0:1}" == "-" ]] ; then - negative_terms+=("${search_term}") - elif [[ "${term:0:1}" == "@" ]] ; then - if _bash-it-array-contains-element "${search_term}" "${component_list[@]:-}" - then - exact_terms+=( "${search_term}") - fi - else - while IFS='' read -r line - do - partial_terms+=( "$line" ) + for term in "${terms[@]}"; do + local search_term="${term:1}" + if [[ "${term:0:2}" == "--" ]]; then + continue + elif [[ "${term:0:1}" == "-" ]]; then + negative_terms+=("${search_term}") + elif [[ "${term:0:1}" == "@" ]]; then + if _bash-it-array-contains-element "${search_term}" "${component_list[@]:-}"; then + exact_terms+=("${search_term}") + fi + else + while IFS='' read -r line; do + partial_terms+=("$line") done < <(_bash-it-component-list-matching "${component}" "${term}") - fi - done + fi + done - local -a total_matches=() - while IFS='' read -r line - do + local -a total_matches=() + while IFS='' read -r line; do total_matches+=("$line") done < <(_bash-it-array-dedup "${exact_terms[@]:-}" "${partial_terms[@]:-}") - local -a matches=() - for match in "${total_matches[@]}"; do - local include_match=true - if [[ ${#negative_terms[@]} -gt 0 ]]; then - ( _bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}" ) && include_match=false - fi - ( ${include_match} ) && matches+=("${match}") - done + local -a matches=() + for match in "${total_matches[@]}"; do + local include_match=true + if [[ ${#negative_terms[@]} -gt 0 ]]; then + (_bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}") && include_match=false + fi + (${include_match}) && matches+=("${match}") + done - _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]:-}" + _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]:-}" } -_bash-it-search-result() { - local component="$1"; shift - local action="$1"; shift - local action_func="$1"; shift - local -a matches=("$@") - - local color_component color_enable color_disable color_off - - color_sep=':' - - if ${BASH_IT_SEARCH_USE_COLOR} - then - color_component='\e[1;34m' - color_enable='\e[1;32m' - suffix_enable='' - suffix_disable='' - color_disable='\e[0;0m' - color_off='\e[0;0m' +function _bash-it-search-result() { + local component="$1" + shift + local action="$1" + shift + local action_func="$1" + shift + local -a matches=("$@") + + local color_component color_enable color_disable color_off + + color_sep=':' + + if ${BASH_IT_SEARCH_USE_COLOR}; then + color_component='\e[1;34m' + color_enable='\e[1;32m' + suffix_enable='' + suffix_disable='' + color_disable='\e[0;0m' + color_off='\e[0;0m' else - color_component='' - suffix_enable=' ✓ ︎' - suffix_disable=' ' - color_enable='' - color_disable='' - color_off='' + color_component='' + suffix_enable=' ✓ ︎' + suffix_disable=' ' + color_enable='' + color_disable='' + color_off='' fi - local match - local -i modified=0 - - if [[ "${#matches[@]}" -gt 0 ]] ; then - printf "${color_component}%13s${color_sep} ${color_off}" "${component}" - - for match in "${matches[@]}"; do - local -i enabled=0 - ( _bash-it-component-item-is-enabled "${component}" "${match}" ) && enabled=1 - - local match_color compatible_action suffix opposite_suffix - - (( enabled )) && { - match_color=${color_enable} - suffix=${suffix_enable} - opposite_suffix=${suffix_disable} - compatible_action="disable" - } - - (( enabled )) || { - match_color=${color_disable} - suffix=${suffix_disable} - opposite_suffix=${suffix_enable} - compatible_action="enable" - } - - local m="${match}${suffix}" - local -i len=${#m} - - printf '%b' " ${match_color}${match}${suffix}" # print current state - if [[ "${action}" == "${compatible_action}" ]]; then - if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == false ]]; then - _bash-it-flash-term "${len}" "${match}${suffix}" - else - _bash-it-erase-term "${len}" - fi - modified=1 - # shellcheck disable=SC2034 # no idea if `$result` is ever used - result=$("${action_func}" "${match}") - local temp="color_${compatible_action}" - match_color="${!temp}" - _bash-it-rewind "${len}" - printf '%b' "${match_color}${match}${opposite_suffix}" - fi - - printf '%b' "${color_off}" - done - - [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache "${component}" - printf "\n" - fi + local match + local -i modified=0 + + if [[ "${#matches[@]}" -gt 0 ]]; then + printf "${color_component}%13s${color_sep} ${color_off}" "${component}" + + for match in "${matches[@]}"; do + local -i enabled=0 + (_bash-it-component-item-is-enabled "${component}" "${match}") && enabled=1 + + local match_color compatible_action suffix opposite_suffix + + ((enabled)) && { + match_color=${color_enable} + suffix=${suffix_enable} + opposite_suffix=${suffix_disable} + compatible_action="disable" + } + + ((enabled)) || { + match_color=${color_disable} + suffix=${suffix_disable} + opposite_suffix=${suffix_enable} + compatible_action="enable" + } + + local m="${match}${suffix}" + local -i len=${#m} + + printf '%b' " ${match_color}${match}${suffix}" # print current state + if [[ "${action}" == "${compatible_action}" ]]; then + if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == false ]]; then + _bash-it-flash-term "${len}" "${match}${suffix}" + else + _bash-it-erase-term "${len}" + fi + modified=1 + # shellcheck disable=SC2034 # no idea if `$result` is ever used + result=$("${action_func}" "${match}") + local temp="color_${compatible_action}" + match_color="${!temp}" + _bash-it-rewind "${len}" + printf '%b' "${match_color}${match}${opposite_suffix}" + fi + + printf '%b' "${color_off}" + done + + [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache "${component}" + printf "\n" + fi } -_bash-it-rewind() { - local -i len="$1" - printf '%b' "\033[${len}D" +function _bash-it-rewind() { + local -i len="$1" + printf '%b' "\033[${len}D" } -_bash-it-flash-term() { - local -i len="${1:-0}" - local match="${2:-}" - local delay=0.1 - local color - - for color in "${echo_black-}" "${echo_bold_blue-}" "${echo_bold_yellow-}" "${echo_bold_red-}" "${echo_bold_green-}" "${echo_normal-}" - do - sleep "${delay}" - _bash-it-rewind "${len}" - printf '%b' "${color}${match}" - done +function _bash-it-flash-term() { + local -i len="${1:-0}" + local match="${2:-}" + local delay=0.1 + local color + + for color in "${echo_black-}" "${echo_bold_blue-}" "${echo_bold_yellow-}" "${echo_bold_red-}" "${echo_bold_green-}" "${echo_normal-}"; do + sleep "${delay}" + _bash-it-rewind "${len}" + printf '%b' "${color}${match}" + done } -_bash-it-erase-term() { - local -i len="${1:-0}" - _bash-it-rewind "${len}" - for a in {0..30}; do - [[ ${a} -gt ${len} ]] && break - printf "%.*s" "$a" " " - sleep 0.05 - done +function _bash-it-erase-term() { + local -i len="${1:-0}" + _bash-it-rewind "${len}" + for a in {0..30}; do + [[ ${a} -gt ${len} ]] && break + printf "%.*s" "$a" " " + sleep 0.05 + done } From 4cf2aae36e0be9ecde02ad333f308116d4e75c69 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 20 Oct 2021 22:42:10 -0400 Subject: [PATCH 6/6] lib/search: code cleanup Improve `_bash-it-erase-term()`, `_bash-it-flash-term()`, `_bash-it-rewind()`, `_bash-it-search-result()`, and `_bash-it-search-component()`. Minor tweaks to `_bash-it-is-partial-match()`, and `_bash-it-search()`. --- lib/search.bash | 98 ++++++++++++++++++++++++-------------------- test/lib/search.bats | 30 +++++++------- 2 files changed, 68 insertions(+), 60 deletions(-) mode change 100644 => 100755 test/lib/search.bats diff --git a/lib/search.bash b/lib/search.bash index 98db13c8a6..2da8f0054d 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -55,7 +55,7 @@ function _bash-it-search() { local component local BASH_IT_SEARCH_USE_COLOR="${BASH_IT_SEARCH_USE_COLOR:=true}" - local -a BASH_IT_COMPONENTS=(aliases plugins completions) + local -a BASH_IT_COMPONENTS=('aliases' 'plugins' 'completions') if [[ $# -eq 0 ]]; then _bash-it-search-help @@ -168,8 +168,8 @@ ${echo_underline_yellow-}SUMMARY${echo_normal-} } function _bash-it-is-partial-match() { - local component="${1?}" - local term="${2?}" + local component="${1?${FUNCNAME[0]}: component type must be specified}" + local term="${2:-}" _bash-it-component-help "${component}" | _bash-it-egrep -i -q -- "${term}" } @@ -191,12 +191,12 @@ function _bash-it-search-component() { _param '3: [-]term4 [-]term5 ...' _example '$ _bash-it-search-component aliases @git rake bundler -chruby' - local component="$1" + local component="${1?${FUNCNAME[0]}: component type must be specified}" shift # if one of the search terms is --enable or --disable, we will apply # this action to the matches further ` down. - local component_singular= action= action_func= + local component_singular action action_func local -a search_commands=('enable' 'disable') for search_command in "${search_commands[@]}"; do if _bash-it-array-contains-element "--${search_command}" "$@"; then @@ -247,30 +247,34 @@ function _bash-it-search-component() { local -a matches=() for match in "${total_matches[@]}"; do - local include_match=true + local -i include_match=1 if [[ ${#negative_terms[@]} -gt 0 ]]; then - (_bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}") && include_match=false + _bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}" && include_match=0 fi - (${include_match}) && matches+=("${match}") + ((include_match)) && matches+=("${match}") done - _bash-it-search-result "${component}" "${action}" "${action_func}" "${matches[@]:-}" + _bash-it-search-result "${component}" "${action:-}" "${action_func:-}" "${matches[@]:-}" } function _bash-it-search-result() { - local component="$1" + local component="${1?${FUNCNAME[0]}: component type must be specified}" shift - local action="$1" + local action="${1:-}" shift - local action_func="$1" + local action_func="${1:-}" shift - local -a matches=("$@") local color_component color_enable color_disable color_off + local color_sep=':' line - color_sep=':' + local -a matches=() + # Discard any empty arguments + while IFS='' read -r line; do + [[ -n "${line}" ]] && matches+=("$line") + done < <(_bash-it-array-dedup "${@}") - if ${BASH_IT_SEARCH_USE_COLOR}; then + if [[ "${BASH_IT_SEARCH_USE_COLOR}" == "true" ]]; then color_component='\e[1;34m' color_enable='\e[1;32m' suffix_enable='' @@ -290,37 +294,35 @@ function _bash-it-search-result() { local -i modified=0 if [[ "${#matches[@]}" -gt 0 ]]; then - printf "${color_component}%13s${color_sep} ${color_off}" "${component}" + printf "${color_component}%13s${color_sep}${color_off} " "${component}" for match in "${matches[@]}"; do local -i enabled=0 - (_bash-it-component-item-is-enabled "${component}" "${match}") && enabled=1 + _bash-it-component-item-is-enabled "${component}" "${match}" && enabled=1 local match_color compatible_action suffix opposite_suffix - ((enabled)) && { - match_color=${color_enable} - suffix=${suffix_enable} - opposite_suffix=${suffix_disable} + if ((enabled)); then + match_color="${color_enable}" + suffix="${suffix_enable}" + opposite_suffix="${suffix_disable}" compatible_action="disable" - } - - ((enabled)) || { - match_color=${color_disable} - suffix=${suffix_disable} - opposite_suffix=${suffix_enable} + else + match_color="${color_disable}" + suffix="${suffix_disable}" + opposite_suffix="${suffix_enable}" compatible_action="enable" - } + fi - local m="${match}${suffix}" - local -i len=${#m} + local matched="${match}${suffix}" + local -i len="${#matched}" - printf '%b' " ${match_color}${match}${suffix}" # print current state + printf '%b' "${match_color}${matched}" # print current state if [[ "${action}" == "${compatible_action}" ]]; then - if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == false ]]; then - _bash-it-flash-term "${len}" "${match}${suffix}" + if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == "true" ]]; then + _bash-it-flash-term "${len}" "${matched}" else - _bash-it-erase-term "${len}" + _bash-it-erase-term "${len}" "${matched}" fi modified=1 # shellcheck disable=SC2034 # no idea if `$result` is ever used @@ -331,38 +333,44 @@ function _bash-it-search-result() { printf '%b' "${match_color}${match}${opposite_suffix}" fi - printf '%b' "${color_off}" + printf '%b' "${color_off} " done - [[ ${modified} -gt 0 ]] && _bash-it-clean-component-cache "${component}" + ((modified)) && _bash-it-clean-component-cache "${component}" printf "\n" fi } function _bash-it-rewind() { - local -i len="$1" + local -i len="${1:-0}" printf '%b' "\033[${len}D" } function _bash-it-flash-term() { - local -i len="${1:-0}" - local match="${2:-}" + local -i len="${1:-0}" # redundant + local term="${2:-}" + # as currently implemented, `$match` has already been printed to screen the first time local delay=0.1 local color + [[ "${#term}" -gt 0 ]] && len="${#term}" for color in "${echo_black-}" "${echo_bold_blue-}" "${echo_bold_yellow-}" "${echo_bold_red-}" "${echo_bold_green-}" "${echo_normal-}"; do sleep "${delay}" _bash-it-rewind "${len}" - printf '%b' "${color}${match}" + printf '%b' "${color}${term}" done } function _bash-it-erase-term() { - local -i len="${1:-0}" + local -i len="${1:-0}" i + local delay=0.05 + local term="${2:-}" # calculate length ourselves + [[ "${#term}" -gt 0 ]] && len="${#term}" + _bash-it-rewind "${len}" - for a in {0..30}; do - [[ ${a} -gt ${len} ]] && break - printf "%.*s" "$a" " " - sleep 0.05 + # white-out the already-printed term by printing blanks + for ((i = 0; i <= len; i++)); do + printf "%.*s" "$i" " " + sleep "${delay}" done } diff --git a/test/lib/search.bats b/test/lib/search.bats old mode 100644 new mode 100755 index 4d2ed614c9..057951a0a5 --- a/test/lib/search.bats +++ b/test/lib/search.bats @@ -28,42 +28,42 @@ function local_teardown { @test "search: plugin base" { export BASH_IT_SEARCH_USE_COLOR=false run _bash-it-search-component 'plugins' 'base' - assert_line -n 0 ' plugins: base ' + assert_line -n 0 ' plugins: base ' } @test "search: git" { run _bash-it-search 'git' --no-color - assert_line -n 0 ' aliases: git gitsvn ' + assert_line -n 0 ' aliases: git gitsvn ' assert_line -n 1 -p ' plugins:' for plugin in "autojump" "git" "gitstatus" "git-subrepo" "jgitflow" "jump" do echo $plugin assert_line -n 1 -p $plugin done - assert_line -n 2 ' completions: git git_flow git_flow_avh github-cli ' + assert_line -n 2 ' completions: git git_flow git_flow_avh github-cli ' } @test "search: ruby gem bundle rake rails" { run _bash-it-search rails ruby gem bundler rake --no-color - assert_line -n 0 ' aliases: bundler rails ' - assert_line -n 1 ' plugins: chruby chruby-auto rails ruby ' - assert_line -n 2 ' completions: bundler gem rake ' + assert_line -n 0 ' aliases: bundler rails ' + assert_line -n 1 ' plugins: chruby chruby-auto rails ruby ' + assert_line -n 2 ' completions: bundler gem rake ' } @test "search: rails ruby gem bundler rake -chruby" { run _bash-it-search rails ruby gem bundler rake -chruby --no-color - assert_line -n 0 ' aliases: bundler rails ' - assert_line -n 1 ' plugins: rails ruby ' - assert_line -n 2 ' completions: bundler gem rake ' + assert_line -n 0 ' aliases: bundler rails ' + assert_line -n 1 ' plugins: rails ruby ' + assert_line -n 2 ' completions: bundler gem rake ' } @test "search: @git" { run _bash-it-search '@git' --no-color - assert_line -n 0 ' aliases: git ' - assert_line -n 1 ' plugins: git ' - assert_line -n 2 ' completions: git ' + assert_line -n 0 ' aliases: git ' + assert_line -n 1 ' plugins: git ' + assert_line -n 2 ' completions: git ' } @test "search: @git --enable / --disable" { @@ -76,7 +76,7 @@ function local_teardown { run _bash-it-search '@git' --disable --no-color run _bash-it-search '@git' --no-color - assert_line -n 0 ' aliases: git ' - assert_line -n 1 ' plugins: git ' - assert_line -n 2 ' completions: git ' + assert_line -n 0 ' aliases: git ' + assert_line -n 1 ' plugins: git ' + assert_line -n 2 ' completions: git ' }