diff --git a/.gitignore b/.gitignore index a17b6e82..8e6f12a1 100755 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,8 @@ bats enabled/* /enabled tmp/ + +# Do not save profiles +profiles/* +# apart from the default one +!profiles/default.bash_it diff --git a/bash_it.sh b/bash_it.sh index de655e81..bda3407e 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -137,13 +137,6 @@ elif [ -s /Applications/Preview.app ]; then PREVIEW="/Applications/Preview.app" fi -# Load all the Jekyll stuff - -if [ -e "$HOME/.jekyllconfig" ]; then - # shellcheck disable=SC1090 - . "$HOME/.jekyllconfig" -fi - # BASH_IT_RELOAD_LEGACY is set. if ! _command_exists reload && [[ -n "${BASH_IT_RELOAD_LEGACY:-}" ]]; then case $OSTYPE in diff --git a/clean_files.txt b/clean_files.txt index 53765a5f..8c8b3fed 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -97,6 +97,8 @@ plugins/available/history-search.plugin.bash plugins/available/history-substring-search.plugin.bash plugins/available/history.plugin.bash plugins/available/hub.plugin.bash +plugins/available/java.plugin.bash +plugins/available/jekyll.plugin.bash plugins/available/jump.plugin.bash plugins/available/less-pretty-cat.plugin.bash plugins/available/node.plugin.bash diff --git a/completion/available/bash-it.completion.bash b/completion/available/bash-it.completion.bash index 4fdd72d6..18cd241a 100644 --- a/completion/available/bash-it.completion.bash +++ b/completion/available/bash-it.completion.bash @@ -57,6 +57,18 @@ _bash-it-comp-list-available() COMPREPLY=( $(compgen -W "${enabled_things}" -- ${cur}) ) } +_bash-it-comp-list-profiles() +{ + local profiles + + profiles=$(for f in `compgen -G "${BASH_IT}/profiles/*.bash_it" | sort -d`; + do + basename $f | sed -e 's/.bash_it//g' + done) + + COMPREPLY=( $(compgen -W "${profiles}" -- ${cur}) ) +} + _bash-it-comp() { local cur prev opts @@ -65,7 +77,7 @@ _bash-it-comp() prev="${COMP_WORDS[COMP_CWORD-1]}" chose_opt="${COMP_WORDS[1]}" file_type="${COMP_WORDS[2]}" - opts="disable enable help migrate reload restart doctor search show update version" + opts="disable enable help migrate reload restart profile doctor search show update version" case "${chose_opt}" in show) local show_args="aliases completions plugins" @@ -82,6 +94,33 @@ _bash-it-comp() return 0 fi ;; + profile) + case "${file_type}" in + load) + if [[ "load" == "$prev" ]]; then + _bash-it-comp-list-profiles + fi + return 0 + ;; + rm) + if [[ "rm" == "$prev" ]]; then + _bash-it-comp-list-profiles + fi + return 0 + ;; + save) + return 0 + ;; + list) + return 0 + ;; + *) + local profile_args="load save list rm" + COMPREPLY=( $(compgen -W "${profile_args}" -- ${cur}) ) + return 0 + ;; + esac + ;; doctor) local doctor_args="errors warnings all" COMPREPLY=( $(compgen -W "${doctor_args}" -- ${cur}) ) diff --git a/completion/available/defaults.completion.bash b/completion/available/defaults.completion.bash index c43c0aae..39d7ea95 100644 --- a/completion/available/defaults.completion.bash +++ b/completion/available/defaults.completion.bash @@ -1,175 +1,5 @@ -# defaults -# Bash command line completion for defaults -# -# Created by Jonathon Mah on 2006-11-08. -# Copyright 2006 Playhaus. All rights reserved. -# -# Version 1.0 (2006-11-08) +# shellcheck shell=bash - -_defaults_domains() -{ - local cur - COMPREPLY=() - cur=${COMP_WORDS[COMP_CWORD]} - - local domains=$( defaults domains | sed -e 's/, /:/g' | tr : '\n' | sed -e 's/ /\\ /g' | grep "^$cur" ) - local IFS=$'\n' - COMPREPLY=( $domains ) - if [[ $( echo '-app' | grep "^$cur" ) ]]; then - COMPREPLY[${#COMPREPLY[@]}]="-app" - fi - - return 0 -} - - -_defaults() -{ - local cur prev host_opts cmds cmd domain keys key_index - cur=${COMP_WORDS[COMP_CWORD]} - prev=${COMP_WORDS[COMP_CWORD-1]} - - host_opts='-currentHost -host' - cmds='read read-type write rename delete domains find help' - - if [[ $COMP_CWORD -eq 1 ]]; then - COMPREPLY=( $( compgen -W "$host_opts $cmds" -- $cur ) ) - return 0 - elif [[ $COMP_CWORD -eq 2 ]]; then - if [[ "$prev" == "-currentHost" ]]; then - COMPREPLY=( $( compgen -W "$cmds" -- $cur ) ) - return 0 - elif [[ "$prev" == "-host" ]]; then - _known_hosts -a - return 0 - else - _defaults_domains - return 0 - fi - elif [[ $COMP_CWORD -eq 3 ]]; then - if [[ ${COMP_WORDS[1]} == "-host" ]]; then - _defaults_domains - return 0 - fi - fi - - # Both a domain and command have been specified - - if [[ ${COMP_WORDS[1]} == [${cmds// /|}] ]]; then - cmd=${COMP_WORDS[1]} - domain=${COMP_WORDS[2]} - key_index=3 - if [[ "$domain" == "-app" ]]; then - if [[ $COMP_CWORD -eq 3 ]]; then - # Completing application name. Can't help here, sorry - return 0 - fi - domain="-app ${COMP_WORDS[3]}" - key_index=4 - fi - elif [[ ${COMP_WORDS[2]} == "-currentHost" ]] && [[ ${COMP_WORDS[2]} == [${cmds// /|}] ]]; then - cmd=${COMP_WORDS[2]} - domain=${COMP_WORDS[3]} - key_index=4 - if [[ "$domain" == "-app" ]]; then - if [[ $COMP_CWORD -eq 4 ]]; then - # Completing application name. Can't help here, sorry - return 0 - fi - domain="-app ${COMP_WORDS[4]}" - key_index=5 - fi - elif [[ ${COMP_WORDS[3]} == "-host" ]] && [[ ${COMP_WORDS[3]} == [${cmds// /|}] ]]; then - cmd=${COMP_WORDS[3]} - domain=${COMP_WORDS[4]} - key_index=5 - if [[ "$domain" == "-app" ]]; then - if [[ $COMP_CWORD -eq 5 ]]; then - # Completing application name. Can't help here, sorry - return 0 - fi - domain="-app ${COMP_WORDS[5]}" - key_index=6 - fi - fi - - keys=$( defaults read $domain 2>/dev/null | sed -n -e '/^ [^}) ]/p' | sed -e 's/^ \([^" ]\{1,\}\) = .*$/\1/g' -e 's/^ "\([^"]\{1,\}\)" = .*$/\1/g' | sed -e 's/ /\\ /g' ) - - case $cmd in - read|read-type) - # Complete key - local IFS=$'\n' - COMPREPLY=( $( echo "$keys" | grep -i "^${cur//\\/\\\\}" ) ) - ;; - write) - if [[ $key_index -eq $COMP_CWORD ]]; then - # Complete key - local IFS=$'\n' - COMPREPLY=( $( echo "$keys" | grep -i "^${cur//\\/\\\\}" ) ) - elif [[ $((key_index+1)) -eq $COMP_CWORD ]]; then - # Complete value type - # Unfortunately ${COMP_WORDS[key_index]} fails on keys with spaces - local value_types='-string -data -integer -float -boolean -date -array -array-add -dict -dict-add' - local cur_type=$( defaults read-type $domain ${COMP_WORDS[key_index]} 2>/dev/null | sed -e 's/^Type is \(.*\)/-\1/' -e's/dictionary/dict/' | grep "^$cur" ) - if [[ $cur_type ]]; then - COMPREPLY=( $cur_type ) - else - COMPREPLY=( $( compgen -W "$value_types" -- $cur ) ) - fi - elif [[ $((key_index+2)) -eq $COMP_CWORD ]]; then - # Complete value - # Unfortunately ${COMP_WORDS[key_index]} fails on keys with spaces - COMPREPLY=( $( defaults read $domain ${COMP_WORDS[key_index]} 2>/dev/null | grep -i "^${cur//\\/\\\\}" ) ) - fi - ;; - rename) - if [[ $key_index -eq $COMP_CWORD ]] || - [[ $((key_index+1)) -eq $COMP_CWORD ]]; then - # Complete source and destination keys - local IFS=$'\n' - COMPREPLY=( $( echo "$keys" | grep -i "^${cur//\\/\\\\}" ) ) - fi - ;; - delete) - if [[ $key_index -eq $COMP_CWORD ]]; then - # Complete key - local IFS=$'\n' - COMPREPLY=( $( echo "$keys" | grep -i "^${cur//\\/\\\\}" ) ) - fi - ;; - esac - - return 0 -} - -complete -F _defaults -o default defaults - - -# This file is licensed under the BSD license, as follows: -# -# Copyright (c) 2006, Playhaus -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# * Neither the name of the Playhaus nor the names of its contributors may be -# used to endorse or promote products derived from this software without -# specific prior written permission. -# -# This software is provided by the copyright holders and contributors "as is" -# and any express or implied warranties, including, but not limited to, the -# implied warranties of merchantability and fitness for a particular purpose are -# disclaimed. In no event shall the copyright owner or contributors be liable -# for any direct, indirect, incidental, special, exemplary, or consequential -# damages (including, but not limited to, procurement of substitute goods or -# services; loss of use, data, or profits; or business interruption) however -# caused and on any theory of liability, whether in contract, strict liability, -# or tort (including negligence or otherwise) arising in any way out of the use -# of this software, even if advised of the possibility of such damage. +if test -s "${BASH_IT?}/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash"; then + source "$_" +fi diff --git a/completion/available/git.completion.bash b/completion/available/git.completion.bash index d6fd3265..31b77fa3 100644 --- a/completion/available/git.completion.bash +++ b/completion/available/git.completion.bash @@ -39,5 +39,4 @@ done if [[ "${_git_bash_completion_found}" == false ]]; then _log_warning "no completion files found - please try enabling the 'system' completion instead." fi -# shellcheck disable=SC2154 # ignore unknown unset "${!_git_bash_completion@}" diff --git a/completion/available/pipenv.completion.bash b/completion/available/pipenv.completion.bash index 52451b8a..4adfab95 100644 --- a/completion/available/pipenv.completion.bash +++ b/completion/available/pipenv.completion.bash @@ -1,4 +1,4 @@ # shellcheck shell=bash if _command_exists pipenv; then - eval "$(pipenv --completion)" + eval "$(_PIPENV_COMPLETE=bash_source pipenv)" fi diff --git a/docs/commands/index.rst b/docs/commands/index.rst index 3eee3b3a..3890a139 100644 --- a/docs/commands/index.rst +++ b/docs/commands/index.rst @@ -13,3 +13,4 @@ You should be familiar with them in order to fully utilize Bash-it. search reload doctor + profile diff --git a/docs/commands/profile.rst b/docs/commands/profile.rst new file mode 100644 index 00000000..67ca9b5b --- /dev/null +++ b/docs/commands/profile.rst @@ -0,0 +1,31 @@ +.. _profile: + +Bash-it Profile +--------------- + +Have you ever wanted to port your *Bash-it* configuration into another machine? + +If you did, then ``bash-it profile`` is for you! + +This command can save and load custom *"profile"* files, that can be later +used to load and recreate your configuration, in any machine you would like |:smile:| + +When porting your configuration into a new machine, you just need to save your current profile, copy the resulting *"profile"* file, and load it in the other machine. + +Example +^^^^^^^ + +.. code-block:: bash + + # Saves your current profile + bash-it profile save my_profile + # Load the default profile, which is the one used in the default installation. + bash-it profile load default + + # Do whatever you want: + # Disable stuff + bash-it disable ... + # Enable stuff + bash-it enable ... + # If you want to get back into your original configuration, you can do it easily + bash-it profile load my_profile diff --git a/install.sh b/install.sh index 5d2f883e..2bb78a3f 100755 --- a/install.sh +++ b/install.sh @@ -208,6 +208,8 @@ export BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE='' source "${BASH_IT}"/vendor/github.com/erichs/composure/composure.sh # shellcheck source=./lib/utilities.bash source "$BASH_IT/lib/utilities.bash" +# shellcheck source=./lib/log.bash +source "${BASH_IT}/lib/log.bash" cite _about _param _example _group _author _version # shellcheck source=./lib/helpers.bash source "$BASH_IT/lib/helpers.bash" @@ -219,12 +221,7 @@ if [[ -n $interactive && -z "${silent}" ]]; then done else echo "" - echo -e "\033[0;32mEnabling reasonable defaults\033[0m" - _enable-completion bash-it - _enable-completion system - _enable-plugin base - _enable-plugin alias-completion - _enable-alias general + _bash-it-profile-load "default" fi echo "" diff --git a/lib/helpers.bash b/lib/helpers.bash index f11df4be..01211079 100755 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -108,6 +108,7 @@ bash-it () example '$ bash-it version' example '$ bash-it reload' example '$ bash-it restart' + example '$ bash-it profile list|save|load|rm [profile_name]' example '$ bash-it doctor errors|warnings|all' typeset verb=${1:-} shift @@ -126,6 +127,8 @@ bash-it () func=_help-$component;; doctor) func=_bash-it-doctor-$component;; + profile) + func=_bash-it-profile-$component;; search) _bash-it-search $component "$@" return;; @@ -457,6 +460,172 @@ _bash-it-doctor-() { _bash-it-doctor-all } +_bash-it-profile-save() { + _about 'saves the current configuration to the "profile" directory' + _group 'lib' + + local name=$1 + while [ -z "$1" ]; do + read -r -e -p "Please enter the name of the profile to save: " name + case $name in + "") + echo -e "\033[91mPlease choose a name.\033[m" + ;; + *) + break + ;; + esac + done + + local profile_path="${BASH_IT}/profiles/${name}.bash_it" + if [ -f "$profile_path" ]; then + echo -e "\033[0;33mProfile \"$name\" already exists.\033[m" + while true; do + read -r -e -n 1 -p "Would you like to overwrite existing profile? [y/N] " RESP + case $RESP in + [yY]) + echo -e "\033[0;32mOverwriting profile \"$name\"...\033[m" + rm "$profile_path" + break + ;; + [nN] | "") + echo -e "\033[91mAborting profile save...\033[m" + return 1 + ;; + *) + echo -e "\033[91mPlease choose y or n.\033[m" + ;; + esac + done + fi + + local something_exists + echo "# This file is auto generated by Bash-it. Do not edit manually!" > "$profile_path" + for subdirectory in "plugins" "completion" "aliases"; do + local component_exists="" + echo "Saving $subdirectory configuration..." + for f in "${BASH_IT}/$subdirectory/available/"*.bash; do + _bash-it-determine-component-status-from-path "$f" + if [ "$enabled" == "x" ]; then + if [ -z "$component_exists" ]; then + # This is the first component of this type, print the header + component_exists="yes" + something_exists="yes" + echo "" >> "$profile_path" + echo "# $subdirectory" >> "$profile_path" + fi + echo "$subdirectory $enabled_file_clean" >> "$profile_path" + fi + done + done + if [ -z "$something_exists" ]; then + echo "It seems like no configuration was enabled.." + echo "Make sure to double check that this is the wanted behavior." + fi + + echo "All done!" + echo "" + echo "Profile location: $profile_path" + echo "Load the profile by invoking \"bash-it profile load $name\"" +} + +_bash-it-profile-load-parse-profile() { + _about 'Internal function used to parse the profile file' + _param '1: path to the profile file' + _param '2: dry run- only check integrity of the profile file' + _example '$ _bash-it-profile-load-parse-profile "profile.bash_it" "dry"' + + local num=0 + while read -r -a line; do + num=$((num + 1)) + # Ignore comments and empty lines + [[ -z "${line[*]}" || "${line[*]}" =~ ^#.* ]] && continue + local enable_func="_enable-${line[0]}" + local subdirectory=${line[0]} + local component=${line[1]} + + typeset to_enable=$(command ls "${BASH_IT}/$subdirectory/available/$component".*bash 2>/dev/null | head -1) + # Ignore botched lines + if [[ -z "$to_enable" ]]; then + echo -e "\033[91mBad line(#$num) in profile, aborting load...\033[m" + local bad="bad line" + break + fi + # Do not actually modify config on dry run + [[ -z $2 ]] || continue + # Actually enable the component + $enable_func "$component" + done < "$1" + + # Make sure to propagate the error + [[ -z $bad ]] +} + +_bash-it-profile-list() { + about 'lists all profiles from the "profiles" directory' + _group 'lib' + + echo "Available profiles:" + for profile in "${BASH_IT}/profiles"/*.bash_it; do + profile="${profile##*/}" + echo "${profile/.bash_it/}" + done +} + +_bash-it-profile-rm() { + about 'Removes a profile from the "profiles" directory' + _group 'lib' + local name="$1" + if [[ -z $name ]]; then + echo -e "\033[91mPlease specify profile name to remove...\033[m" + return 1 + fi + + # Users should not be allowed to delete the default profile + if [[ $name == "default" ]]; then + echo -e "\033[91mCan not remove the default profile...\033[m" + return 1 + fi + + local profile_path="${BASH_IT}/profiles/$name.bash_it" + if [[ ! -f "$profile_path" ]]; then + echo -e "\033[91mCould not find profile \"$name\"...\033[m" + return 1 + fi + + command rm "$profile_path" + echo "Removed profile \"$name\" successfully!" +} + +_bash-it-profile-load() { + _about 'loads a configuration from the "profiles" directory' + _group 'lib' + + local name="$1" + if [[ -z $name ]]; then + echo -e "\033[91mPlease specify profile name to load, not changing configuration...\033[m" + return 1 + fi + + local profile_path="${BASH_IT}/profiles/$name.bash_it" + if [[ ! -f "$profile_path" ]]; then + echo -e "\033[91mCould not find profile \"$name\", not changing configuration...\033[m" + return 1 + fi + + echo "Trying to parse profile \"$name\"..." + if _bash-it-profile-load-parse-profile "$profile_path" "dry"; then + echo "Profile \"$name\" parsed successfully!" + echo "Disabling current configuration..." + _disable-all + echo "" + echo "Enabling configuration based on profile..." + _bash-it-profile-load-parse-profile "$profile_path" + echo "" + echo "Profile \"$name\" enabled!" + fi +} + _bash-it-restart() { _about 'restarts the shell in order to fully reload it' _group 'lib' @@ -492,6 +661,25 @@ _bash-it-reload() { popd &> /dev/null || return } +_bash-it-determine-component-status-from-path () +{ + _about 'internal function used to process component name and check if its enabled' + _param '1: full path to available component file' + _example '$ _bash-it-determine-component-status-from-path "${BASH_IT}/plugins/available/git.plugin.bash' + + # Check for both the old format without the load priority, and the extended format with the priority + declare enabled_files enabled_file + enabled_file="${f##*/}" + enabled_file_clean=$(echo "$enabled_file" | sed -e 's/\(.*\)\..*\.bash/\1/g') + enabled_files=$(sort <(compgen -G "${BASH_IT}/enabled/*$BASH_IT_LOAD_PRIORITY_SEPARATOR${enabled_file}") <(compgen -G "${BASH_IT}/$subdirectory/enabled/${enabled_file}") <(compgen -G "${BASH_IT}/$subdirectory/enabled/*$BASH_IT_LOAD_PRIORITY_SEPARATOR${enabled_file}") | wc -l) + + if [ "$enabled_files" -gt 0 ]; then + enabled='x' + else + enabled=' ' + fi +} + _bash-it-describe () { _about 'summarizes available bash_it components' @@ -511,17 +699,8 @@ _bash-it-describe () printf "%-20s%-10s%s\n" "$column_header" 'Enabled?' 'Description' for f in "${BASH_IT}/$subdirectory/available/"*.bash do - # Check for both the old format without the load priority, and the extended format with the priority - declare enabled_files enabled_file - enabled_file="${f##*/}" - enabled_files=$(sort <(compgen -G "${BASH_IT}/enabled/*$BASH_IT_LOAD_PRIORITY_SEPARATOR${enabled_file}") <(compgen -G "${BASH_IT}/$subdirectory/enabled/${enabled_file}") <(compgen -G "${BASH_IT}/$subdirectory/enabled/*$BASH_IT_LOAD_PRIORITY_SEPARATOR${enabled_file}") | wc -l) - - if [ $enabled_files -gt 0 ]; then - enabled='x' - else - enabled=' ' - fi - printf "%-20s%-10s%s\n" "$(basename $f | sed -e 's/\(.*\)\..*\.bash/\1/g')" " [$enabled]" "$(cat $f | metafor about-$file_type)" + _bash-it-determine-component-status-from-path "$f" + printf "%-20s%-10s%s\n" "$enabled_file_clean" " [$enabled]" "$(cat $f | metafor about-$file_type)" done printf '\n%s\n' "to enable $preposition $file_type, do:" printf '%s\n' "$ bash-it enable $file_type <$file_type name> [$file_type name]... -or- $ bash-it enable $file_type all" @@ -540,6 +719,17 @@ _on-disable-callback() _command_exists $callback && $callback } +_disable-all () +{ + _about 'disables all bash_it components' + _example '$ _disable-all' + _group 'lib' + + _disable-plugin "all" + _disable-alias "all" + _disable-completion "all" +} + _disable-plugin () { _about 'disables bash_it plugin' @@ -623,7 +813,11 @@ _disable-thing () _bash-it-clean-component-cache "${file_type}" - printf '%s\n' "$file_entity disabled." + if [ "$file_entity" = "all" ]; then + printf '%s\n' "$file_entity $(_bash-it-pluralize-component "$file_type") disabled." + else + printf '%s\n' "$file_entity disabled." + fi } _enable-plugin () @@ -636,6 +830,12 @@ _enable-plugin () _enable-thing "plugins" "plugin" $1 $BASH_IT_LOAD_PRIORITY_DEFAULT_PLUGIN } +_enable-plugins () +{ + _about 'alias of _enable-plugin' + _enable-plugin "$@" +} + _enable-alias () { _about 'enables bash_it alias' @@ -646,6 +846,12 @@ _enable-alias () _enable-thing "aliases" "alias" $1 $BASH_IT_LOAD_PRIORITY_DEFAULT_ALIAS } +_enable-aliases () +{ + _about 'alias of _enable-alias' + _enable-alias "$@" +} + _enable-completion () { _about 'enables bash_it completion' @@ -802,6 +1008,17 @@ _help-plugins() rm $grouplist 2> /dev/null } +_help-profile () { + _about 'help message for profile command' + _group 'lib' + + echo "Manages profiles of bash it." + echo "Use 'bash-it profile list' to see all available profiles." + echo "Use 'bash-it profile save foo' to save the current configuration into a profile named 'foo'." + echo "Use 'bash-it profile load foo' to load an existing profile named 'foo'." + echo "Use 'bash-it profile rm foo' to remove an existing profile named 'foo'." +} + _help-update () { _about 'help message for update command' _group 'lib' diff --git a/plugins/available/autojump.plugin.bash b/plugins/available/autojump.plugin.bash index 89694100..3dfa0bca 100644 --- a/plugins/available/autojump.plugin.bash +++ b/plugins/available/autojump.plugin.bash @@ -4,13 +4,11 @@ about-plugin 'Autojump configuration, see https://github.com/wting/autojump for # Only supports the Homebrew variant, Debian and Arch at the moment. # Feel free to provide a PR to support other install locations -# shellcheck disable=1090 +# shellcheck disable=SC1090 if _bash_it_homebrew_check && [[ -s "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/autojump.sh" ]]; then source "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/autojump.sh" elif _command_exists dpkg && dpkg -s autojump &> /dev/null; then - # shellcheck disable=SC1090 source "$(dpkg-query -S autojump.sh | cut -d' ' -f2)" elif _command_exists pacman && pacman -Q autojump &> /dev/null; then - # shellcheck disable=SC1090 source "$(pacman -Ql autojump | grep autojump.sh | cut -d' ' -f2)" fi diff --git a/plugins/available/dirs.plugin.bash b/plugins/available/dirs.plugin.bash index 2c1adf7a..a455ff95 100644 --- a/plugins/available/dirs.plugin.bash +++ b/plugins/available/dirs.plugin.bash @@ -103,5 +103,3 @@ R () { } alias U='source ~/.dirs' # Update bookmark stack -# Set the Bash option so that no '$' is required when using the above facility -shopt -s cdable_vars diff --git a/plugins/available/fzf.plugin.bash b/plugins/available/fzf.plugin.bash index c4f5ea84..21182ac2 100644 --- a/plugins/available/fzf.plugin.bash +++ b/plugins/available/fzf.plugin.bash @@ -4,14 +4,15 @@ cite about-plugin about-plugin 'load fzf, if you are using it' -_command_exists fzf || return - if [ -r ~/.fzf.bash ] ; then source ~/.fzf.bash elif [ -r "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash ] ; then source "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash fi +# No need to continue if the command is not present +_command_exists fzf || return + if [ -z ${FZF_DEFAULT_COMMAND+x} ] && _command_exists fd ; then export FZF_DEFAULT_COMMAND='fd --type f' fi diff --git a/plugins/available/java.plugin.bash b/plugins/available/java.plugin.bash index 98e46247..2a80a99a 100644 --- a/plugins/available/java.plugin.bash +++ b/plugins/available/java.plugin.bash @@ -1,11 +1,11 @@ -cite about-plugin +# shellcheck shell=bash about-plugin 'Java and JAR helper functions' function jar_manifest { - about "extracts the specified JAR file's MANIFEST file and prints it to stdout" - group 'java' - param '1: JAR file to extract the MANIFEST from' - example 'jar_manifest lib/foo.jar' + about "extracts the specified JAR file's MANIFEST file and prints it to stdout" + group 'java' + param '1: JAR file to extract the MANIFEST from' + example 'jar_manifest lib/foo.jar' - unzip -c $1 META-INF/MANIFEST.MF + unzip -c "${1:?${FUNCNAME[0]}: JAR file must be specified}" META-INF/MANIFEST.MF } diff --git a/plugins/available/jekyll.plugin.bash b/plugins/available/jekyll.plugin.bash index c340c432..d818b076 100644 --- a/plugins/available/jekyll.plugin.bash +++ b/plugins/available/jekyll.plugin.bash @@ -1,367 +1,288 @@ +# shellcheck shell=bash cite about-plugin about-plugin 'manage your jekyll site' -editpost() { - about 'edit a post' - param '1: site directory' - group 'jekyll' +function editpost() { + about 'edit a post' + param '1: site directory' + group 'jekyll' - unset SITE - if [ -z "$1" ] - then - echo "Error: no site specified." - echo "The site is the name of the directory your project is in." - return 1 - fi + local SITE site POST DATE TITLE POSTS + local -i COUNTER=1 POST_TO_EDIT ret + if [[ -z "${1:-}" ]]; then + echo "Error: no site specified." + echo "The site is the name of the directory your project is in." + return 1 + fi - for site in ${SITES[@]} - do - if [ "${site##*/}" = "$1" ] - then - SITE=$site - break - fi - done + for site in "${SITES[@]:-}"; do + if [[ "${site##*/}" == "$1" ]]; then + SITE="${site}" + break + fi + done - if [ -z "$SITE" ] - then - echo "No such site." - return 1 - fi + if [[ -z "${SITE:-}" ]]; then + echo "No such site." + return 1 + fi - builtin cd "$SITE/_posts" + pushd "${SITE}/_posts" > /dev/null || return - COUNTER=1 - NUMBER="$RANDOM" - TMPFILE="/tmp/editpost-$NUMBER" - - for POST in * - do - DATE=`echo $POST | grep -oE "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}"` - TITLE=`cat $POST | grep -oE "title: (.+)"` - TITLE=`echo $TITLE | sed 's/title: //'` - echo "$COUNTER) $DATE $TITLE" >> "$TMPFILE" - POSTS[$COUNTER]=$POST - COUNTER=`expr $COUNTER + 1` - done - less $TMPFILE - read -p "Number of post to edit: " POST_TO_EDIT - if [ -z "$JEKYLL_EDITOR" ] - then - nano "${POSTS[$POST_TO_EDIT]}" - else - "$JEKYLL_EDITOR" "${POSTS[$POST_TO_EDIT]}" - fi + for POST in *; do + DATE="$(echo "${POST}" | grep -oE "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}")" + TITLE="$(grep -oE "title: (.+)" < "${POST}")" + TITLE="${TITLE/title: /}" + echo "${COUNTER}) ${DATE} ${TITLE}" + POSTS[COUNTER]="$POST" + COUNTER="$((COUNTER + 1))" + done > >(less) + read -rp "Number of post to edit: " POST_TO_EDIT + "${JEKYLL_EDITOR:-${VISUAL:-${EDITOR:-${ALTERNATE_EDITOR:-nano}}}}" "${POSTS[POST_TO_EDIT]}" + ret="$?" + popd > /dev/null || return "$ret" + return "$ret" } -newpost() { - about 'create a new post' - param '1: site directory' - group 'jekyll' +function newpost() { + about 'create a new post' + param '1: site directory' + group 'jekyll' - unset SITE - if [ -z "$1" ] - then - echo "Error: no site specified." - echo "The site is the name of the directory your project is in." - return 1 - fi + local SITE site FNAME_POST_TITLE FNAME YAML_DATE + local JEKYLL_FORMATTING FNAME_DATE OPTIONS OPTION POST_TYPE POST_TITLE + local -i loc=0 ret + if [[ -z "${1:-}" ]]; then + echo "Error: no site specified." + echo "The site is the name of the directory your project is in." + return 1 + fi - if [ -z "$SITE" ] - then - echo "No such site." - return 1 - fi + if [[ -z "${SITE}" ]]; then + echo "No such site." + return 1 + fi - loc=0 + for site in "${SITES[@]}"; do + if [[ "${site##*/}" == "$1" ]]; then + SITE="$site" + JEKYLL_FORMATTING="${MARKUPS[loc]}" + break + fi + loc=$((loc + 1)) + done - for site in ${SITES[@]} - do - if [ "${site##*/}" = "$1" ] - then - SITE=$site - JEKYLL_FORMATTING=${MARKUPS[$loc]} - break - fi - loc=$(($loc+1)) - done + # Change directory into the local jekyll root + pushd "${SITE}/_posts" > /dev/null || return - # 'builtin cd' into the local jekyll root + # Get the date for the new post's filename + FNAME_DATE="$(date "+%Y-%m-%d")" - builtin cd "$SITE/_posts" + # If the user is using markdown or textile formatting, let them choose what type of post they want. Sort of like Tumblr. + OPTIONS=('Text' 'Quote' 'Image' 'Audio' 'Video' 'Link') - # Get the date for the new post's filename + if [[ $JEKYLL_FORMATTING == "markdown" || $JEKYLL_FORMATTING == "textile" ]]; then + select OPTION in "${OPTIONS[@]}"; do + POST_TYPE="${OPTION}" + break + done + fi - FNAME_DATE=$(date "+%Y-%m-%d") + # Get the title for the new post + read -rp "Enter title of the new post: " POST_TITLE - # If the user is using markdown or textile formatting, let them choose what type of post they want. Sort of like Tumblr. + # Convert the spaces in the title to hyphens for use in the filename + FNAME_POST_TITLE="${POST_TITLE/ /-}" - OPTIONS="Text Quote Image Audio Video Link" + # Now, put it all together for the full filename + FNAME="$FNAME_DATE-$FNAME_POST_TITLE.$JEKYLL_FORMATTING" - if [ $JEKYLL_FORMATTING = "markdown" -o $JEKYLL_FORMATTING = "textile" ] - then - select OPTION in $OPTIONS - do - if [[ $OPTION = "Text" ]] - then - POST_TYPE="Text" - break - fi + # And, finally, create the actual post file. But we're not done yet... + { + # Write a little stuff to the file for the YAML Front Matter + echo "---" - if [[ $OPTION = "Quote" ]] - then - POST_TYPE="Quote" - break - fi + # Now we have to get the date, again. But this time for in the header (YAML Front Matter) of the file + YAML_DATE="$(date "+%B %d %Y %X")" - if [[ $OPTION = "Image" ]] - then - POST_TYPE="Image" - break - fi + # Echo the YAML Formatted date to the post file + echo "date: $YAML_DATE" - if [[ $OPTION = "Audio" ]] - then - POST_TYPE="Audio" - break - fi + # Echo the original post title to the YAML Front Matter header + echo "title: $POST_TITLE" - if [[ $OPTION = "Video" ]] - then - POST_TYPE="Video" - break - fi + # And, now, echo the "post" layout to the YAML Front Matter header + echo "layout: post" - if [[ $OPTION = "Link" ]] - then - POST_TYPE="Link" - break - fi - done - fi + # Close the YAML Front Matter Header + echo "---" - # Get the title for the new post + echo + } > "${FNAME}" - read -p "Enter title of the new post: " POST_TITLE + # Generate template text based on the post type + if [[ $JEKYLL_FORMATTING == "markdown" ]]; then + case $POST_TYPE in + "Text") + true + ;; + "Quote") + echo "> Quote" + echo + echo "— Author" + ;; + "Image") + echo "![Alternate Text](/path/to/image/or/url)" + ;; + "Audio") + echo "" + ;; + "Video") + echo "" + ;; + "Link") + echo "[link][1]" + echo + echo "> Quote" + echo + echo "[1]: url" + ;; + esac + elif [[ $JEKYLL_FORMATTING == "textile" ]]; then + case $POST_TYPE in + "Text") + true + ;; + "Quote") + echo "bq. Quote" + echo + echo "— Author" + ;; + "Image") + echo "!url(alt text)" + ;; + "Audio") + echo "" + ;; + "Video") + echo "" + ;; + "Link") + echo "\"Site\":url" + echo + echo "bq. Quote" + ;; + esac + fi >> "${FNAME}" - # Convert the spaces in the title to hyphens for use in the filename - - FNAME_POST_TITLE=`echo $POST_TITLE | tr ' ' "-"` - - # Now, put it all together for the full filename - - FNAME="$FNAME_DATE-$FNAME_POST_TITLE.$JEKYLL_FORMATTING" - - # And, finally, create the actual post file. But we're not done yet... - - touch "$FNAME" - - # Write a little stuff to the file for the YAML Front Matter - - echo "---" >> $FNAME - - # Now we have to get the date, again. But this time for in the header (YAML Front Matter) of - # the file - - YAML_DATE=$(date "+%B %d %Y %X") - - # Echo the YAML Formatted date to the post file - - echo "date: $YAML_DATE" >> $FNAME - - # Echo the original post title to the YAML Front Matter header - - echo "title: $POST_TITLE" >> $FNAME - - # And, now, echo the "post" layout to the YAML Front Matter header - - echo "layout: post" >> $FNAME - - # Close the YAML Front Matter Header - - echo "---" >> $FNAME - echo >> $FNAME - - # Generate template text based on the post type - - if [[ $JEKYLL_FORMATTING = "markdown" ]] - then - if [[ $POST_TYPE = "Text" ]] - then - true - fi - - if [[ $POST_TYPE = "Quote" ]] - then - echo "> Quote" >> $FNAME - echo >> $FNAME - echo "— Author" >> $FNAME - fi - - if [[ $POST_TYPE = "Image" ]] - then - echo "![Alternate Text](/path/to/image/or/url)" >> $FNAME - fi - - if [[ $POST_TYPE = "Audio" ]] - then - echo "" >> $FNAME - fi - - if [[ $POST_TYPE = "Video" ]] - then - echo "" >> $FNAME - fi - - if [[ $POST_TYPE = "Link" ]] - then - echo "[link][1]" >> $FNAME - echo >> $FNAME - echo "> Quote" >> $FNAME - echo >> $FNAME - echo "[1]: url" >> $FNAME - fi - fi - - if [[ $JEKYLL_FORMATTING = "textile" ]] - then - if [[ $POST_TYPE = "Text" ]] - then - true - fi - - if [[ $POST_TYPE = "Quote" ]] - then - echo "bq. Quote" >> $FNAME - echo >> $FNAME - echo "— Author" >> $FNAME - fi - - if [[ $POST_TYPE = "Image" ]] - then - echo "!url(alt text)" >> $FNAME - fi - - if [[ $POST_TYPE = "Audio" ]] - then - echo "" >> $FNAME - fi - - if [[ $POST_TYPE = "Video" ]] - then - echo "" >> $FNAME - fi - - if [[ $POST_TYPE = "Link" ]] - then - echo "\"Site\":url" >> $FNAME - echo >> $FNAME - echo "bq. Quote" >> $FNAME - fi - fi - - # Open the file in your favorite editor - - "$JEKYLL_EDITOR" $FNAME + # Open the file in your favorite editor + "${JEKYLL_EDITOR:-${VISUAL:-${EDITOR:-${ALTERNATE_EDITOR:-nano}}}}" "${FNAME}" + ret="$?" + popd > /dev/null || return "$ret" + return "$ret" } function testsite() { - about 'launches local jekyll server' - param '1: site directory' - group 'jekyll' + about 'launches local jekyll server' + param '1: site directory' + group 'jekyll' - unset SITE - if [ -z "$1" ] - then - echo "Error: no site specified." - echo "The site is the name of the directory your project is in." - return 1 - fi + local SITE site + local -i ret + if [[ -z "${1:-}" ]]; then + echo "Error: no site specified." + echo "The site is the name of the directory your project is in." + return 1 + fi - for site in ${SITES[@]} - do - if [ "${site##*/}" = "$1" ] - then - SITE=$site - break - fi - done + for site in "${SITES[@]}"; do + if [[ "${site##*/}" == "$1" ]]; then + SITE="$site" + break + fi + done - if [ -z "$SITE" ] - then - echo "No such site." - return 1 - fi + if [[ -z "${SITE}" ]]; then + echo "No such site." + return 1 + fi - builtin cd $SITE - jekyll --server --auto + pushd "${SITE}" > /dev/null || return + jekyll --server --auto + ret="$?" + popd > /dev/null || return "$ret" + return "$ret" } function buildsite() { - about 'builds site' - param '1: site directory' - group 'jekyll' + about 'builds site' + param '1: site directory' + group 'jekyll' - unset SITE - if [ -z "$1" ] - then - echo "Error: no site specified." - echo "The site is the name of the directory your project is in." - return 1 - fi + local SITE site + local -i ret + if [[ -z "${1:-}" ]]; then + echo "Error: no site specified." + echo "The site is the name of the directory your project is in." + return 1 + fi - for site in ${SITES[@]} - do - if [ "${site##*/}" = "$1" ] - then - SITE=$site - break - fi - done + for site in "${SITES[@]}"; do + if [[ "${site##*/}" == "$1" ]]; then + SITE="$site" + break + fi + done - if [ -z "$SITE" ] - then - echo "No such site." - return 1 - fi + if [[ -z "${SITE}" ]]; then + echo "No such site." + return 1 + fi - builtin cd $SITE - rm -rf _site - jekyll --no-server + pushd "${SITE}" > /dev/null || return + rm -rf _site + jekyll --no-server + ret="$?" + popd > /dev/null || return "$ret" + return "$ret" } function deploysite() { - about 'rsyncs site to remote host' - param '1: site directory' - group 'jekyll' + about 'rsyncs site to remote host' + param '1: site directory' + group 'jekyll' - unset SITE - if [ -z "$1" ] - then - echo "Error: no site specified." - echo "The site is the name of the directory your project is in." - return 1 - fi + local SITE site REMOTE + local -i loc=0 ret + if [[ -z "${1:-}" ]]; then + echo "Error: no site specified." + echo "The site is the name of the directory your project is in." + return 1 + fi - loc=0 + for site in "${SITES[@]}"; do + if [[ "${site##*/}" == "$1" ]]; then + SITE="$site" + # shellcheck disable=SC2153 # who knows + REMOTE="${REMOTES[loc]}" + break + fi + loc=$((loc + 1)) + done - for site in ${SITES[@]} - do - if [ "${site##*/}" = "$1" ] - then - SITE=$site - REMOTE=${REMOTES[$loc]} - break - fi - loc=$(($loc+1)) - done + if [[ -z "${SITE}" ]]; then + echo "No such site." + return 1 + fi - if [ -z "$SITE" ] - then - echo "No such site." - return 1 - fi - - builtin cd $SITE - rsync -rz $REMOTE + pushd "${SITE}" > /dev/null || return + rsync -rz "${REMOTE?}" + ret="$?" + popd > /dev/null || return "$ret" + return "$ret" } + +# Load the Jekyll config +if [[ -s "$HOME/.jekyllconfig" ]]; then + source "$HOME/.jekyllconfig" +fi diff --git a/profiles/default.bash_it b/profiles/default.bash_it new file mode 100644 index 00000000..5e4f4631 --- /dev/null +++ b/profiles/default.bash_it @@ -0,0 +1,12 @@ +# This is the default profile of Bash-it + +# plugins +plugins alias-completion +plugins base + +# completion +completion bash-it +completion system + +# aliases +aliases general diff --git a/test/completion/bash-it.completion.bats b/test/completion/bash-it.completion.bats index eaa4423d..fbf0a3fa 100644 --- a/test/completion/bash-it.completion.bats +++ b/test/completion/bash-it.completion.bats @@ -80,32 +80,42 @@ function __check_completion () { @test "completion bash-it: show options" { run __check_completion 'bash-it ' - assert_line -n 0 "disable enable help migrate reload restart doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart 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 doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart 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 doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart 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 doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart 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 doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart 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 doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" +} + +@test "completion bash-it: profile - show options" { + run __check_completion 'bash-it profile ' + assert_line -n 0 "load save list rm" +} + +@test "completion bash-it: profile load - show options" { + run __check_completion 'bash-it profile load ' + assert_line -n 0 "default" } @test "completion bash-it: show - show options" { diff --git a/test/fixtures/bash_it/profiles/test-bad-component.bash_it b/test/fixtures/bash_it/profiles/test-bad-component.bash_it new file mode 100644 index 00000000..8640265c --- /dev/null +++ b/test/fixtures/bash_it/profiles/test-bad-component.bash_it @@ -0,0 +1,12 @@ +# plugins +plugins alias-completion +plugins base + +# completion +completion bash-it +completion system + +# aliases +aliases general +# Bad component +aliases bla diff --git a/test/fixtures/bash_it/profiles/test-bad-type.bash_it b/test/fixtures/bash_it/profiles/test-bad-type.bash_it new file mode 100644 index 00000000..ed2d2373 --- /dev/null +++ b/test/fixtures/bash_it/profiles/test-bad-type.bash_it @@ -0,0 +1,12 @@ +# plugins +plugins alias-completion +plugins base +# Bad type +pluugins alias-completion + +# completion +completion bash-it +completion system + +# aliases +aliases general diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats index 7f6664e0..d876d882 100644 --- a/test/lib/helpers.bats +++ b/test/lib/helpers.bats @@ -13,11 +13,24 @@ load ../../plugins/available/base.plugin function local_setup { setup_test_fixture + + # Copy the test fixture to the Bash-it folder + if command -v rsync &> /dev/null; then + rsync -a "$BASH_IT/test/fixtures/bash_it/" "$BASH_IT/" + else + find "$BASH_IT/test/fixtures/bash_it" \ + -mindepth 1 -maxdepth 1 \ + -exec cp -r {} "$BASH_IT/" \; + fi } # TODO Create global __is_enabled function # TODO Create global __get_base_name function # TODO Create global __get_enabled_name function +@test "bash-it: verify that the test fixture is available" { + assert_file_exist "$BASH_IT/profiles/test-bad-component.bash_it" + assert_file_exist "$BASH_IT/profiles/test-bad-type.bash_it" +} @test "helpers: _command_exists function exists" { run type -a _command_exists &> /dev/null @@ -283,6 +296,149 @@ function local_setup { assert_link_exist "$BASH_IT/enabled/225---nvm.plugin.bash" } +@test "helper: profile load command sanity" { + run _bash-it-profile-load "default" + + 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/350---bash-it.completion.bash" + assert_link_exist "$BASH_IT/enabled/350---system.completion.bash" +} + +@test "helper: profile save command sanity" { + run _enable-plugin "nvm" + + run _bash-it-profile-save "test" + assert_line -n 0 "Saving plugins configuration..." + assert_line -n 1 "Saving completion configuration..." + assert_line -n 2 "Saving aliases configuration..." + assert_line -n 3 "All done!" + assert_file_exist "$BASH_IT/profiles/test.bash_it" +} + +@test "helper: profile save creates valid file with only plugin enabled" { + run _enable-plugin "nvm" + + run _bash-it-profile-save "test" + run cat "$BASH_IT/profiles/test.bash_it" + assert_line -n 0 "# This file is auto generated by Bash-it. Do not edit manually!" + assert_line -n 1 "# plugins" + assert_line -n 2 "plugins nvm" +} + +@test "helper: profile save creates valid file with only completion enabled" { + run _enable-completion "bash-it" + + run _bash-it-profile-save "test" + run cat "$BASH_IT/profiles/test.bash_it" + assert_line -n 0 "# This file is auto generated by Bash-it. Do not edit manually!" + assert_line -n 1 "# completion" + assert_line -n 2 "completion bash-it" +} + +@test "helper: profile save creates valid file with only aliases enabled" { + run _enable-alias "general" + + run _bash-it-profile-save "test" + run cat "$BASH_IT/profiles/test.bash_it" + assert_line -n 0 "# This file is auto generated by Bash-it. Do not edit manually!" + assert_line -n 1 "# aliases" + assert_line -n 2 "aliases general" +} + +@test "helper: profile edge case, empty configuration" { + run _bash-it-profile-save "test" + assert_line -n 3 "It seems like no configuration was enabled.." + assert_line -n 4 "Make sure to double check that this is the wanted behavior." + + run _enable-alias "general" + run _enable-plugin "base" + run _enable-plugin "alias-completion" + run _enable-completion "bash-it" + run _enable-completion "system" + + 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/350---bash-it.completion.bash" + assert_link_not_exist "$BASH_IT/enabled/350---system.completion.bash" +} + +@test "helper: profile save and load" { + run _enable-alias "general" + run _enable-plugin "base" + run _enable-plugin "alias-completion" + run _enable-completion "bash-it" + run _enable-completion "system" + + run _bash-it-profile-save "test" + assert_success + + run _disable-alias "general" + assert_link_not_exist "$BASH_IT/enabled/150---general.aliases.bash" + run _bash-it-profile-load "test" + assert_link_exist "$BASH_IT/enabled/150---general.aliases.bash" +} + +@test "helper: profile load corrupted profile file: bad component" { + run _bash-it-profile-load "test-bad-component" + assert_line -n 1 -p "Bad line(#12) in profile, aborting load..." +} + +@test "helper: 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..." +} + +@test "helper: profile rm sanity" { + run _bash-it-profile-save "test" + assert_file_exist "$BASH_IT/profiles/test.bash_it" + run _bash-it-profile-rm "test" + assert_line -n 0 "Removed profile \"test\" successfully!" + assert_file_not_exist "$BASH_IT/profiles/test.bash_it" +} + +@test "helper: profile rm no params" { + run _bash-it-profile-rm "" + assert_line -n 0 -p "Please specify profile name to remove..." +} + +@test "helper: profile load no params" { + run _bash-it-profile-load "" + assert_line -n 0 -p "Please specify profile name to load, not changing configuration..." +} + +@test "helper: profile rm default" { + run _bash-it-profile-rm "default" + assert_line -n 0 -p "Can not remove the default profile..." + assert_file_exist "$BASH_IT/profiles/default.bash_it" +} + +@test "helper: profile rm bad profile name" { + run _bash-it-profile-rm "notexisting" + assert_line -n 0 -p "Could not find profile \"notexisting\"..." +} + +@test "helper: profile list sanity" { + run _bash-it-profile-list + assert_line -n 0 "Available profiles:" + assert_line -n 1 "default" +} + +@test "helper: profile list more profiles" { + run _bash-it-profile-save "cactus" + run _bash-it-profile-save "another" + run _bash-it-profile-save "brother" + run _bash-it-profile-list + assert_line -n 0 "Available profiles:" + assert_line -n 4 "default" + assert_line -n 3 "cactus" + assert_line -n 1 "another" + assert_line -n 2 "brother" +} + @test "helpers: migrate plugins and completions that share the same name" { ln -s $BASH_IT/completion/available/dirs.completion.bash $BASH_IT/completion/enabled/350---dirs.completion.bash assert_link_exist "$BASH_IT/completion/enabled/350---dirs.completion.bash" diff --git a/themes/90210/90210.theme.bash b/themes/90210/90210.theme.bash index 3db3f17b..6b94427a 100644 --- a/themes/90210/90210.theme.bash +++ b/themes/90210/90210.theme.bash @@ -1,20 +1,21 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. -SCM_THEME_PROMPT_DIRTY=" ${red}✗" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" +SCM_THEME_PROMPT_DIRTY=" ${red?}✗" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓" SCM_THEME_PROMPT_PREFIX=" |" -SCM_THEME_PROMPT_SUFFIX="${green}|" +SCM_THEME_PROMPT_SUFFIX="${green?}|" -GIT_THEME_PROMPT_DIRTY=" ${red}✗" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓" -GIT_THEME_PROMPT_PREFIX=" ${green}|" -GIT_THEME_PROMPT_SUFFIX="${green}|" +GIT_THEME_PROMPT_DIRTY=" ${red?}✗" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +GIT_THEME_PROMPT_PREFIX=" ${green?}|" +GIT_THEME_PROMPT_SUFFIX="${green?}|" # Nicely formatted terminal prompt function prompt_command() { - PS1="\n${bold_black}[${blue}\@${bold_black}]-${bold_black}[${green}\u${yellow}@${green}\h${bold_black}]-${bold_black}[${purple}\w${bold_black}]-$(scm_prompt_info)\n${reset_color}\$ " + local scm_prompt_info + scm_prompt_info="$(scm_prompt_info)" + PS1="\n${bold_black?}[${blue?}\@${bold_black?}]-${bold_black?}[${green?}\u${yellow?}@${green?}\h${bold_black?}]-${bold_black?}[${purple?}\w${bold_black?}]-${scm_prompt_info?}\n${reset_color?}\$ " } safe_append_prompt_command prompt_command diff --git a/themes/bakke/bakke.theme.bash b/themes/bakke/bakke.theme.bash index d7bfbbe8..a3670b07 100644 --- a/themes/bakke/bakke.theme.bash +++ b/themes/bakke/bakke.theme.bash @@ -1,16 +1,15 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. -SCM_THEME_PROMPT_DIRTY=" ${red}✗" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" +SCM_THEME_PROMPT_DIRTY=" ${red?}✗" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓" SCM_THEME_PROMPT_PREFIX=" |" -SCM_THEME_PROMPT_SUFFIX="${green}|" +SCM_THEME_PROMPT_SUFFIX="${green?}|" -GIT_THEME_PROMPT_DIRTY=" ${red}✗" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓" -GIT_THEME_PROMPT_PREFIX=" ${green}|" -GIT_THEME_PROMPT_SUFFIX="${green}|" +GIT_THEME_PROMPT_DIRTY=" ${red?}✗" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +GIT_THEME_PROMPT_PREFIX=" ${green?}|" +GIT_THEME_PROMPT_SUFFIX="${green?}|" RVM_THEME_PROMPT_PREFIX="|" RVM_THEME_PROMPT_SUFFIX="|" @@ -19,7 +18,10 @@ function prompt_command() { #PS1="${bold_cyan}$(scm_char)${green}$(scm_prompt_info)${purple}$(ruby_version_prompt) ${yellow}\h ${reset_color}in ${green}\w ${reset_color}\n${green}→${reset_color} " #PS1="\n${purple}\h: ${reset_color} ${green}\w\n${bold_cyan}$(scm_char)${green}$(scm_prompt_info) ${green}→${reset_color} " #PS1="\n${cyan}\h: ${reset_color} ${yellow}\w\n${red}$(scm_char)${red}$(scm_prompt_info) ${green}→${reset_color} " - PS1="\n${cyan}\h:$(virtualenv_prompt) ${reset_color} ${yellow}\w ${green}$(scm_prompt_info)\n${reset_color}→ " + local virtualenv_prompt scm_prompt_info + virtualenv_prompt="$(virtualenv_prompt)" + scm_prompt_info="$(scm_prompt_info)" + PS1="\n${cyan?}\h:${virtualenv_prompt} ${reset_color?} ${yellow?}\w ${green?}${scm_prompt_info}\n${reset_color?}→ " } safe_append_prompt_command prompt_command diff --git a/themes/bira/bira.theme.bash b/themes/bira/bira.theme.bash index 7db03000..f30d8d5d 100644 --- a/themes/bira/bira.theme.bash +++ b/themes/bira/bira.theme.bash @@ -1,24 +1,26 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. -SCM_THEME_PROMPT_PREFIX=" ${yellow}‹" -SCM_THEME_PROMPT_SUFFIX="›${reset_color}" +SCM_THEME_PROMPT_PREFIX=" ${yellow?}‹" +SCM_THEME_PROMPT_SUFFIX="›${reset_color?}" -VIRTUALENV_THEME_PROMPT_PREFIX=" ${cyan}‹" -VIRTUALENV_THEME_PROMPT_SUFFIX="›${reset_color}" +VIRTUALENV_THEME_PROMPT_PREFIX=" ${cyan?}‹" +VIRTUALENV_THEME_PROMPT_SUFFIX="›${reset_color?}" bold="\[\e[1m\]" -if [ ${UID} -eq 0 ]; then - user_host="${bold_red}\u@\h${normal}${reset_color}" +if [[ ${UID} -eq 0 ]]; then + user_host="${bold_red?}\u@\h${normal?}${reset_color?}" else - user_host="${bold_green}\u@\h${normal}${reset_color}" + user_host="${bold_green?}\u@\h${normal?}${reset_color?}" fi function prompt_command() { - local current_dir=" ${bold_blue}\w${normal}${reset_color}" - PS1="╭─${user_host}${current_dir}$(virtualenv_prompt)$(scm_prompt_info)\n╰─${bold}\\$ ${normal}" + local current_dir=" ${bold_blue?}\w${normal?}${reset_color?}" + local virtualenv_prompt scm_prompt_info + virtualenv_prompt="$(virtualenv_prompt)" + scm_prompt_info="$(scm_prompt_info)" + PS1="╭─${user_host?}${current_dir}${virtualenv_prompt}${scm_prompt_info}\n╰─${bold?}\\$ ${normal?}" } safe_append_prompt_command prompt_command diff --git a/themes/codeword/codeword.theme.bash b/themes/codeword/codeword.theme.bash index beab6a4a..d52403c1 100644 --- a/themes/codeword/codeword.theme.bash +++ b/themes/codeword/codeword.theme.bash @@ -1,23 +1,23 @@ # shellcheck shell=bash -SCM_THEME_PROMPT_PREFIX=${SCM_THEME_PROMPT_SUFFIX} -SCM_THEME_PROMPT_DIRTY="${bold_red} ✗${normal}" -SCM_THEME_PROMPT_CLEAN="${bold_green} ✓${normal}" -SCM_GIT_CHAR="${green}±${normal}" +SCM_THEME_PROMPT_PREFIX="${SCM_THEME_PROMPT_SUFFIX:-}" +SCM_THEME_PROMPT_DIRTY="${bold_red?} ✗${normal?}" +SCM_THEME_PROMPT_CLEAN="${bold_green?} ✓${normal?}" +SCM_GIT_CHAR="${green?}±${normal?}" -mark_prompt() { - echo "${green}\$${normal}" +function mark_prompt() { + echo "${green?}\$${normal?}" } -user_host_path_prompt() { - ps_user="${green}\u${normal}"; - ps_host="${blue}\H${normal}"; - ps_path="${yellow}\w${normal}"; - echo "$ps_user@$ps_host:$ps_path" +function user_host_path_prompt() { + ps_user="${green?}\u${normal?}"; + ps_host="${blue?}\H${normal?}"; + ps_path="${yellow?}\w${normal?}"; + echo "${ps_user?}@${ps_host?}:${ps_path?}" } -prompt() { - SCM_PROMPT_FORMAT=' [%s%s]' +function prompt() { + local SCM_PROMPT_FORMAT=' [%s%s]' PS1="$(user_host_path_prompt)$(virtualenv_prompt)$(scm_prompt) $(mark_prompt) " } diff --git a/themes/powerline/powerline.base.bash b/themes/powerline/powerline.base.bash index 7da15cfd..7067dfb8 100644 --- a/themes/powerline/powerline.base.bash +++ b/themes/powerline/powerline.base.bash @@ -1,16 +1,15 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. # Define this here so it can be used by all of the Powerline themes THEME_CHECK_SUDO=${THEME_CHECK_SUDO:=true} function set_color() { - set +u - if [[ "${1}" != "-" ]]; then + local fg='' bg='' + if [[ "${1:-}" != "-" ]]; then fg="38;5;${1}" fi - if [[ "${2}" != "-" ]]; then + if [[ "${2:-}" != "-" ]]; then bg="48;5;${2}" [[ -n "${fg}" ]] && bg=";${bg}" fi @@ -99,14 +98,13 @@ function __powerline_k8s_namespace_prompt() { } function __powerline_python_venv_prompt() { - set +u local python_venv="" - if [[ -n "${CONDA_DEFAULT_ENV}" ]]; then + if [[ -n "${CONDA_DEFAULT_ENV:-}" ]]; then python_venv="${CONDA_DEFAULT_ENV}" PYTHON_VENV_CHAR=${CONDA_PYTHON_VENV_CHAR} - elif [[ -n "${VIRTUAL_ENV}" ]]; then - python_venv=$(basename "${VIRTUAL_ENV}") + elif [[ -n "${VIRTUAL_ENV:-}" ]]; then + python_venv="${VIRTUAL_ENV##*/}" fi [[ -n "${python_venv}" ]] && echo "${PYTHON_VENV_CHAR}${python_venv}|${PYTHON_VENV_THEME_PROMPT_COLOR}" @@ -137,7 +135,7 @@ function __powerline_scm_prompt() { elif [[ "${SCM_SVN_CHAR}" == "${SCM_CHAR}" ]]; then scm_prompt+="${SCM_CHAR}${SCM_BRANCH}${SCM_STATE}" fi - echo "$(eval "echo ${scm_prompt}")${scm}|${color}" + echo "${scm_prompt?}${scm?}|${color}" fi } @@ -243,12 +241,12 @@ function __powerline_left_segment() { # Since the previous segment wasn't the last segment, add padding, if needed # if [[ "${POWERLINE_COMPACT_BEFORE_SEPARATOR}" -eq 0 ]]; then - LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}") ${normal}" + LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}") ${normal?}" fi if [[ "${LAST_SEGMENT_COLOR}" -eq "${params[1]}" ]]; then - LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}")${POWERLINE_LEFT_SEPARATOR_SOFT}${normal}" + LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}")${POWERLINE_LEFT_SEPARATOR_SOFT}${normal?}" else - LEFT_PROMPT+="$(set_color "${LAST_SEGMENT_COLOR}" "${params[1]}")${POWERLINE_LEFT_SEPARATOR}${normal}" + LEFT_PROMPT+="$(set_color "${LAST_SEGMENT_COLOR}" "${params[1]}")${POWERLINE_LEFT_SEPARATOR}${normal?}" fi fi @@ -258,7 +256,7 @@ function __powerline_left_segment() { } function __powerline_left_last_segment_padding() { - LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}") ${normal}" + LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}") ${normal?}" } function __powerline_last_status_prompt() { @@ -285,9 +283,9 @@ function __powerline_prompt_command() { [[ -n "${info}" ]] && __powerline_left_segment "${info}" done - [[ "${last_status}" -ne 0 ]] && __powerline_left_segment "$(__powerline_last_status_prompt ${last_status})" + [[ "${last_status}" -ne 0 ]] && __powerline_left_segment "$(__powerline_last_status_prompt "${last_status}")" - if [[ -n "${LEFT_PROMPT}" ]] && [[ "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT}" -eq 0 ]]; then + if [[ -n "${LEFT_PROMPT}" ]] && [[ "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:-}" -eq 0 ]]; then __powerline_left_last_segment_padding fi @@ -296,11 +294,11 @@ function __powerline_prompt_command() { prompt_color="$(set_color "${LAST_SEGMENT_COLOR}" -)" if [[ -n "${LEFT_PROMPT}" ]] && [[ -n "${POWERLINE_LEFT_LAST_SEGMENT_PROMPT_CHAR}" ]]; then LEFT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR}")${POWERLINE_LEFT_LAST_SEGMENT_PROMPT_CHAR}" - prompt_color="${normal}" + prompt_color="${normal?}" fi - [[ -n "${LEFT_PROMPT}" ]] && LEFT_PROMPT+="${prompt_color}${separator_char}${normal}" + [[ -n "${LEFT_PROMPT}" ]] && LEFT_PROMPT+="${prompt_color}${separator_char}${normal?}" - if [[ "${POWERLINE_COMPACT_PROMPT}" -eq 0 ]]; then + if [[ "${POWERLINE_COMPACT_PROMPT:-}" -eq 0 ]]; then LEFT_PROMPT+=" " fi diff --git a/themes/pure/pure.theme.bash b/themes/pure/pure.theme.bash index 99476f4a..ba83a232 100644 --- a/themes/pure/pure.theme.bash +++ b/themes/pure/pure.theme.bash @@ -1,16 +1,15 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. # scm theming SCM_THEME_PROMPT_PREFIX="|" SCM_THEME_PROMPT_SUFFIX="" -SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${normal}" -SCM_THEME_PROMPT_CLEAN=" ${green}✓${normal}" -SCM_GIT_CHAR="${green}±${normal}" -SCM_SVN_CHAR="${bold_cyan}⑆${normal}" -SCM_HG_CHAR="${bold_red}☿${normal}" +SCM_THEME_PROMPT_DIRTY=" ${bold_red?}✗${normal?}" +SCM_THEME_PROMPT_CLEAN=" ${green?}✓${normal?}" +SCM_GIT_CHAR="${green?}±${normal?}" +SCM_SVN_CHAR="${bold_cyan?}⑆${normal?}" +SCM_HG_CHAR="${bold_red?}☿${normal?}" VIRTUALENV_THEME_PROMPT_PREFIX="(" VIRTUALENV_THEME_PROMPT_SUFFIX=")" @@ -20,20 +19,23 @@ VIRTUALENV_THEME_PROMPT_SUFFIX=")" # export LSCOLORS="Gxfxcxdxbxegedabagacad" # export LS_COLORS='no=00:fi=00:di=01;34:ln=00;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=41;33;01:ex=00;32:*.cmd=00;32:*.exe=01;32:*.com=01;32:*.bat=01;32:*.btm=01;32:*.dll=01;32:*.tar=00;31:*.tbz=00;31:*.tgz=00;31:*.rpm=00;31:*.deb=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.lzma=00;31:*.zip=00;31:*.zoo=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.tb2=00;31:*.tz2=00;31:*.tbz2=00;31:*.avi=01;35:*.bmp=01;35:*.fli=01;35:*.gif=01;35:*.jpg=01;35:*.jpeg=01;35:*.mng=01;35:*.mov=01;35:*.mpg=01;35:*.pcx=01;35:*.pbm=01;35:*.pgm=01;35:*.png=01;35:*.ppm=01;35:*.tga=01;35:*.tif=01;35:*.xbm=01;35:*.xpm=01;35:*.dl=01;35:*.gl=01;35:*.wmv=01;35:*.aiff=00;32:*.au=00;32:*.mid=00;32:*.mp3=00;32:*.ogg=00;32:*.voc=00;32:*.wav=00;32:' -pure_prompt() { - ps_host="${bold_blue}\h${normal}" - ps_user="${green}\u${normal}" - ps_user_mark="${green} $ ${normal}" - ps_root="${red}\u${red}" - ps_root_mark="${red} # ${normal}" - ps_path="${yellow}\w${normal}" +function pure_prompt() { + local ps_host="${bold_blue?}\h${normal?}" + local ps_user="${green?}\u${normal?}" + local ps_user_mark="${green?} $ ${normal?}" + local ps_root="${red?}\u${red?}" + local ps_root_mark="${red?} # ${normal?}" + local ps_path="${yellow?}\w${normal?}" + local virtualenv_prompt scm_prompt + virtualenv_prompt="$(virtualenv_prompt)" + scm_prompt="$(scm_prompt)" # make it work - case $(id -u) in + case "${EUID:-$UID}" in 0) - PS1="$(virtualenv_prompt)$ps_root@$ps_host$(scm_prompt):$ps_path$ps_root_mark" + PS1="${virtualenv_prompt}${ps_root}@${ps_host}${scm_prompt}:${ps_path}${ps_root_mark}" ;; *) - PS1="$(virtualenv_prompt)$ps_user@$ps_host$(scm_prompt):$ps_path$ps_user_mark" + PS1="${virtualenv_prompt}${ps_user}@${ps_host}${scm_prompt}:${ps_path}${ps_user_mark}" ;; esac } diff --git a/themes/purity/purity.theme.bash b/themes/purity/purity.theme.bash index 22a3fbfb..0fc6c4cf 100644 --- a/themes/purity/purity.theme.bash +++ b/themes/purity/purity.theme.bash @@ -1,36 +1,44 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. -SCM_THEME_PROMPT_DIRTY=" ${bold_red}⊘${normal}" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" -SCM_THEME_PROMPT_PREFIX="${reset_color}( " -SCM_THEME_PROMPT_SUFFIX=" ${reset_color})" +SCM_THEME_PROMPT_DIRTY=" ${bold_red?}⊘${normal?}" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓${normal?}" +SCM_THEME_PROMPT_PREFIX="${reset_color?}( " +SCM_THEME_PROMPT_SUFFIX=" ${reset_color?})" -GIT_THEME_PROMPT_DIRTY=" ${bold_red}⊘${normal}" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" -GIT_THEME_PROMPT_PREFIX="${reset_color}( " -GIT_THEME_PROMPT_SUFFIX=" ${reset_color})" +GIT_THEME_PROMPT_DIRTY=" ${bold_red?}⊘${normal?}" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓${normal?}" +GIT_THEME_PROMPT_PREFIX="${reset_color?}( " +GIT_THEME_PROMPT_SUFFIX=" ${reset_color?})" -STATUS_THEME_PROMPT_BAD="${bold_red}❯${reset_color}${normal} " -STATUS_THEME_PROMPT_OK="${bold_green}❯${reset_color}${normal} " -PURITY_THEME_PROMPT_COLOR="${PURITY_THEME_PROMPT_COLOR:=$blue}" +STATUS_THEME_PROMPT_BAD="${bold_red?}❯${reset_color?}${normal?} " +STATUS_THEME_PROMPT_OK="${bold_green?}❯${reset_color?}${normal?} " +: "${PURITY_THEME_PROMPT_COLOR:=$blue}" -venv_prompt() { +function venv_prompt() { python_venv="" # Detect python venv - if [[ -n "${CONDA_DEFAULT_ENV}" ]]; then - python_venv="($PYTHON_VENV_CHAR${CONDA_DEFAULT_ENV}) " + if [[ -n "${CONDA_DEFAULT_ENV:-}" ]]; then + python_venv="(${PYTHON_VENV_CHAR}${CONDA_DEFAULT_ENV}) " elif [[ -n "${VIRTUAL_ENV}" ]]; then - python_venv="($PYTHON_VENV_CHAR$(basename "${VIRTUAL_ENV}")) " + python_venv="(${PYTHON_VENV_CHAR}${VIRTUAL_ENV##*/}) " fi [[ -n "${python_venv}" ]] && echo "${python_venv}" } function prompt_command() { - local retval=$? ret_status - ret_status="$([ $retval -eq 0 ] && echo -e "$STATUS_THEME_PROMPT_OK" || echo -e "$STATUS_THEME_PROMPT_BAD")" - PS1="\n${PURITY_THEME_PROMPT_COLOR}\w $(scm_prompt_info)\n${ret_status}$(venv_prompt)" + local retval="$?" ret_status python_venv scm_prompt_info venv_prompt + case "${retval}" in + 0) + ret_status="$STATUS_THEME_PROMPT_OK" + ;; + *) + ret_status="$STATUS_THEME_PROMPT_BAD" + ;; + esac + scm_prompt_info="$(scm_prompt_info)" + venv_prompt="$(venv_prompt)" + PS1="\n${PURITY_THEME_PROMPT_COLOR}\w ${scm_prompt_info}\n${ret_status}${venv_prompt}" } safe_append_prompt_command prompt_command diff --git a/vendor/github.com/gaelicWizard/bash-progcomp/.editorconfig b/vendor/github.com/gaelicWizard/bash-progcomp/.editorconfig new file mode 100644 index 00000000..e1eba2cf --- /dev/null +++ b/vendor/github.com/gaelicWizard/bash-progcomp/.editorconfig @@ -0,0 +1,40 @@ +# EditorConfig is awesome: http://EditorConfig.org + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[**.md] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = false + +[.git*] +indent_style = tab + +[**.*sh] +indent_style = tab +indent_size = tab + +shell_variant = bash +binary_next_line = true # like -bn +switch_case_indent = false # like -ci +space_redirects = true # like -sr +keep_padding = false # like -kp +function_next_line = true # like -fn +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[**.bats] +indent_style = tab +indent_size = tab + +shell_variant = bash +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/vendor/github.com/gaelicWizard/bash-progcomp/LICENSE b/vendor/github.com/gaelicWizard/bash-progcomp/LICENSE new file mode 100644 index 00000000..cd48959a --- /dev/null +++ b/vendor/github.com/gaelicWizard/bash-progcomp/LICENSE @@ -0,0 +1,30 @@ +BSD 3-Clause License + +Copyright (c) 2006, Playhaus +Copyright (c) 2021, gaelicWizard.LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash b/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash new file mode 100644 index 00000000..67cb4fe5 --- /dev/null +++ b/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash @@ -0,0 +1,286 @@ +# shellcheck shell=bash +# shellcheck disable=SC2207 +# +# Bash command line completion for defaults +# +# Version 1.0 created by Jonathon Mah on 2006-11-08. +# Version 2.0 written by John Pell on 2021-09-11. +# + +function matchpattern() +{ + local PATTERN=${2:?$FUNCNAME: a pattern is required} + local SEP=${3:-|} + [[ -z "${PATTERN##*${SEP}${1}${SEP}*}" ]] +} + +function _defaults_verbs() +{ + local IFS=$'\n' # Treat only newlines as delimiters in string operations. + local LC_CTYPE='C' # Do not consider character set in string operations. + local LC_COLLATE='C' # Do not consider character set in pattern matching. + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD - 1]}" + COMPREPLY=() + + case $COMP_CWORD in + 1) + candidates=("${cmds// /$IFS}" "${host_opts[@]}") + ;; + 2 | 3) + candidates=("${cmds// /$IFS}") + ;; + *) + return 1 + ;; + esac + + COMPREPLY=($(compgen -W "${candidates[*]}" | grep -i "^${cur}")) + return 0 +} + +function _defaults_domains() +{ + local IFS=$'\n' # Treat only newlines as delimiters in string operations. + local LC_CTYPE='C' # Do not consider character set in string operations. + local LC_COLLATE='C' # Do not consider character set in pattern matching. + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD - 1]}" + COMPREPLY=() + + if [[ "$BASH_VERSINFO" -ge 4 ]] + then # Exponential performance issue on strings greater than about 10k. + local domains="$(defaults domains)" + local candidates=($(compgen -W "${domains//, /$IFS}" | grep -i "^${cur}")) + else + local domains="$(defaults domains | sed -e 's/, /^/g' | tr '^' '\n')" + local candidates=($(compgen -W "${domains}" | grep -i "^${cur}")) + fi + COMPREPLY=($(printf '%q\n' "${candidates[@]}")) + if grep -q "^$cur" <<< '-app' + then + COMPREPLY[${#COMPREPLY[@]}]="-app" + elif grep -q "^$cur" <<< '-g' + then + COMPREPLY[${#COMPREPLY[@]}]="-g" + fi + + return 0 +} + +function _defaults() +{ + local IFS=$'\n' # Treat only newlines as delimiters in string operations. + local LC_CTYPE='C' # Do not consider character set in string operations. + local LC_COLLATE='C' # Do not consider character set in pattern matching. + local cur="${COMP_WORDS[COMP_CWORD]}" + local prev="${COMP_WORDS[COMP_CWORD - 1]}" + COMPREPLY=() + + local host_opts cmds cmd domain keys key_index candidates verbs value_types + + host_opts=('-currentHost' '-host') + cmds=' delete domains export find help import read read-type rename write ' + value_types=('-string' '-data' '-integer' '-float' '-boolean' '-date' '-array' '-array-add' '-dict' '-dict-add') + + case $COMP_CWORD in + 1) + _defaults_verbs + return "$?" + ;; + 2) + case $prev in + "-currentHost") + _defaults_verbs + ;; + "-host") + _known_hosts -a + ;; + *) + if matchpattern "$prev" "${cmds// /|}" + then + # TODO: not correct for verbs: domains, find, help + _defaults_domains + else + return 1 # verb is not recognized + fi + ;; + esac + return "$?" + ;; + 3) + case ${COMP_WORDS[1]} in + "-currentHost") + _defaults_domains + return "$?" + ;; + "-host") + _defaults_verbs + return "$?" + ;; + esac + ;; + 4) + case ${COMP_WORDS[1]} in + "-host") + if matchpattern "$prev" "${cmds// /|}" + then + # TODO: not correct for verbs: domains, find, help + _defaults_domains + else + return 1 # verb is not recognized + fi + ;; + esac + ;; + esac + + # Both a domain and command have been specified + + case ${COMP_WORDS[1]} in + "-currentHost") + if matchpattern "${COMP_WORDS[2]}" "${cmds// /|}" + then + cmd="${COMP_WORDS[2]}" + domain="${COMP_WORDS[3]}" + key_index=4 + if [[ "$domain" == "-app" ]] + then + if [[ $COMP_CWORD -eq 4 ]] + then + # Completing application name. Can't help here, sorry + return 0 + fi + domain="-app ${COMP_WORDS[4]}" + key_index=5 + fi + fi + ;; + "-host") + if matchpattern "${COMP_WORDS[3]}" "${cmds// /|}" + then + cmd="${COMP_WORDS[3]}" + domain="${COMP_WORDS[4]}" + key_index=5 + if [[ "$domain" == "-app" ]] + then + if [[ $COMP_CWORD -eq 5 ]] + then + # Completing application name. Can't help here, sorry + return 0 + fi + domain="-app ${COMP_WORDS[5]}" + key_index=6 + fi + fi + ;; + *) + if matchpattern "${COMP_WORDS[1]}" "${cmds// /|}" + then + cmd="${COMP_WORDS[1]}" + domain="${COMP_WORDS[2]}" + key_index=3 + if [[ "$domain" == "-app" ]] + then + if [[ $COMP_CWORD -eq 3 ]] + then + # Completing application name. Can't help here, sorry + return 0 + fi + domain="-app ${COMP_WORDS[3]}" + key_index=4 + fi + fi + ;; + + esac + + keys=($(defaults read "$domain" 2> /dev/null | sed -n -e '/^ [^}) ]/p' | sed -e 's/^ \([^" ]\{1,\}\) = .*$/\1/g' -e 's/^ "\([^"]\{1,\}\)" = .*$/\1/g')) + + case $cmd in + read | read-type) + # Complete key + if candidates=($(compgen -W "${keys[*]:-}" | grep -i "^${cur}")) + then + COMPREPLY=($(printf '%q\n' "${candidates[@]}")) + fi + ;; + write) + if [[ $key_index -eq $COMP_CWORD ]] + then + # Complete key + if candidates=($(compgen -W "${keys[*]:-}" | grep -i "^${cur}")) + then + COMPREPLY=($(printf '%q\n' "${candidates[@]}")) + fi + elif [[ $((key_index + 1)) -eq $COMP_CWORD ]] + then + # Complete value type + local cur_type="$(defaults read-type "$domain" "${COMP_WORDS[key_index]}" 2> /dev/null | sed -e 's/^Type is \(.*\)/-\1/' -e's/dictionary/dict/' | grep "^$cur")" + if [[ $cur_type ]] + then + COMPREPLY=("$cur_type") + else + COMPREPLY=($(compgen -W "${value_types[*]}" -- "$cur")) + fi + elif [[ $((key_index + 2)) -eq $COMP_CWORD ]] + then + # Complete value + COMPREPLY=($(defaults read "$domain" "${COMP_WORDS[key_index]}" 2> /dev/null | grep -i "^${cur//\\/\\\\}")) + fi + ;; + rename) + if [[ $key_index -eq $COMP_CWORD || $((key_index + 1)) -eq $COMP_CWORD ]] + then + # Complete source and destination keys + if candidates=($(compgen -W "${keys[*]:-}" | grep -i "^${cur}")) + then + COMPREPLY=($(printf '%q\n' "${candidates[@]}")) + fi + fi + ;; + delete) + if [[ $key_index -eq $COMP_CWORD ]] + then + # Complete key + if candidates=($(compgen -W "${keys[*]:-}" | grep -i "^${cur}")) + then + COMPREPLY=($(printf '%q\n' "${candidates[@]}")) + fi + fi + ;; + esac + + return 0 +} + +complete -F _defaults -o default defaults + +# This file is licensed under the BSD license, as follows: +# +# Copyright (c) 2006, Playhaus +# Copyright (c) 2021, gaelicWizard.LLC +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# * Neither the names of the authors nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# This software is provided by the copyright holders and contributors "as is" +# and any express or implied warranties, including, but not limited to, the +# implied warranties of merchantability and fitness for a particular purpose are +# disclaimed. In no event shall the copyright owner or contributors be liable +# for any direct, indirect, incidental, special, exemplary, or consequential +# damages (including, but not limited to, procurement of substitute goods or +# services; loss of use, data, or profits; or business interruption) however +# caused and on any theory of liability, whether in contract, strict liability, +# or tort (including negligence or otherwise) arising in any way out of the use +# of this software, even if advised of the possibility of such damage. diff --git a/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bats b/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bats new file mode 100755 index 00000000..65b32dad --- /dev/null +++ b/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bats @@ -0,0 +1,184 @@ +#!/usr/bin/env bats + +load ../test_helper + +function local_setup() { + load ../../completion/available/defaults.completion + function _known_hosts() { :; } + function defaults() { echo 'NSGlobalDomain, Bash It'; } +} + +function __check_completion() { + # Get the parameters as a single value + COMP_LINE=$* + + # Get the parameters as an array + eval set -- "$@" + COMP_WORDS=("$@") + + # Index of the cursor in the line + COMP_POINT=${#COMP_LINE} + + # Get the last character of the line that was entered + COMP_LAST=$((${COMP_POINT} - 1)) + + # If the last character was a space... + if [[ ${COMP_LINE:$COMP_LAST} = ' ' ]]; then + # ...then add an empty array item + COMP_WORDS+=('') + fi + + # Word index of the last word + COMP_CWORD=$(( ${#COMP_WORDS[@]} - 1 )) + + # Run the Bash-it completion function + _defaults + + # Return the completion output + echo "${COMPREPLY[@]}" +} + +@test "completion defaults: ensure that the _defaults function is available" { + type -a _defaults &> /dev/null + assert_success +} + +@test "completion defaults: - show verbs and options" { + run __check_completion 'defaults ' + assert_line -n 0 'delete domains export find help import read read-type rename write -currentHost -host' +} + +@test "completion defaults: r* - show matching verbs" { + run __check_completion 'defaults r' + assert_line -n 0 'read read-type rename' +} + +@test "completion defaults: R* - show matching verbs" { + run __check_completion 'defaults R' + assert_line -n 0 'read read-type rename' +} + +@test "completion defaults: -* - show matching flags" { + run __check_completion 'defaults -' + assert_line -n 0 '-currentHost -host' +} + +@test "completion defaults: -currentHost - show verbs" { + run __check_completion 'defaults -currentHost ' + assert_line -n 0 'delete domains export find help import read read-type rename write' +} + +@test "completion defaults: -host - show nothing" { + run __check_completion 'defaults -host ' + assert_line -n 0 "$(_known_hosts -a)" +} + +@test "completion defaults: -host some_computer_name - show verbs" { + run __check_completion 'defaults -host some_computer_name ' + assert_line -n 0 'delete domains export find help import read read-type rename write' +} + +@test "completion defaults: read - show all domains" { + run __check_completion 'defaults read ' + assert_line -n 0 "NSGlobalDomain Bash\ It -app" +} + +@test "completion defaults: read nsg* - show matching domains" { + run __check_completion 'defaults read nsg' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: read NSG* - show matching domains" { + run __check_completion 'defaults read NSG' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: read bash* - show matching domains" { + run __check_completion 'defaults read bash' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: read BASH* - show matching domains" { + run __check_completion 'defaults read BASH' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: read bash* - show matching domains (with spaces)" { + run __check_completion 'defaults read bash\ i' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: read BASH* - show matching domains (with spaces)" { + run __check_completion 'defaults read BASH\ I' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -currentHost read - show all domains" { + run __check_completion 'defaults -currentHost read ' + assert_line -n 0 "NSGlobalDomain Bash\ It -app" +} + +@test "completion defaults: -currentHost read nsg* - show matching domains" { + run __check_completion 'defaults -currentHost read nsg' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: -currentHost read NSG* - show matching domains" { + run __check_completion 'defaults -currentHost read NSG' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: -currentHost read bash* - show matching domains" { + run __check_completion 'defaults -currentHost read bash' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -currentHost read BASH* - show matching domains" { + run __check_completion 'defaults -currentHost read BASH' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -currentHost read bash* - show matching domains (with spaces)" { + run __check_completion 'defaults -currentHost read bash\ i' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -currentHost read BASH* - show matching domains (with spaces)" { + run __check_completion 'defaults -currentHost read BASH\ I' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -host some.computer.name read - show all domains" { + run __check_completion 'defaults -host some.computer.name read ' + assert_line -n 0 "NSGlobalDomain Bash\ It -app" +} + +@test "completion defaults: -host some.computer.name read nsg* - show matching domains" { + run __check_completion 'defaults -host some.computer.name read nsg' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: -host some.computer.name read NSG* - show matching domains" { + run __check_completion 'defaults -host some.computer.name read NSG' + assert_line -n 0 "NSGlobalDomain" +} + +@test "completion defaults: -host some.computer.name read bash* - show matching domains" { + run __check_completion 'defaults -host some.computer.name read bash' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -host some.computer.name read BASH* - show matching domains" { + run __check_completion 'defaults -host some.computer.name read BASH' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -host some.computer.name read bash* - show matching domains (with spaces)" { + run __check_completion 'defaults -host some.computer.name read bash\ i' + assert_line -n 0 "Bash\ It" +} + +@test "completion defaults: -host some.computer.name read BASH* - show matching domains (with spaces)" { + run __check_completion 'defaults -host some.computer.name read BASH\ I' + assert_line -n 0 "Bash\ It" +} diff --git a/vendor/init.d/preexec.bash b/vendor/init.d/preexec.bash index 25596dd6..6cfa7b0a 100644 --- a/vendor/init.d/preexec.bash +++ b/vendor/init.d/preexec.bash @@ -8,7 +8,7 @@ # Disable immediate `$PROMPT_COMMAND` modification __bp_delay_install="delayed" -# shellcheck source=SCRIPTDIR/../github.com/rcaloras/bash-preexec +# shellcheck source-path=SCRIPTDIR/../github.com/rcaloras/bash-preexec source "${BASH_IT?}/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh" # Block damanaging user's `$HISTCONTROL`