add bash-it

This commit is contained in:
2022-05-05 22:20:02 +02:00
parent 6a62a35d0d
commit 43701f0590
490 changed files with 33047 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
# shellcheck shell=bash
: "${CLICOLOR:=$(tput colors)}"
export CLICOLOR
: "${CUSTOM_THEME_DIR:="${BASH_IT_CUSTOM:=${BASH_IT}/custom}/themes"}"
# Load the theme
# shellcheck disable=SC1090
if [[ -n "${BASH_IT_THEME:-}" ]]; then
if [[ -f "${BASH_IT_THEME}" ]]; then
source "${BASH_IT_THEME}"
elif [[ -f "$CUSTOM_THEME_DIR/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" ]]; then
source "$CUSTOM_THEME_DIR/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash"
else
source "$BASH_IT/themes/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash"
fi
fi
+91
View File
@@ -0,0 +1,91 @@
# shellcheck shell=bash
# shellcheck disable=SC2034
#
# A set of pre-defined color escape codes for use in prompts and with `echo`.
black="\[\e[0;30m\]"
red="\[\e[0;31m\]"
green="\[\e[0;32m\]"
yellow="\[\e[0;33m\]"
blue="\[\e[0;34m\]"
purple="\[\e[0;35m\]"
cyan="\[\e[0;36m\]"
white="\[\e[0;37m\]"
orange="\[\e[0;91m\]"
bold_black="\[\e[30;1m\]"
bold_red="\[\e[31;1m\]"
bold_green="\[\e[32;1m\]"
bold_yellow="\[\e[33;1m\]"
bold_blue="\[\e[34;1m\]"
bold_purple="\[\e[35;1m\]"
bold_cyan="\[\e[36;1m\]"
bold_white="\[\e[37;1m\]"
bold_orange="\[\e[91;1m\]"
underline_black="\[\e[30;4m\]"
underline_red="\[\e[31;4m\]"
underline_green="\[\e[32;4m\]"
underline_yellow="\[\e[33;4m\]"
underline_blue="\[\e[34;4m\]"
underline_purple="\[\e[35;4m\]"
underline_cyan="\[\e[36;4m\]"
underline_white="\[\e[37;4m\]"
underline_orange="\[\e[91;4m\]"
background_black="\[\e[40m\]"
background_red="\[\e[41m\]"
background_green="\[\e[42m\]"
background_yellow="\[\e[43m\]"
background_blue="\[\e[44m\]"
background_purple="\[\e[45m\]"
background_cyan="\[\e[46m\]"
background_white="\[\e[47;1m\]"
background_orange="\[\e[101m\]"
normal="\[\e[0m\]"
reset_color="\[\e[39m\]"
# These colors are meant to be used with `echo -e`
echo_black="\033[0;30m"
echo_red="\033[0;31m"
echo_green="\033[0;32m"
echo_yellow="\033[0;33m"
echo_blue="\033[0;34m"
echo_purple="\033[0;35m"
echo_cyan="\033[0;36m"
echo_white="\033[0;37;1m"
echo_orange="\033[0;91m"
echo_bold_black="\033[30;1m"
echo_bold_red="\033[31;1m"
echo_bold_green="\033[32;1m"
echo_bold_yellow="\033[33;1m"
echo_bold_blue="\033[34;1m"
echo_bold_purple="\033[35;1m"
echo_bold_cyan="\033[36;1m"
echo_bold_white="\033[37;1m"
echo_bold_orange="\033[91;1m"
echo_underline_black="\033[30;4m"
echo_underline_red="\033[31;4m"
echo_underline_green="\033[32;4m"
echo_underline_yellow="\033[33;4m"
echo_underline_blue="\033[34;4m"
echo_underline_purple="\033[35;4m"
echo_underline_cyan="\033[36;4m"
echo_underline_white="\033[37;4m"
echo_underline_orange="\033[91;4m"
echo_background_black="\033[40m"
echo_background_red="\033[41m"
echo_background_green="\033[42m"
echo_background_yellow="\033[43m"
echo_background_blue="\033[44m"
echo_background_purple="\033[45m"
echo_background_cyan="\033[46m"
echo_background_white="\033[47;1m"
echo_background_orange="\033[101m"
echo_normal="\033[0m"
echo_reset_color="\033[39m"
+61
View File
@@ -0,0 +1,61 @@
# shellcheck shell=bash
#
# Functions for measuring and reporting how long a command takes to run.
: "${COMMAND_DURATION_START_SECONDS:=${EPOCHREALTIME:-$SECONDS}}"
: "${COMMAND_DURATION_ICON:=🕘}"
: "${COMMAND_DURATION_MIN_SECONDS:=1}"
function _command_duration_pre_exec() {
COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}"
}
function _dynamic_clock_icon {
local clock_hand
# clock hand value is between 90 and 9b in hexadecimal.
# so between 144 and 155 in base 10.
printf -v clock_hand '%x' $(((${1:-${SECONDS}} % 12) + 144))
printf -v 'COMMAND_DURATION_ICON' '%b' "\xf0\x9f\x95\x$clock_hand"
}
function _command_duration() {
[[ -n "${BASH_IT_COMMAND_DURATION:-}" ]] || return
local command_duration=0 command_start="${COMMAND_DURATION_START_SECONDS:-0}"
local -i minutes=0 seconds=0 deciseconds=0
local -i command_start_seconds="${command_start%.*}"
local -i command_start_deciseconds=$((10#${command_start##*.}))
command_start_deciseconds="${command_start_deciseconds:0:1}"
local current_time="${EPOCHREALTIME:-$SECONDS}"
local -i current_time_seconds="${current_time%.*}"
local -i current_time_deciseconds="$((10#${current_time##*.}))"
current_time_deciseconds="${current_time_deciseconds:0:1}"
if [[ "${command_start_seconds:-0}" -gt 0 ]]; then
# seconds
command_duration="$((current_time_seconds - command_start_seconds))"
if ((current_time_deciseconds >= command_start_deciseconds)); then
deciseconds="$((current_time_deciseconds - command_start_deciseconds))"
else
((command_duration -= 1))
deciseconds="$((10 - (command_start_deciseconds - current_time_deciseconds)))"
fi
else
command_duration=0
fi
if ((command_duration > 0)); then
minutes=$((command_duration / 60))
seconds=$((command_duration % 60))
fi
_dynamic_clock_icon "${command_duration}"
if ((minutes > 0)); then
printf "%s %s%dm %ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$minutes" "$seconds"
elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then
printf "%s %s%d.%01ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$seconds" "$deciseconds"
fi
}
_bash_it_library_finalize_hook+=("safe_append_preexec '_command_duration_pre_exec'")
File diff suppressed because it is too large Load Diff
+49
View File
@@ -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')
+100
View File
@@ -0,0 +1,100 @@
# shellcheck shell=bash
#
# A collection of logging functions.
# Declare log severity levels, matching syslog numbering
: "${BASH_IT_LOG_LEVEL_FATAL:=1}"
: "${BASH_IT_LOG_LEVEL_ERROR:=3}"
: "${BASH_IT_LOG_LEVEL_WARNING:=4}"
: "${BASH_IT_LOG_LEVEL_ALL:=6}"
: "${BASH_IT_LOG_LEVEL_INFO:=6}"
: "${BASH_IT_LOG_LEVEL_TRACE:=7}"
readonly "${!BASH_IT_LOG_LEVEL_@}"
function _bash-it-log-prefix-by-path() {
local component_path="${1?${FUNCNAME[0]}: path specification required}"
local without_extension component_directory
local component_filename component_type component_name
# get the directory, if any
component_directory="${component_path%/*}"
# drop the directory, if any
component_filename="${component_path##*/}"
# strip the file extension
without_extension="${component_filename%.bash}"
# strip before the last dot
component_type="${without_extension##*.}"
# strip component type, but try not to strip other words
# - aliases, completions, plugins, themes
component_name="${without_extension%.[acpt][hlo][eimu]*[ens]}"
# Finally, strip load priority prefix
component_name="${component_name##[[:digit:]][[:digit:]][[:digit:]]"${BASH_IT_LOAD_PRIORITY_SEPARATOR:----}"}"
# best-guess for files without a type
if [[ "${component_type:-${component_name}}" == "${component_name}" ]]; then
if [[ "${component_directory}" == *'vendor'* ]]; then
component_type='vendor'
else
component_type="${component_directory##*/}"
fi
fi
# shellcheck disable=SC2034
BASH_IT_LOG_PREFIX="${component_type:-lib}: $component_name"
}
function _has_colors() {
# Check that stdout is a terminal, and that it has at least 8 colors.
[[ -t 1 && "${CLICOLOR:=$(tput colors 2> /dev/null)}" -ge 8 ]]
}
function _bash-it-log-message() {
: _about 'Internal function used for logging, uses BASH_IT_LOG_PREFIX as a prefix'
: _param '1: color of the message'
: _param '2: log level to print before the prefix'
: _param '3: message to log'
: _group 'log'
local prefix="${BASH_IT_LOG_PREFIX:-default}"
local color="${1-${echo_cyan:-}}"
local level="${2:-TRACE}"
local message="${level%: }: ${prefix%: }: ${3?}"
if _has_colors; then
printf '%b%s%b\n' "${color}" "${message}" "${echo_normal:-}"
else
printf '%s\n' "${message}"
fi
}
function _log_debug() {
: _about 'log a debug message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_INFO'
: _param '1: message to log'
: _example '$ _log_debug "Loading plugin git..."'
: _group 'log'
if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_INFO?}" ]]; then
_bash-it-log-message "${echo_green:-}" "DEBUG: " "$1"
fi
}
function _log_warning() {
: _about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_WARNING'
: _param '1: message to log'
: _example '$ _log_warning "git binary not found, disabling git plugin..."'
: _group 'log'
if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_WARNING?}" ]]; then
_bash-it-log-message "${echo_yellow:-}" " WARN: " "$1"
fi
}
function _log_error() {
: _about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_ERROR'
: _param '1: message to log'
: _example '$ _log_error "Failed to load git plugin..."'
: _group 'log'
if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_ERROR?}" ]]; then
_bash-it-log-message "${echo_red:-}" "ERROR: " "$1"
fi
}
+75
View File
@@ -0,0 +1,75 @@
# shellcheck shell=bash
# shellcheck disable=SC2034
#
# Load the `bash-preexec.sh` library, and define helper functions
## Prepare, load, fix, and install `bash-preexec.sh`
# Disable `$PROMPT_COMMAND` modification for now.
__bp_delay_install="delayed"
# shellcheck source-path=SCRIPTDIR/../vendor/github.com/rcaloras/bash-preexec
source "${BASH_IT?}/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh"
# Block damanaging user's `$HISTCONTROL`
function __bp_adjust_histcontrol() { :; }
# Don't fail on readonly variables
function __bp_require_not_readonly() { :; }
# For performance, testing, and to avoid unexpected behavior: disable DEBUG traps in subshells.
# See bash-it/bash-it#1040 and rcaloras/bash-preexec#26
: "${__bp_enable_subshells:=}" # blank
# Modify `$PROMPT_COMMAND` in finalize hook
_bash_it_library_finalize_hook+=('__bp_install_after_session_init')
## Helper functions
function __check_precmd_conflict() {
local f
__bp_trim_whitespace f "${1?}"
_bash-it-array-contains-element "${f}" "${precmd_functions[@]}"
}
function __check_preexec_conflict() {
local f
__bp_trim_whitespace f "${1?}"
_bash-it-array-contains-element "${f}" "${preexec_functions[@]}"
}
function safe_append_prompt_command() {
local prompt_re prompt_er f
if [[ "${bash_preexec_imported:-${__bp_imported:-missing}}" == "defined" ]]; then
# We are using bash-preexec
__bp_trim_whitespace f "${1?}"
if ! __check_precmd_conflict "${f}"; then
precmd_functions+=("${f}")
fi
else
# Match on word-boundaries
prompt_re='(^|[^[:alnum:]_])'
prompt_er='([^[:alnum:]_]|$)'
if [[ ${PROMPT_COMMAND} =~ ${prompt_re}"${1}"${prompt_er} ]]; then
return
elif [[ -z ${PROMPT_COMMAND} ]]; then
PROMPT_COMMAND="${1}"
else
PROMPT_COMMAND="${1};${PROMPT_COMMAND}"
fi
fi
}
function safe_append_preexec() {
local prompt_re f
if [[ "${bash_preexec_imported:-${__bp_imported:-missing}}" == "defined" ]]; then
# We are using bash-preexec
__bp_trim_whitespace f "${1?}"
if ! __check_preexec_conflict "${f}"; then
preexec_functions+=("${f}")
fi
else
_log_error "${FUNCNAME[0]}: can't append to preexec hook because _bash-preexec.sh_ hasn't been loaded"
fi
}
+34
View File
@@ -0,0 +1,34 @@
# shellcheck shell=bash
#
# Displays the prompt from each _Bash It_ theme.
function _bash-it-preview() {
local BASH_IT_THEME BASH_IT_LOG_LEVEL
local themes IFS=$'\n' cur
if [[ $# -gt '0' ]]; then
themes=("$@")
else
themes=("${BASH_IT?}/themes"/*/*.theme.bash)
themes=("${themes[@]##*/}")
themes=("${themes[@]%.theme.bash}")
fi
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?}/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
+373
View File
@@ -0,0 +1,373 @@
# shellcheck shell=bash
#
# Search by Konstantin Gredeskoul «github.com/kigster»
#———————————————————————————————————————————————————————————————————————————————
# This function returns list of aliases, plugins and completions in bash-it,
# whose name or description matches one of the search terms provided as arguments.
#
# Usage:
# bash-it search [-|@]term1 [-|@]term2 ... \
# [ --enable | -e ] \
# [ --disable | -d ] \
# [ --no-color | -c ] \
# [ --refresh | -r ] \
# [ --help | -h ]
#
# Single dash, as in "-chruby", indicates a negative search term.
# Double dash indicates a command that is to be applied to the search result.
# At the moment only --help, --enable and --disable are supported.
# An '@' sign indicates an exact (not partial) match.
#
# Examples:
# bash-it search ruby rbenv rvm gem rake
# aliases: bundler
# plugins: chruby chruby-auto ruby rbenv rvm ruby
# completions: rvm gem rake
#
# bash-it search ruby rbenv rvm gem rake -chruby
# aliases: bundler
# plugins: ruby rbenv rvm ruby
# completions: rvm gem rake
#
# Examples of enabling or disabling results of the search:
#
# bash-it search ruby
# aliases: bundler
# plugins: chruby chruby-auto ruby
#
# bash-it search ruby -chruby --enable
# aliases: bundler
# plugins: ruby
#
# Examples of using exact match:
# bash-it search @git @ruby
# aliases: git
# plugins: git ruby
# completions: git
#
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-component-cache-clean
;;
'-c' | '--no-color')
BASH_IT_SEARCH_USE_COLOR=false
;;
*)
args+=("${word}")
;;
esac
done
if [[ ${#args} -gt 0 ]]; then
for component in "${BASH_IT_COMPONENTS[@]}"; do
_bash-it-search-component "${component}" "${args[@]}"
done
fi
return 0
}
function _bash-it-search-help() {
printf '%b' "${echo_normal-}
${echo_underline_yellow-}USAGE${echo_normal-}
bash-it search [-|@]term1 [-|@]term2 ... \\
[ --enable | -e ] \\
[ --disable | -d ] \\
[ --no-color | -c ] \\
[ --refresh | -r ] \\
[ --help | -h ]
${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
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).
In addition to simply finding the right component, you can use the results
of the search to enable or disable all components that the search returns.
When search is used to enable/disable components it becomes clear that
you must be able to perform not just a partial match, but an exact match,
as well as be able to exclude some components.
* To exclude a component (or all components matching a substring) use
a search term with minus as a prefix, eg '-flow'
* 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-}EXAMPLES${echo_normal-}
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-}
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-}
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_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
negative terms, or specify an exact matches of any number of terms. Once
you created the search command that returns ONLY the modules you need,
simply append '--enable' or '--disable' at the end to activate/deactivate
each module.
"
}
function _bash-it-is-partial-match() {
local component="${1?${FUNCNAME[0]}: component type must be specified}"
local term="${2:-}"
_bash-it-component-help "${component}" | _bash-it-egrep -i -q -- "${term}"
}
function _bash-it-component-term-matches-negation() {
local match="$1"
shift
local negative
for negative in "$@"; do
[[ "${match}" =~ ${negative} ]] && return 0
done
return 1
}
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?${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 -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")
done < <(_bash-it-component-list-matching "${component}" "${term}")
fi
done
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 -i include_match=1
if [[ ${#negative_terms[@]} -gt 0 ]]; then
_bash-it-component-term-matches-negation "${match}" "${negative_terms[@]:-}" && include_match=0
fi
((include_match)) && matches+=("${match}")
done
_bash-it-search-result "${component}" "${action:-}" "${action_func:-}" "${matches[@]:-}"
}
function _bash-it-search-result() {
local component="${1?${FUNCNAME[0]}: component type must be specified}"
shift
local action="${1:-}"
shift
local action_func="${1:-}"
shift
local color_component color_enable color_disable color_off
local match_color compatible_action suffix opposite_suffix
local color_sep=':' line match matched temp
local -i modified=0 enabled=0 len
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}" == "true" ]]; 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=''
fi
if [[ "${#matches[@]}" -gt 0 ]]; then
printf "${color_component}%13s${color_sep}${color_off} " "${component}"
for match in "${matches[@]}"; do
enabled=0
_bash-it-component-item-is-enabled "${component}" "${match}" && enabled=1
if ((enabled)); then
match_color="${color_enable}"
suffix="${suffix_enable}"
opposite_suffix="${suffix_disable}"
compatible_action="disable"
else
match_color="${color_disable}"
suffix="${suffix_disable}"
opposite_suffix="${suffix_enable}"
compatible_action="enable"
fi
matched="${match}${suffix}"
len="${#matched}"
printf '%b' "${match_color}${matched}" # print current state
if [[ "${action}" == "${compatible_action}" ]]; then
if [[ "${action}" == "enable" && "${BASH_IT_SEARCH_USE_COLOR}" == "true" ]]; then
_bash-it-flash-term "${len}" "${matched}"
else
_bash-it-erase-term "${len}" "${matched}"
fi
modified=1
# shellcheck disable=SC2034 # no idea if `$result` is ever used
result=$("${action_func}" "${match}")
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)) && _bash-it-component-cache-clean "${component}"
printf "\n"
fi
}
function _bash-it-rewind() {
local -i len="${1:-0}"
printf '%b' "\033[${len}D"
}
function _bash-it-flash-term() {
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.2
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}${term}"
done
}
function _bash-it-erase-term() {
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}"
# white-out the already-printed term by printing blanks
for ((i = 0; i <= len; i++)); do
printf "%.*s" "$i" " "
sleep "${delay}"
done
}
+198
View File
@@ -0,0 +1,198 @@
# shellcheck shell=bash
#
# A collection of reusable functions.
###########################################################################
# Generic utilies
###########################################################################
function _bash-it-get-component-name-from-path() {
local filename
# filename without path
filename="${1##*/}"
# filename without path or priority
filename="${filename##*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}"}"
# filename without path, priority or extension
echo "${filename%.*.bash}"
}
function _bash-it-get-component-type-from-path() {
local filename
# filename without path
filename="${1##*/}"
# filename without extension
filename="${filename%.bash}"
# extension without priority or name
filename="${filename##*.}"
echo "${filename}"
}
# This function searches an array for an exact match against the term passed
# as the first argument to the function. This function exits as soon as
# a match is found.
#
# Returns:
# 0 when a match is found, otherwise 1.
#
# Examples:
# $ declare -a fruits=(apple orange pear mandarin)
#
# $ _bash-it-array-contains-element apple "@{fruits[@]}" && echo 'contains apple'
# contains apple
#
# $ if _bash-it-array-contains-element pear "${fruits[@]}"; then
# echo "contains pear!"
# fi
# contains pear!
#
#
function _bash-it-array-contains-element() {
local e element="${1?}"
shift
for e in "$@"; do
[[ "$e" == "${element}" ]] && return 0
done
return 1
}
# Dedupe an array (without embedded newlines).
function _bash-it-array-dedup() {
printf '%s\n' "$@" | sort -u
}
# Outputs a full path of the grep found on the filesystem
function _bash-it-grep() {
: "${BASH_IT_GREP:=$(type -P egrep || type -P grep)}"
printf "%s" "${BASH_IT_GREP:-/usr/bin/grep}"
}
# Runs `grep` with extended regular expressions
function _bash-it-egrep() {
: "${BASH_IT_GREP:=$(type -P egrep || type -P grep)}"
"${BASH_IT_GREP:-/usr/bin/grep}" -E "$@"
}
###########################################################################
# Component-specific functions (component is either an alias, a plugin, or a
# completion).
###########################################################################
function _bash-it-component-help() {
local component file func
_bash-it-component-pluralize "${1}" component
_bash-it-component-cache-file "${component}" file
if [[ ! -s "${file?}" || -z "$(find "${file}" -mmin -300)" ]]; then
func="_bash-it-${component?}"
"${func}" | _bash-it-egrep '\[[x ]\]' >| "${file}"
fi
cat "${file}"
}
function _bash-it-component-cache-file() {
local _component_to_cache _file_path _result="${2:-${FUNCNAME[0]//-/_}}"
_bash-it-component-pluralize "${1?${FUNCNAME[0]}: component name required}" _component_to_cache
_file_path="${XDG_CACHE_HOME:-${HOME?}/.cache}/bash/${_component_to_cache?}"
[[ -f "${_file_path}" ]] || mkdir -p "${_file_path%/*}"
printf -v "${_result?}" '%s' "${_file_path}"
}
function _bash-it-component-singularize() {
local _result="${2:-${FUNCNAME[0]//-/_}}"
local _component_to_single="${1?${FUNCNAME[0]}: component name required}"
local -i len="$((${#_component_to_single} - 2))"
if [[ "${_component_to_single:${len}:2}" == 'ns' ]]; then
_component_to_single="${_component_to_single%s}"
elif [[ "${_component_to_single}" == "aliases" ]]; then
_component_to_single="${_component_to_single%es}"
fi
printf -v "${_result?}" '%s' "${_component_to_single}"
}
function _bash-it-component-pluralize() {
local _result="${2:-${FUNCNAME[0]//-/_}}"
local _component_to_plural="${1?${FUNCNAME[0]}: component name required}"
local -i len="$((${#_component_to_plural} - 1))"
# pluralize component name for consistency
if [[ "${_component_to_plural:${len}:1}" != 's' ]]; then
_component_to_plural="${_component_to_plural}s"
elif [[ "${_component_to_plural}" == "alias" ]]; then
_component_to_plural="${_component_to_plural}es"
fi
printf -v "${_result?}" '%s' "${_component_to_plural}"
}
function _bash-it-component-cache-clean() {
local component="${1:-}"
local cache
local -a components=('aliases' 'plugins' 'completions')
if [[ -z "${component}" ]]; then
for component in "${components[@]}"; do
_bash-it-component-cache-clean "${component}"
done
else
_bash-it-component-cache-file "${component}" cache
: >| "${cache:?}"
fi
}
# Returns an array of items within each compoenent.
function _bash-it-component-list() {
local IFS=$'\n' component="$1"
_bash-it-component-help "${component}" | awk '{print $1}' | sort -u
}
function _bash-it-component-list-matching() {
local component="$1"
shift
local term="$1"
_bash-it-component-help "${component}" | _bash-it-egrep -- "${term}" | awk '{print $1}' | sort -u
}
function _bash-it-component-list-enabled() {
local IFS=$'\n' component="$1"
_bash-it-component-help "${component}" | _bash-it-egrep '\[x\]' | awk '{print $1}' | sort -u
}
function _bash-it-component-list-disabled() {
local IFS=$'\n' component="$1"
_bash-it-component-help "${component}" | _bash-it-egrep -v '\[x\]' | awk '{print $1}' | sort -u
}
# Checks if a given item is enabled for a particular component/file-type.
#
# Returns:
# 0 if an item of the component is enabled, 1 otherwise.
#
# Examples:
# _bash-it-component-item-is-enabled alias git && echo "git alias is enabled"
function _bash-it-component-item-is-enabled() {
local component_type item_name each_file
if [[ -f "${1?}" ]]; then
item_name="$(_bash-it-get-component-name-from-path "${1}")"
component_type="$(_bash-it-get-component-type-from-path "${1}")"
else
component_type="${1}" item_name="${2?}"
fi
for each_file in "${BASH_IT}/enabled"/*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}${item_name}.${component_type}"*."bash" \
"${BASH_IT}/${component_type}"*/"enabled/${item_name}.${component_type}"*."bash" \
"${BASH_IT}/${component_type}"*/"enabled"/*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}${item_name}.${component_type}"*."bash"; do
if [[ -f "${each_file}" ]]; then
return 0
fi
done
return 1
}
# Checks if a given item is disabled for a particular component/file-type.
#
# Returns:
# 0 if an item of the component is enabled, 1 otherwise.
#
# Examples:
# _bash-it-component-item-is-disabled alias git && echo "git aliases are disabled"
function _bash-it-component-item-is-disabled() {
! _bash-it-component-item-is-enabled "$@"
}