diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..08abb8f6ce --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,5 @@ +# Ignore shfmt related commits +003b0ce802c10ab6e161d7ba5a7d9b6722312cc5 +7c2c2a5525557cbfee98e73de921fd7f7e6811a1 +d37505b636ca7bc95301d8daaf9c58a3186ce57a +d7695d5456b980190b6d1c4a4715b13d1b63c332 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a187422efb..a6d280cba3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -36,48 +36,32 @@ body: Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code to reproduce, if relevant. validations: required: true - - type: input - attributes: - label: Bash-it version - placeholder: "How to get: bash-it version" - validations: - required: true - - type: input - attributes: - label: List of enabled plugins, themes and aliases - placeholder: "How to get: bash-it show plugins|themes|aliases (it is not a pipe)" - validations: - required: true - - type: input - attributes: - label: Bash version - placeholder: "How to get: bash --version" - validations: - required: true - - type: input - attributes: - label: Operating system and version - placeholder: "How to get: neofetch (or another command)" - validations: - required: true - type: textarea attributes: - label: "bash-it doctor output" + label: "Diagnostic Information" + description: > + **Please run `bash-it doctor` and paste the complete output below.** + This single command provides all the diagnostic information we need including: + bash-it version, enabled components, bash version, OS version, and configuration. + placeholder: "Run: bash-it doctor" value: | ``` - # How to get: bash-it doctor + # Paste the output of: bash-it doctor + + ``` validations: - required: false + required: true - type: textarea attributes: - label: Your ~/.bashrc - value: | - ```bash - # How to get: cat ~/.bashrc - ``` + label: "Additional Context (Optional)" + description: > + Any additional information that might help diagnose the issue. + This could include specific error messages, relevant parts of your ~/.bashrc, + or other configuration details not captured by `bash-it doctor`. + placeholder: "Paste any additional relevant information here" validations: - required: true + required: false - type: textarea attributes: label: Notes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b82f628c20..b3298175e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: bats-test: strategy: matrix: - os: [ubuntu-20.04, ubuntu-24.04, macos-14] + os: [ubuntu-24.04, macos-14] runs-on: ${{ matrix.os }} diff --git a/.gitignore b/.gitignore index 8e6f12a106..856077d3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ tmp/ profiles/* # apart from the default one !profiles/default.bash_it + +/vendor/github.com/nojhan/liquidprompt +.trunk/ diff --git a/.gitmodules b/.gitmodules index 536f6e9283..4e1155917e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,11 +1,12 @@ [submodule "test_lib/bats-core"] path = test_lib/bats-core url = https://github.com/bats-core/bats-core - branch = tags/v1.9.0 + branch = tags/v1.11.1 [submodule "test_lib/bats-support"] path = test_lib/bats-support url = https://github.com/bats-core/bats-support - branch = tags/v0.3.0 + branch = master + #branch = tags/v0.3.0 [submodule "test_lib/bats-assert"] path = test_lib/bats-assert url = https://github.com/bats-core/bats-assert @@ -13,4 +14,4 @@ [submodule "test_lib/bats-file"] path = test_lib/bats-file url = https://github.com/bats-core/bats-file - branch = tags/v0.4.0 + branch = master diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07fa3a360e..b8615c4d14 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ --- # fail_fast: true minimum_pre_commit_version: 1.18.1 -exclude: "docs/_build/" +exclude: "docs/_build/|vendor/" repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.3.0 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..1364c6b23f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,158 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Bash-it is a collection of community Bash commands and scripts for Bash 3.2+, providing a framework for aliases, themes, plugins, and completions. It's structured as a modular system where components can be individually enabled or disabled. + +## Architecture + +### Core Components + +- **bash_it.sh**: Main entry point that initializes the framework +- **lib/**: Core libraries providing utilities, logging, helpers, and appearance functions +- **scripts/reloader.bash**: Component loader that sources enabled components +- **install.sh**: Installation script with interactive and silent modes +- **enabled/**: Symlinks to active components from available/ directories + +### Component Types + +1. **Aliases** (`aliases/available/`): Command shortcuts and convenience functions +2. **Plugins** (`plugins/available/`): Extended functionality and integrations +3. **Completions** (`completion/available/`): Tab completion definitions +4. **Themes** (`themes/`): Prompt customizations and visual styles + +### Loading Order + +1. Libraries (except appearance) +2. Global enabled directory +3. Enabled aliases, plugins, completions +4. Theme files (if BASH_IT_THEME is set) +5. Custom files from BASH_IT_CUSTOM directory + +## Development Commands + +### Testing +```bash +# Run all tests using BATS (Bash Automated Testing System) +test/run + +# Run specific test suites +test/run test/bash_it test/completion test/plugins + +# Tests require git submodules to be initialized +git submodule init && git submodule update +``` + +### Linting and Code Quality + +The project uses a gradual pre-commit system implementation via `clean_files.txt` allow-list: + +```bash +# Run pre-commit hooks only on allow-listed clean files +./lint_clean_files.sh + +# Run pre-commit hooks on all files (for testing new coverage) +pre-commit run --all-files + +# Manual shellcheck on bash files +shellcheck **/*.bash + +# Format shell scripts +shfmt -w **/*.bash +``` + +**Gradual Linting System**: +- `clean_files.txt`: Allow-list of files/directories that pass all linting rules +- `lint_clean_files.sh`: Runs pre-commit hooks only on allow-listed files +- When modifying files NOT in `clean_files.txt`, ensure they pass linting before adding them to the allow-list +- Before creating a PR, add newly cleaned files to `clean_files.txt` to expand coverage +- This system allows gradual improvement of code quality across the large codebase + +**Vendor Directory Policy**: +- Files in `vendor/` are treated as immutable external dependencies +- Pre-commit hooks exclude vendor files via `.pre-commit-config.yaml` global exclude pattern +- `clean_files.txt` does not include vendor shell scripts, only `.gitattributes` +- CI and local linting will skip vendor files entirely + +### Component Management +```bash +# Enable/disable components +bash-it enable alias git +bash-it enable plugin history +bash-it enable completion docker + +# Show available components +bash-it show aliases +bash-it show plugins +bash-it show completions + +# Search components +bash-it search docker +``` + +## Key Configuration + +### Environment Variables +- `BASH_IT`: Base directory path +- `BASH_IT_THEME`: Active theme name +- `BASH_IT_CUSTOM`: Custom components directory +- `BASH_IT_LOG_PREFIX`: Logging prefix for debug output + +### File Structure Conventions +- Available components: `{type}/available/{name}.{type}.bash` +- Enabled components: `{type}/enabled/{name}.{type}.bash` (symlinks) +- Custom components: `custom/{name}.bash` +- Themes: `themes/{name}/` + +## Development Guidelines + +### Git Workflow +- **NEVER commit directly to master branch** +- Master should always stay in sync with `origin/master` +- Always create a feature branch for new work: `git checkout -b feature/feature-name` +- Keep feature branches focused on a single issue/feature +- Create separate branches for separate features +- Push feature branches with upstream tracking: `git push -u fork feature-branch-name` + - This allows manual pushes later with just `git push` + - Use `--force-with-lease` for rebased branches + +### Component Development +- Use composure metadata: `about`, `group`, `author`, `example` +- Follow naming convention: `{name}.{type}.bash` +- Test components before submitting +- Components should be modular and not conflict with others + +### Testing Components +- Each component type has dedicated test files in `test/` +- Use BATS framework for shell script testing +- Test files follow pattern: `{component}.bats` + +### Code Standards +- Use shellcheck for linting +- Follow existing code style in the repository +- Add appropriate metadata using composure functions +- Components should handle missing dependencies gracefully +- **Prefix sensitive commands with `command`** to bypass user aliases: + - `command mv` instead of `mv` (users may have `alias mv='mv -i'`) + - `command grep` instead of `grep` (users may have custom grep flags) + - `command rm` instead of `rm` (users may have `alias rm='rm -i'`) + - Apply to any command that could be aliased and break core functionality + - This prevents surprises from user's alias configurations in bash-it core functions +- **Use parameter expansion with default for potentially unset variables**: + - `${VARIABLE-}` instead of `$VARIABLE` when variable may be unset + - Prevents errors when `set -u` is active in user's shell + - Examples: `${BASH_VERSION-}`, `${HOME-}`, `${PATH-}` + - Critical for variables checked in conditionals: `if [ -n "${BASH_VERSION-}" ]` + - This defensive practice ensures scripts work regardless of user's shell options + +## Project Planning & Roadmaps + +Strategic planning documents are maintained in `docs/plans/`: + +- **[Quick Reference](docs/plans/bash-it-quick-reference.md)** - TL;DR summary of current issues and action items +- **[Comprehensive Issue Analysis](docs/plans/bash-it-issues-comprehensive-analysis.md)** - Detailed breakdown of all open issues with categorization and recommendations +- **[2025 Roadmap](docs/plans/bash-it-roadmap-2025.md)** - 6-month technical debt reduction plan with phases and success metrics + +These documents guide ongoing maintenance, issue triage, and code quality improvements. diff --git a/aliases/available/directory.aliases.bash b/aliases/available/directory.aliases.bash new file mode 100644 index 0000000000..671ceffe5e --- /dev/null +++ b/aliases/available/directory.aliases.bash @@ -0,0 +1,26 @@ +# shellcheck shell=bash +about-alias 'Shortcuts for directory commands: ls, cd, &c.' + +if command ls --color -d . &> /dev/null; then + alias ls='ls --color=auto' + # BSD `ls` doesn't need an argument (`-G`) when `$CLICOLOR` is set. +fi + +# List directory contents +alias sl=ls +alias la='ls -AF' # Compact view, show hidden +alias ll='ls -Al' +alias l='ls -A' +alias l1='ls -1' +alias lf='ls -F' + +# Change directory +alias ..='cd ..' # Go up one directory +alias cd..='cd ..' # Common misspelling for going up one directory +alias ...='cd ../..' # Go up two directories +alias ....='cd ../../..' # Go up three directories +alias -- -='cd -' # Go back + +# Create or remove directory +alias md='mkdir -p' +alias rd='rmdir' diff --git a/aliases/available/editor.aliases.bash b/aliases/available/editor.aliases.bash new file mode 100644 index 0000000000..654f910f77 --- /dev/null +++ b/aliases/available/editor.aliases.bash @@ -0,0 +1,14 @@ +# shellcheck shell=bash +about-alias 'shortcuts for editing' + +alias edit='${EDITOR:-${ALTERNATE_EDITOR:-nano}}' +alias e='edit' + +# sudo editors +alias svim='sudo ${VISUAL:-vim}' +alias snano='sudo ${ALTERNATE_EDITOR:-nano}' +alias sedit='sudo ${EDITOR:-${ALTERNATE_EDITOR:-nano}}' + +# Shortcuts to edit startup files +alias vbrc='${VISUAL:-vim} ~/.bashrc' +alias vbpf='${VISUAL:-vim} ~/.bash_profile' diff --git a/aliases/available/general.aliases.bash b/aliases/available/general.aliases.bash index 2511aab8a9..35a956bc86 100644 --- a/aliases/available/general.aliases.bash +++ b/aliases/available/general.aliases.bash @@ -1,4 +1,5 @@ # shellcheck shell=bash +# shellcheck source-path=SCRIPTDIR about-alias 'general aliases' if command ls --color -d . &> /dev/null; then @@ -9,17 +10,13 @@ fi # List directory contents alias sl=ls alias la='ls -AF' # Compact view, show hidden -alias ll='ls -al' -alias l='ls -a' +alias ll='ls -Al' +alias l='ls -A' alias l1='ls -1' alias lf='ls -F' alias _='sudo' -# Shortcuts to edit startup files -alias vbrc='${VISUAL:-vim} ~/.bashrc' -alias vbpf='${VISUAL:-vim} ~/.bash_profile' - # colored grep # Need to check an existing file for a pattern that will be found to ensure # that the check works when on an OS that supports the color option @@ -39,7 +36,7 @@ alias pager='${PAGER:=less}' alias q='exit' -alias irc='${IRC_CLIENT:=irc}' +alias irc='${IRC_CLIENT:-irc}' # Language aliases alias rb='ruby' @@ -47,14 +44,16 @@ alias py='python' alias ipy='ipython' # Pianobar can be found here: http://github.com/PromyLOPh/pianobar/ +if _command_exists pianobar; then + alias piano='pianobar' +fi -alias piano='pianobar' - -alias ..='cd ..' # Go up one directory -alias cd..='cd ..' # Common misspelling for going up one directory -alias ...='cd ../..' # Go up two directories -alias ....='cd ../../..' # Go up three directories -alias -- -='cd -' # Go back +alias ..='cd ..' # Go up one directory +alias cd..='cd ..' # Common misspelling for going up one directory +alias ...='cd ../..' # Go up two directories +alias ....='cd ../../..' # Go up three directories +alias -- -='cd -' # Go back +alias dow='cd $HOME/Downloads' # Go to the Downloads directory # Shell History alias h='history' @@ -68,8 +67,16 @@ fi alias md='mkdir -p' alias rd='rmdir' +# Remove +alias rmrf='rm -rf' + # Shorten extract -alias xt='extract' +_command_exists 'extract' \ + && alias xt='extract' + +# sudo editors +alias svim='sudo "${VISUAL:-vim}"' +alias snano='sudo "${ALTERNATE_EDITOR:-nano}"' # Display whatever file is regular file or folder function catt() { @@ -88,5 +95,6 @@ function catt() { # aliases and enable just the ones for Bash-it explicitly: # bash-it disable alias general # bash-it enable alias bash-it -# shellcheck source-path=SCRIPTDIR source "$BASH_IT/aliases/available/bash-it.aliases.bash" +source "$BASH_IT/aliases/available/directory.aliases.bash" +source "$BASH_IT/aliases/available/editor.aliases.bash" diff --git a/aliases/available/git-omz.aliases.bash b/aliases/available/git-omz.aliases.bash new file mode 100644 index 0000000000..f7c01fc4d9 --- /dev/null +++ b/aliases/available/git-omz.aliases.bash @@ -0,0 +1,34 @@ +# shellcheck shell=bash +cite 'about-alias' +about-alias 'git aliases from oh-my-zsh (incompatible with regular git aliases option)' + +if _bash-it-component-item-is-enabled aliases git; then + _log_warning "git-omz aliases are incompatible with regular git aliases" + return 1 +fi + +# Load after regular git aliases +# BASH_IT_LOAD_PRIORITY: 160 + +# Setup git version +read -ra git_version_arr <<< "$(git version 2> /dev/null)" +# shellcheck disable=SC2034 +git_version="${git_version_arr[2]}" + +# Setup is-at-least +function is-at-least { + local expected_version=$1 + local actual_version=$2 + local versions + + printf -v versions '%s\n%s' "$expected_version" "$actual_version" + [[ $versions = "$(sort -V <<< "$versions")" ]] +} + +# Setup git_current_branch +function git_current_branch { + _git-branch +} + +# shellcheck disable=SC1090 +source "${BASH_IT}"/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/git.plugin.zsh diff --git a/aliases/available/git.aliases.bash b/aliases/available/git.aliases.bash index f3cf6fa11e..c6209af81f 100644 --- a/aliases/available/git.aliases.bash +++ b/aliases/available/git.aliases.bash @@ -1,9 +1,15 @@ # shellcheck shell=bash about-alias 'common git abbreviations' +# We can use this variable to make sure that we don't accidentally clash with git-zsh aliases +if _bash-it-component-item-is-enabled aliases git-omz; then + _log_warning "The aliases from 'git' and from 'git-omz' conflict with each other; please only enable one." + return 1 +fi + alias g='git' alias get='git' -alias got='git ' +alias got='git' # add alias ga='git add' @@ -105,6 +111,7 @@ alias gm='git merge' alias gma='git merge --abort' alias gmc='git merge --continue' alias gms='git merge --squash' +alias gmt='git mergetool' # mv alias gmv='git mv' @@ -205,6 +212,12 @@ alias gta='git tag -a' alias gtd='git tag -d' alias gtl='git tag -l' +#worktree +alias gw='git worktree' +alias gwa='git worktree add' +alias gwl='git worktree list' +alias gwr='git worktree remove' + case $OSTYPE in darwin*) alias gtls="git tag -l | gsort -V" diff --git a/aliases/available/laravel.aliases.bash b/aliases/available/laravel.aliases.bash index 50a9749f91..d602295fd3 100644 --- a/aliases/available/laravel.aliases.bash +++ b/aliases/available/laravel.aliases.bash @@ -3,7 +3,14 @@ about-alias 'laravel artisan abbreviations' # A list of useful laravel aliases -alias laravel='${HOME?}/.composer/vendor/bin/laravel' +if [[ -x "${HOME?}/.config/composer/vendor/bin/laravel" ]]; then + alias laravel='${HOME?}/.config/composer/vendor/bin/laravel' +elif [[ -x "${HOME?}/.composer/vendor/bin/laravel" ]]; then + alias laravel='${HOME?}/.composer/vendor/bin/laravel' +else + return +fi + # asset alias a:apub='php artisan asset:publish' diff --git a/aliases/available/terraform.aliases.bash b/aliases/available/terraform.aliases.bash index b236b5fd9f..b4eb74163e 100644 --- a/aliases/available/terraform.aliases.bash +++ b/aliases/available/terraform.aliases.bash @@ -1,10 +1,22 @@ # shellcheck shell=bash -about-alias 'Aliases for Terraform and Terragrunt' +about-alias 'Aliases for Terraform/OpenTofu and Terragrunt' -alias tf='terraform' -alias tfi='tf init' -alias tfv='terraform validate' -alias tfp='terraform plan' -alias tfa='terraform apply' -alias tfd='terraform destroy' -alias tfw='terraform workspace' +if _command_exists terraform; then + alias tf='terraform' +elif _command_exists tofu; then + alias tf='tofu' +fi + +if _command_exists tf; then + alias tfa='tf apply' + alias tfp='tf plan' + alias tfd='tf destroy' + alias tfv='tf validate' + alias tfi='tf init' + alias tfo='tf output' + alias tfr='tf refresh' + alias tfw='tf workspace' + alias tfae='tf apply -auto-approve' + alias tfpa='tf plan -out=tfplan && tf apply tfplan' + alias tfpaf='tf plan -out=tfplan && tf apply -auto-approve tfplan' +fi diff --git a/aliases/available/todo.txt-cli.aliases.bash b/aliases/available/todo.aliases.bash similarity index 100% rename from aliases/available/todo.txt-cli.aliases.bash rename to aliases/available/todo.aliases.bash diff --git a/aliases/available/vim.aliases.bash b/aliases/available/vim.aliases.bash index f80687640b..d6383175c2 100644 --- a/aliases/available/vim.aliases.bash +++ b/aliases/available/vim.aliases.bash @@ -1,9 +1,11 @@ # shellcheck shell=bash about-alias 'vim abbreviations' -_command_exists vim || return +alias v='${VISUAL:-vim}' -alias v='vim' +if ! _command_exists vim; then + _log_warning "Without 'vim', these aliases just aren't that useful..." +fi # open the vim help in fullscreen incorporated from # https://stackoverflow.com/a/4687513 alias vimh='vim -c ":h | only"' diff --git a/bash_it.sh b/bash_it.sh index ddc02b708f..19a26ed965 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -22,11 +22,9 @@ _bash_it_library_finalize_hook=() # We need to load logging module early in order to be able to log source "${BASH_IT}/lib/log.bash" -# libraries, but skip appearance (themes) for now -_log_debug "Loading libraries(except appearance)..." -APPEARANCE_LIB="${BASH_IT}/lib/appearance.bash" +# Load libraries +_log_debug "Loading libraries..." for _bash_it_main_file_lib in "${BASH_IT}/lib"/*.bash; do - [[ "$_bash_it_main_file_lib" == "$APPEARANCE_LIB" ]] && continue _bash-it-log-prefix-by-path "${_bash_it_main_file_lib}" _log_debug "Loading library file..." # shellcheck disable=SC1090 @@ -55,10 +53,14 @@ if [[ -n "${BASH_IT_THEME:-}" ]]; then source "${BASH_IT}/themes/base.theme.bash" BASH_IT_LOG_PREFIX="lib: appearance: " - # appearance (themes) now, after all dependencies - # shellcheck source=SCRIPTDIR/lib/appearance.bash - source "$APPEARANCE_LIB" - BASH_IT_LOG_PREFIX="core: main: " + # shellcheck disable=SC1090 + 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" + elif [[ -f "$BASH_IT/themes/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" ]]; then + source "$BASH_IT/themes/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" + fi fi _log_debug "Loading custom aliases, completion, plugins..." diff --git a/clean_files.txt b/clean_files.txt index bc29c62ded..8bfc2b0e7c 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -17,12 +17,13 @@ # root directories # aliases/ -completions/ +completion/ docs/ hooks/ lib/ plugins/ scripts/ +template/ test/ # root files @@ -32,6 +33,7 @@ bash_it.sh clean_files.txt install.sh lint_clean_files.sh +uninstall.sh # themes # @@ -41,7 +43,6 @@ themes/atomic themes/axin themes/bakke themes/barbuk -themes/base.theme.bash themes/binaryanomaly themes/bira themes/bobby @@ -50,23 +51,43 @@ themes/brainy themes/brunton themes/candy themes/clean +themes/codeword +themes/cooperkid +themes/cupcake +themes/demula +themes/dos themes/doubletime +themes/doubletime_multiline +themes/doubletime_multiline_pyonly +themes/dulcie +themes/duru themes/easy themes/elixr +themes/emperor +themes/envy themes/essential -themes/githelpers.theme.bash +themes/font +themes/gallifrey themes/gitline +themes/hawaii50 themes/inretio +themes/iterate +themes/kitsune themes/lambda +themes/liquidprompt +themes/luan themes/modern themes/norbu themes/oh-my-posh themes/p4helpers.theme.bash themes/pete themes/powerline +themes/powerline-multiline +themes/powerline-naked themes/pure themes/purity themes/rjorgenson +themes/robbyrussell # vendor init files # diff --git a/completion/available/aliases.completion.bash b/completion/available/aliases.completion.bash index a4b15959a8..2748d66208 100644 --- a/completion/available/aliases.completion.bash +++ b/completion/available/aliases.completion.bash @@ -9,7 +9,7 @@ about-plugin 'Automatic completion of aliases' # Automatically add completion for all aliases to commands having completion functions function _bash-it-component-completion-callback-on-init-aliases() { - local namespace="alias_completion" + local aliasCommandFunction namespace="alias_completion" local tmp_file completion_loader alias_name line completions chars local alias_arg_words new_completion compl_func compl_wrapper alias_defn @@ -40,6 +40,24 @@ function _bash-it-component-completion-callback-on-init-aliases() { line="${line#alias -- }" line="${line#alias }" alias_name="${line%%=*}" + + # Skip aliases not added by this script that already have completion functions. + # This allows users to define their own alias completion functions. + # For aliases added by this script, we do want to replace them in case the + # alias getting the completion added has changed. + if complete -p "$alias_name" &> /dev/null; then + # Get the -F argument from the existing completion for this alias. + aliasCommandFunction=$(complete -p "$alias_name" | rev | cut -d " " -f 2 | rev) + # Check if aliasCommandFunction starts with our namespace. + if [[ "$aliasCommandFunction" != "_${namespace}::"* ]]; then + continue + fi + + # Remove existing completion. It will be replaced by the new one. We need to + # delete it in case the new alias does not support having completion added. + complete -r "$alias_name" + fi + alias_defn="${line#*=\'}" # alias definition alias_defn="${alias_defn%\'}" alias_cmd="${alias_defn%%[[:space:]]*}" # first word of alias @@ -71,13 +89,22 @@ function _bash-it-component-completion-callback-on-init-aliases() { fi new_completion="$(complete -p "$alias_cmd" 2> /dev/null)" - # create a wrapper inserting the alias arguments if any - if [[ -n $alias_args ]]; then - compl_func="${new_completion/#* -F /}" - compl_func="${compl_func%% *}" - # avoid recursive call loops by ignoring our own functions - if [[ "${compl_func#_"$namespace"::}" == "$compl_func" ]]; then - compl_wrapper="_${namespace}::${alias_name}" + compl_func="${new_completion/#* -F /}" + compl_func="${compl_func%% *}" + # avoid recursive call loops by ignoring our own functions + if [[ "${compl_func#_"$namespace"::}" == "$compl_func" ]]; then + compl_wrapper="_${namespace}::${alias_name}" + + if [[ -z $alias_args ]]; then + # Create a wrapper without arguments. + # This allows identifying the completions added by this script on reload. + echo "function $compl_wrapper { + $compl_func \"\$@\" + }" >> "$tmp_file" + else + # Create a wrapper inserting the alias arguments + # The use of printf on alias_arg_words is needed to ensure each element of + # the array is quoted. E.X. (one two three) -> ('one' 'two' 'three') echo "function $compl_wrapper { local compl_word=\${2?} local prec_word=\${3?} @@ -89,14 +116,14 @@ function _bash-it-component-completion-callback-on-init-aliases() { prec_word=\${prec_word#* } fi (( COMP_CWORD += ${#alias_arg_words[@]} )) - COMP_WORDS=(\"$alias_cmd\" \"${alias_arg_words[*]}\" \"\${COMP_WORDS[@]:1}\") + COMP_WORDS=(\"$alias_cmd\" $(printf "%q " "${alias_arg_words[@]}") \"\${COMP_WORDS[@]:1}\") (( COMP_POINT -= \${#COMP_LINE} )) COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args} (( COMP_POINT += \${#COMP_LINE} )) \"$compl_func\" \"$alias_cmd\" \"\$compl_word\" \"\$prec_word\" }" >> "$tmp_file" - new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }" fi + new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }" fi # replace completion trigger by alias diff --git a/completion/available/apm.completion.bash b/completion/available/apm.completion.bash index c3dcfe45f8..9737938f24 100644 --- a/completion/available/apm.completion.bash +++ b/completion/available/apm.completion.bash @@ -1,4 +1,4 @@ # shellcheck shell=bash about-completion "apm completion" -# shellcheck disable=SC1090 -source "${BASH_IT}"/vendor/github.com/vigo/apm-bash-completion/apm +# shellcheck source-path=SCRIPTDIR/../../vendor/github.com/vigo/apm-bash-completion +source "${BASH_IT?}/vendor/github.com/vigo/apm-bash-completion/apm" diff --git a/completion/available/artisan.completion.bash b/completion/available/artisan.completion.bash new file mode 100644 index 0000000000..a894f878fb --- /dev/null +++ b/completion/available/artisan.completion.bash @@ -0,0 +1,27 @@ +# shellcheck shell=bash +cite "about-completion" +about-completion "Laravel artisan completion" + +# Completion function for Laravel artisan +_artisan_completion() { + local cur artisan_commands + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + + # Only provide completions if artisan file exists in current directory + if [[ ! -f "artisan" ]]; then + return 0 + fi + + # Get list of available artisan commands + # Use command prefix to bypass user aliases + # shellcheck disable=SC2034 + artisan_commands=$(command php artisan --raw --no-ansi list 2> /dev/null | command sed "s/[[:space:]].*//") + + # shellcheck disable=SC2016,SC2207 + COMPREPLY=($(compgen -W '${artisan_commands}' -- "${cur}")) + return 0 +} + +# Complete for both 'artisan' and common alias 'art' +complete -F _artisan_completion artisan art diff --git a/completion/available/awless.completion.bash b/completion/available/awless.completion.bash index 98a5d38881..9d175e7502 100644 --- a/completion/available/awless.completion.bash +++ b/completion/available/awless.completion.bash @@ -1,5 +1,10 @@ # shellcheck shell=bash -if _command_exists awless; then - # shellcheck disable=SC1090 - source <(awless completion bash) -fi + +# Make sure awless is installed +_bash-it-completion-helper-necessary awless || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient awless || return + +# shellcheck disable=SC1090 +source <(awless completion bash) diff --git a/completion/available/awscli.completion.bash b/completion/available/awscli.completion.bash index 6b2c90ff5d..bb5bd6b0d5 100644 --- a/completion/available/awscli.completion.bash +++ b/completion/available/awscli.completion.bash @@ -1,5 +1,9 @@ # shellcheck shell=bash -if _command_exists aws_completer; then - complete -C "$(command -v aws_completer)" aws -fi +# Make sure aws is installed +_bash-it-completion-helper-necessary aws aws_completer || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient aws || return + +complete -C aws_completer aws diff --git a/completion/available/cargo.completion.bash b/completion/available/cargo.completion.bash index d276ee7298..d40d4d4948 100644 --- a/completion/available/cargo.completion.bash +++ b/completion/available/cargo.completion.bash @@ -1,6 +1,10 @@ # shellcheck shell=bash -# cargo (Rust package manager) completion +about-completion "cargo (Rust package manager) completion" -if _binary_exists rustup && _binary_exists cargo; then - eval "$(rustup completions bash cargo)" -fi +# Make sure cargo is installed +_bash-it-completion-helper-necessary rustup cargo || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient cargo || return + +eval "$(rustup completions bash cargo)" diff --git a/completion/available/conda.completion.bash b/completion/available/conda.completion.bash index f5a61e5907..84399caec3 100644 --- a/completion/available/conda.completion.bash +++ b/completion/available/conda.completion.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite "about-completion" about-completion "conda completion" if _command_exists conda; then diff --git a/completion/available/consul.completion.bash b/completion/available/consul.completion.bash index 511cf37209..2fbc6c6941 100644 --- a/completion/available/consul.completion.bash +++ b/completion/available/consul.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "Hashicorp consul completion" -if _command_exists consul; then - complete -C "$(command -v consul)" consul -fi +# Make sure consul is installed +_bash-it-completion-helper-necessary consul || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient consul || return + +complete -C consul consul diff --git a/completion/available/crystal.completion.bash b/completion/available/crystal.completion.bash index 7644ffd4d4..950459aa71 100644 --- a/completion/available/crystal.completion.bash +++ b/completion/available/crystal.completion.bash @@ -1 +1,4 @@ -_log_warning 'Bash completion for "crystal" is now covered by "system". This completion can be disabled.' +# shellcheck shell=bash + +_log_warning 'Bash completion for "crystal" is now covered by "system".' +_disable-completion "crystal" diff --git a/completion/available/defaults.completion.bash b/completion/available/defaults.completion.bash index 39d7ea95b0..952c744abe 100644 --- a/completion/available/defaults.completion.bash +++ b/completion/available/defaults.completion.bash @@ -1,5 +1,7 @@ # shellcheck shell=bash +# shellcheck disable=SC1090 -if test -s "${BASH_IT?}/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash"; then - source "$_" +if [[ -s "${BASH_IT?}/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash" ]]; then + # shellcheck source-path=SCRIPTDIR/../../vendor/github.com/gaelicWizard/bash-progcomp + source "${BASH_IT?}/vendor/github.com/gaelicWizard/bash-progcomp/defaults.completion.bash" fi diff --git a/completion/available/dirs.completion.bash b/completion/available/dirs.completion.bash index c6e01155d6..187de36119 100644 --- a/completion/available/dirs.completion.bash +++ b/completion/available/dirs.completion.bash @@ -1,16 +1,13 @@ # shellcheck shell=bash -# Bash completion support for the 'dirs' plugin (commands G, R). +about-completion "Bash completion support for the 'dirs' plugin (commands G, R)." -_dirs-complete() { - local CURRENT_PROMPT="${COMP_WORDS[COMP_CWORD]}" - - # parse all defined shortcuts from ~/.dirs - if [ -r "$HOME/.dirs" ]; then - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "$(grep -v '^#' ~/.dirs | sed -e 's/\(.*\)=.*/\1/')" -- "${CURRENT_PROMPT}")) +function _dirs-complete() { + # parse all defined shortcuts ${BASH_IT_DIRS_BKS} + if [[ -s "${BASH_IT_DIRS_BKS:-/dev/null}" ]]; then + IFS=$'\n' read -d '' -ra COMPREPLY < <(grep -v '^#' "${BASH_IT_DIRS_BKS?}" | sed -e 's/\(.*\)=.*/\1/') fi return 0 } -complete -o default -o nospace -F _dirs-complete G R +complete -o default -o nospace -F _dirs-complete -X '!&*' G R diff --git a/completion/available/dmidecode.completion.bash b/completion/available/dmidecode.completion.bash index 4a8845244e..eacfee81fe 100644 --- a/completion/available/dmidecode.completion.bash +++ b/completion/available/dmidecode.completion.bash @@ -1,22 +1,25 @@ # shellcheck shell=bash -function __dmidecode_completion() { - # shellcheck disable=SC2155 - local prev=$(_get_pword) - # shellcheck disable=SC2155 - local curr=$(_get_cword) +# Make sure dmidecode is installed +_bash-it-completion-helper-necessary dmidecode || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient dmidecode || return + +function _dmidecode() { + local prev="${COMP_WORDS[COMP_CWORD - 1]}" case $prev in -s | --string | -t | --type) OPTS=$(dmidecode "$prev" 2>&1 | grep -E '^ ' | sed 's/ *//g') # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "$OPTS" -- "$curr")) + COMPREPLY=("${OPTS[@]}") ;; dmidecode) # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-d --dev-mem -h --help -q --quiet -s --string -t --type -H --handle -u --dump{,-bin} --from-dump --no-sysfs --oem-string -V --version" -- "$curr")) + COMPREPLY=("-d" "--dev-mem" "-h" "--help" "-q" "--quiet" "-s" "--string" "-t" "--type" "-H" "--handle" "-u" "--dump" "-dump-bin" "--from-dump" "--no-sysfs" "--oem-string" "-V" "--version") ;; esac } -complete -F __dmidecode_completion dmidecode +complete -F _dmidecode -X '!&*' dmidecode diff --git a/completion/available/docker.completion.bash b/completion/available/docker.completion.bash index 3f83a87461..b23be80e4b 100644 --- a/completion/available/docker.completion.bash +++ b/completion/available/docker.completion.bash @@ -1,24 +1,32 @@ # shellcheck shell=bash -cite "about-completion" about-completion "docker completion" # Make sure docker is installed -_command_exists docker || return +_bash-it-completion-helper-necessary docker || : # Don't handle completion if it's already managed -_completion_exists docker && return +_bash-it-completion-helper-sufficient docker || return _docker_bash_completion_paths=( - # MacOS + # MacOS App '/Applications/Docker.app/Contents/Resources/etc/docker.bash-completion' - # Linux + # Command Line '/usr/share/bash-completion/completions/docker' ) -for fn in "${_docker_bash_completion_paths[@]}"; do - if [ -r "$fn" ]; then +# Load the first completion file found +_docker_bash_completion_found=false +for _comp_path in "${_docker_bash_completion_paths[@]}"; do + if [[ -r "$_comp_path" ]]; then + _docker_bash_completion_found=true # shellcheck disable=SC1090 - source "$fn" + source "$_comp_path" break fi done + +# Cleanup +if [[ "${_docker_bash_completion_found}" == false ]]; then + _log_warning "no completion files found - please try enabling the 'system' completion instead." +fi +unset "${!_docker_bash_completion@}" diff --git a/completion/available/drush.completion.bash b/completion/available/drush.completion.bash index 6628c65513..2c6fef8189 100644 --- a/completion/available/drush.completion.bash +++ b/completion/available/drush.completion.bash @@ -1,2 +1,4 @@ +# shellcheck shell=bash _log_warning 'Bash completion for "drush" is now deprecated, as it used code with incompatible license. Please disable this completion and use the instructions from "drush" developers instead.' +_disable-completion "drush" diff --git a/completion/available/export.completion.bash b/completion/available/export.completion.bash index 4898eb9a01..361ead75b6 100644 --- a/completion/available/export.completion.bash +++ b/completion/available/export.completion.bash @@ -1,3 +1,4 @@ # shellcheck shell=bash -complete -o nospace -S = -W "$(printenv | awk -F= "{print \$1}")" export +_log_warning 'Bash completion for "export" is now covered by "system".' +_disable-completion "export" diff --git a/completion/available/fabric.completion.bash b/completion/available/fabric.completion.bash index 163a479b80..717fb4badd 100644 --- a/completion/available/fabric.completion.bash +++ b/completion/available/fabric.completion.bash @@ -41,10 +41,10 @@ export FAB_COMPLETION_CACHED_TASKS_FILENAME=".fab_tasks~" # Set command to get time of last file modification as seconds since Epoch case "$OSTYPE" in 'darwin'* | 'freebsd'*) - __FAB_COMPLETION_MTIME_COMMAND="stat -f '%m'" + __FAB_COMPLETION_MTIME_COMMAND=(stat -f '%m') ;; *) - __FAB_COMPLETION_MTIME_COMMAND="stat -c '%Y'" + __FAB_COMPLETION_MTIME_COMMAND=(stat -c '%Y') ;; esac @@ -52,7 +52,7 @@ esac # Get time of last fab cache file modification as seconds since Epoch # function __fab_chache_mtime() { - ${__FAB_COMPLETION_MTIME_COMMAND} \ + "${__FAB_COMPLETION_MTIME_COMMAND[@]}" \ $FAB_COMPLETION_CACHED_TASKS_FILENAME | xargs -n 1 expr } @@ -62,10 +62,11 @@ function __fab_chache_mtime() { function __fab_fabfile_mtime() { local f="fabfile" if [[ -e "$f.py" ]]; then - ${__FAB_COMPLETION_MTIME_COMMAND} "$f.py" | xargs -n 1 expr + "${__FAB_COMPLETION_MTIME_COMMAND[@]}" "$f.py" | xargs -n 1 expr else # Suppose that it's a fabfile dir - find $f/*.py -exec ${__FAB_COMPLETION_MTIME_COMMAND} {} + \ + # shellcheck disable=SC2038 + find "$f"/*.py -exec "${__FAB_COMPLETION_MTIME_COMMAND[@]}" {} + \ | xargs -n 1 expr | sort -n -r | head -1 fi } @@ -79,15 +80,16 @@ function __fab_completion() { # Variables to hold the current word and possible matches local cur="${COMP_WORDS[COMP_CWORD]}" - local opts=() + local opts # Generate possible matches and store them in variable "opts" case "${cur}" in -*) if [[ -z "${__FAB_COMPLETION_LONG_OPT}" ]]; then - export __FAB_COMPLETION_LONG_OPT=$( + __FAB_COMPLETION_LONG_OPT=$( fab --help | grep -E -o "\-\-[A-Za-z_\-]+\=?" | sort -u ) + export __FAB_COMPLETION_LONG_OPT fi opts="${__FAB_COMPLETION_LONG_OPT}" ;; @@ -124,6 +126,7 @@ function __fab_completion() { esac # Set possible completions - COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${opts}" -- "${cur}") } complete -o default -o nospace -F __fab_completion fab diff --git a/completion/available/flutter.completion.bash b/completion/available/flutter.completion.bash index 7dde5a0709..cc965b579e 100644 --- a/completion/available/flutter.completion.bash +++ b/completion/available/flutter.completion.bash @@ -1,5 +1,9 @@ # shellcheck shell=bash -if _command_exists flutter; then - eval "$(flutter bash-completion)" -fi +# Make sure flutter is installed +_bash-it-completion-helper-necessary flutter || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient flutter || return + +eval "$(flutter bash-completion)" diff --git a/completion/available/gcloud.completion.bash b/completion/available/gcloud.completion.bash index 63073e8ed3..514d8b4c3d 100644 --- a/completion/available/gcloud.completion.bash +++ b/completion/available/gcloud.completion.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite "about-completion" about-completion "Google Cloud SDK completion" if _command_exists gcloud; then diff --git a/completion/available/git.completion.bash b/completion/available/git.completion.bash index 31b77fa3de..d9fe014c91 100644 --- a/completion/available/git.completion.bash +++ b/completion/available/git.completion.bash @@ -3,13 +3,10 @@ # Locate and load completions for `git`. # Make sure git is installed -_command_exists git || return +_bash-it-completion-helper-necessary git || : # Don't handle completion if it's already managed -if complete -p git &> /dev/null; then - _log_warning "completion already loaded - this usually means it is safe to stop using this completion" - return 0 -fi +_bash-it-completion-helper-sufficient git || return _git_bash_completion_xcrun_git= if _command_exists xcrun; then diff --git a/completion/available/github-cli.completion.bash b/completion/available/github-cli.completion.bash index 4a6113945c..0888c6c5eb 100644 --- a/completion/available/github-cli.completion.bash +++ b/completion/available/github-cli.completion.bash @@ -1,9 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "GitHub CLI completion" -if _binary_exists gh; then - # If gh already completed, stop - _completion_exists gh && return - eval "$(gh completion --shell=bash)" -fi +# Make sure gh is installed +_bash-it-completion-helper-necessary gh || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient gh || return + +eval "$(gh completion --shell=bash)" diff --git a/completion/available/gradle.completion.bash b/completion/available/gradle.completion.bash index cedf15dc71..e78a604036 100644 --- a/completion/available/gradle.completion.bash +++ b/completion/available/gradle.completion.bash @@ -22,7 +22,7 @@ # Bash breaks words on : by default. Subproject tasks have ':' # Avoid inaccurate completions for subproject tasks -COMP_WORDBREAKS=$(echo "$COMP_WORDBREAKS" | sed -e 's/://g') +COMP_WORDBREAKS="${COMP_WORDBREAKS//:/}" function __gradle-set-project-root-dir() { project_root_dir="$(_bash-it-find-in-ancestor "settings.gradle" "gradlew")" @@ -31,7 +31,7 @@ function __gradle-set-project-root-dir() { __gradle-init-cache-dir() { cache_dir="$HOME/.gradle/completion" - mkdir -p $cache_dir + mkdir -p "$cache_dir" } __gradle-set-build-file() { @@ -39,7 +39,8 @@ __gradle-set-build-file() { # Otherwise, default is the file 'build.gradle' in the current directory. gradle_build_file="$project_root_dir/build.gradle" if [[ -f "$project_root_dir/settings.gradle" ]]; then - local build_file_name=$(grep "^rootProject\.buildFileName" "$project_root_dir/settings.gradle" \ + local build_file_name + build_file_name=$(grep "^rootProject\.buildFileName" "$project_root_dir/settings.gradle" \ | sed -n -e "s/rootProject\.buildFileName = [\'\"]\(.*\)[\'\"]/\1/p") gradle_build_file="$project_root_dir/${build_file_name:-build.gradle}" fi @@ -47,15 +48,15 @@ __gradle-set-build-file() { __gradle-set-cache-name() { # Cache name is constructed from the absolute path of the build file. - cache_name=$(echo $gradle_build_file | sed -e 's/\//_/g') + cache_name=${gradle_build_file//"/"/_} } __gradle-set-files-checksum() { # Cache MD5 sum of all Gradle scripts and modified timestamps if _command_exists md5; then - gradle_files_checksum=$(md5 -q -s "$(cat "$cache_dir/$cache_name" | xargs ls -o 2> /dev/null)") + gradle_files_checksum=$(md5 -q -s "$(xargs ls -o < "$cache_dir/$cache_name" 2> /dev/null)") elif _command_exists md5sum; then - gradle_files_checksum=$(cat "$cache_dir/$cache_name" | xargs ls -o 2> /dev/null | md5sum | awk '{print $1}') + gradle_files_checksum=$(xargs ls -o < "$cache_dir/$cache_name" 2> /dev/null | md5sum | awk '{print $1}') else echo "Cannot generate completions as neither md5 nor md5sum exist on \$PATH" fi @@ -66,10 +67,15 @@ __gradle-generate-script-cache() { local cache_ttl_mins=${GRADLE_CACHE_TTL_MINUTES:-30240} local script_exclude_pattern=${GRADLE_COMPLETION_EXCLUDE_PATTERN:-"/(build|integTest|out)/"} - if [[ ! $(find $cache_dir/$cache_name -mmin -$cache_ttl_mins 2> /dev/null) ]]; then + if [[ ! $(find "$cache_dir/$cache_name" -mmin "-$cache_ttl_mins" 2> /dev/null) ]]; then # Cache all Gradle scripts - local gradle_build_scripts=$(find $project_root_dir -type f -name "*.gradle" -o -name "*.gradle.kts" 2> /dev/null | grep -E -v "$script_exclude_pattern") - printf "%s\n" "${gradle_build_scripts[@]}" > $cache_dir/$cache_name + local gradle_build_scripts + gradle_build_scripts=$( + find "$project_root_dir" -type f \ + \( -name "*.gradle" -o -name "*.gradle.kts" \) 2> /dev/null \ + | grep -E -v "$script_exclude_pattern" + ) + printf "%s\n" "${gradle_build_scripts[@]}" > "$cache_dir/$cache_name" fi } @@ -115,7 +121,10 @@ __gradle-long-options() { --system-prop - Set a system property --version - Prints Gradle version info --warn - Log warnings and errors only" - COMPREPLY=($(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}")) + COMPREPLY=() + while IFS='' read -r line; do + COMPREPLY+=("$line") + done < <(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") } __gradle-properties() { @@ -130,7 +139,10 @@ __gradle-properties() { -Dorg.gradle.parallel= - Set true to enable parallel project builds (incubating) -Dorg.gradle.parallel.intra= - Set true to enable intra-project parallel builds (incubating) -Dorg.gradle.workers.max= - Set the number of workers Gradle is allowed to use" - COMPREPLY=($(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}")) + COMPREPLY=() + while IFS='' read -r line; do + COMPREPLY+=("$line") + done < <(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") return 0 } @@ -156,7 +168,8 @@ __gradle-short-options() { -I - Specifies an initialization script -P - Sets a project property of the root project -S - Print out the full (very verbose) stacktrace" - COMPREPLY=($(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}")) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") } __gradle-notify-tasks-cache-build() { @@ -179,10 +192,10 @@ __gradle-generate-tasks-cache() { # Run gradle to retrieve possible tasks and cache. # Reuse Gradle Daemon if IDLE but don't start a new one. local gradle_tasks_output - if [[ ! -z "$($gradle_cmd --status 2> /dev/null | grep IDLE)" ]]; then - gradle_tasks_output="$($gradle_cmd -b $gradle_build_file --daemon -q tasks --all)" + if "$gradle_cmd" --status 2> /dev/null | grep -q IDLE; then + gradle_tasks_output="$("$gradle_cmd" -b "$gradle_build_file" --daemon -q tasks --all)" else - gradle_tasks_output="$($gradle_cmd -b $gradle_build_file --no-daemon -q tasks --all)" + gradle_tasks_output="$("$gradle_cmd" -b "$gradle_build_file" --no-daemon -q tasks --all)" fi local output_line local task_description @@ -206,15 +219,18 @@ __gradle-generate-tasks-cache() { # subproject tasks can be referenced implicitly from root project if [[ $GRADLE_COMPLETION_UNQUALIFIED_TASKS == "true" ]]; then - local -a implicit_tasks=() - implicit_tasks=($(comm -23 <(printf "%s\n" "${subproject_tasks[@]}" | sort) <(printf "%s\n" "${root_tasks[@]}" | sort))) - for task in $(printf "%s\n" "${implicit_tasks[@]}"); do - gradle_all_tasks+=($task) + local -a implicit_tasks + while IFS='' read -r line; do + implicit_tasks+=("$line") + done < <(comm -23 <(printf "%s\n" "${subproject_tasks[@]}" | sort) \ + <(printf "%s\n" "${root_tasks[@]}" | sort)) + for task in "${implicit_tasks[@]}"; do + gradle_all_tasks+=("$task") done fi - printf "%s\n" "${gradle_all_tasks[@]}" > $cache_dir/$gradle_files_checksum - echo $gradle_files_checksum > $cache_dir/$cache_name.md5 + printf "%s\n" "${gradle_all_tasks[@]}" > "$cache_dir/$gradle_files_checksum" + echo "$gradle_files_checksum" > "$cache_dir/$cache_name.md5" } __gradle-completion-init() { @@ -262,22 +278,30 @@ _gradle() { __gradle-set-files-checksum # The cache key is md5 sum of all gradle scripts, so it's valid if it exists. - if [[ -f $cache_dir/$cache_name.md5 ]]; then - local cached_checksum="$(cat $cache_dir/$cache_name.md5)" + if [[ -f "$cache_dir/$cache_name.md5" ]]; then + local cached_checksum + cached_checksum="$(cat "$cache_dir/$cache_name.md5")" local -a cached_tasks if [[ -z $cur ]]; then - cached_tasks=($(cat $cache_dir/$cached_checksum)) + while IFS='' read -r line; do + cached_tasks+=("$line") + done < "$cache_dir/$cached_checksum" else - cached_tasks=($(grep "^$cur" $cache_dir/$cached_checksum)) + while IFS='' read -r line; do + cached_tasks+=("$line") + done < <(grep "^$cur" "$cache_dir/$cached_checksum") fi - COMPREPLY=($(compgen -W "${cached_tasks[*]}" -- "$cur")) + while IFS='' read -r line; do + COMPREPLY+=("$line") + done < <(compgen -W "${cached_tasks[*]}" -- "$cur") else __gradle-notify-tasks-cache-build fi # Regenerate tasks cache in the background - if [[ $gradle_files_checksum != "$(cat $cache_dir/$cache_name.md5)" || ! -f $cache_dir/$gradle_files_checksum ]]; then - $(__gradle-generate-tasks-cache 1>&2 2> /dev/null &) + if [[ $gradle_files_checksum != "$(cat "$cache_dir/$cache_name.md5")" || + ! -f "$cache_dir/$gradle_files_checksum" ]]; then + (__gradle-generate-tasks-cache &> /dev/null &) fi else # Default tasks available outside Gradle projects @@ -293,7 +317,10 @@ projects - Displays the sub-projects of root project. properties - Displays the properties of root project. tasks - Displays the tasks runnable from root project. wrapper - Generates Gradle wrapper files." - COMPREPLY=($(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}")) + COMPREPLY=() + while IFS='' read -r line; do + COMPREPLY+=("$line") + done < <(compgen -W "${args}" -- "${cur}") fi fi @@ -301,7 +328,7 @@ wrapper - Generates Gradle wrapper files." # Remove description ("[:space:]" and after) if only one possibility if [[ ${#COMPREPLY[*]} -eq 1 ]]; then - COMPREPLY=(${COMPREPLY[0]%% *}) + COMPREPLY=("${COMPREPLY[0]%% *}") fi return 0 diff --git a/completion/available/helm.completion.bash b/completion/available/helm.completion.bash index 0dae7af46b..d11b4c305b 100644 --- a/completion/available/helm.completion.bash +++ b/completion/available/helm.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "helm (Kubernetes Package Manager) completion" -if _command_exists helm; then - eval "$(helm completion bash)" -fi +# Make sure helm is installed +_bash-it-completion-helper-necessary helm || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient helm || return + +eval "$(helm completion bash)" diff --git a/completion/available/homesick.completion.bash b/completion/available/homesick.completion.bash index ed6f6e79ed..9fbb991313 100644 --- a/completion/available/homesick.completion.bash +++ b/completion/available/homesick.completion.bash @@ -1,2 +1,4 @@ +# shellcheck shell=bash _log_warning 'Bash completion for "homesick" is now deprecated, as it used unlicensed code. Please disable this completion and use the instructions from "homesick" bash completion developers instead.' +_disable-completion "homesick" diff --git a/completion/available/jungle.completion.bash b/completion/available/jungle.completion.bash index e190d1438a..60aa398920 100644 --- a/completion/available/jungle.completion.bash +++ b/completion/available/jungle.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "jungle(AWS cli tool) completion" -if _command_exists jungle; then - eval "$(_JUNGLE_COMPLETE=source jungle)" -fi +# Make sure jungle is installed +_bash-it-completion-helper-necessary jungle || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient jungle || return + +eval "$(_JUNGLE_COMPLETE=source jungle)" diff --git a/completion/available/kind.completion.bash b/completion/available/kind.completion.bash index dcae12b5ad..8530dcd454 100644 --- a/completion/available/kind.completion.bash +++ b/completion/available/kind.completion.bash @@ -1,5 +1,9 @@ # shellcheck shell=bash -if _command_exists kind; then - eval "$(kind completion bash)" -fi +# Make sure kind is installed +_bash-it-completion-helper-necessary kind || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient kind || return + +eval "$(kind completion bash)" diff --git a/completion/available/kontena.completion.bash b/completion/available/kontena.completion.bash index 916ee15f92..08f6ef634b 100644 --- a/completion/available/kontena.completion.bash +++ b/completion/available/kontena.completion.bash @@ -1,5 +1,10 @@ # shellcheck shell=bash -if _command_exists kontena; then - # shellcheck disable=SC1090 - source "$(kontena whoami --bash-completion-path)" -fi + +# Make sure kontena is installed +_bash-it-completion-helper-necessary kontena || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient kontena || return + +# shellcheck disable=SC1090 +source "$(kontena whoami --bash-completion-path)" diff --git a/completion/available/kubectl.completion.bash b/completion/available/kubectl.completion.bash index a9c498b601..f3d9ec5a94 100644 --- a/completion/available/kubectl.completion.bash +++ b/completion/available/kubectl.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "kubectl (Kubernetes CLI) completion" -if _binary_exists kubectl; then - eval "$(kubectl completion bash)" -fi +# Make sure kubectl is installed +_bash-it-completion-helper-necessary kubectl || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient kubectl || return + +eval "$(kubectl completion bash)" diff --git a/completion/available/laravel.completion.bash b/completion/available/laravel.completion.bash index 8f03256896..63693fe257 100644 --- a/completion/available/laravel.completion.bash +++ b/completion/available/laravel.completion.bash @@ -1,6 +1,10 @@ # shellcheck shell=bash -_command_exists laravel || return +# Make sure laravel is installed +_bash-it-completion-helper-necessary laravel || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient laravel || return function __laravel_completion() { local OPTS=('-h' '--help' '-q' '--quiet' '--ansi' '--no-ansi' '-n' '--no-interaction' '-v' '-vv' '-vvv' '--verbose' 'help' 'list' 'new') diff --git a/completion/available/makefile.completion.bash b/completion/available/makefile.completion.bash index 4b36402efc..b518bb5793 100644 --- a/completion/available/makefile.completion.bash +++ b/completion/available/makefile.completion.bash @@ -3,31 +3,31 @@ # Bash completion for Makefile # Loosely adapted from http://stackoverflow.com/a/38415982/1472048 -_makecomplete() { +function _makecomplete() { + local cur="${COMP_WORDS[COMP_CWORD]}" + local files=() targets=() line f COMPREPLY=() # https://www.gnu.org/software/make/manual/html_node/Makefile-Names.html - local files=() for f in 'GNUmakefile' 'makefile' 'Makefile'; do - [ -f "$f" ] && files+=("$f") + [[ -f "$f" ]] && files+=("$f") done - [ "${#files[@]}" -eq 0 ] && return 0 + [[ "${#files[@]}" -eq 0 ]] && return 0 # collect all targets - local targets=() for f in "${files[@]}"; do while IFS='' read -r line; do targets+=("$line") - done < <(grep -E -o '^[a-zA-Z0-9_-]+:([^=]|$)' "$f" | cut -d':' -f1) + done < <(grep -oE '^[a-zA-Z0-9_-]+:([^=]|$)' "$f" | cut -d':' -f1) done - [ "${#targets[@]}" -eq 0 ] && return 0 + [[ "${#targets[@]}" -eq 0 ]] && return 0 # use the targets for completion while IFS='' read -r line; do COMPREPLY+=("$line") - done < <(compgen -W "$(tr ' ' '\n' <<< "${targets[@]}" | sort -u)" -- "${COMP_WORDS[COMP_CWORD]}") + done < <(compgen -W "$(tr ' ' '\n' <<< "${targets[@]}" | sort -u)" -- "${cur}") return 0 } diff --git a/completion/available/maven.completion.bash b/completion/available/maven.completion.bash index 54c28c4d2a..780fed3161 100644 --- a/completion/available/maven.completion.bash +++ b/completion/available/maven.completion.bash @@ -28,7 +28,7 @@ _mvn() { COMPREPLY=($(compgen -W "$cmds" -- "$cur")) local i=${#COMPREPLY[*]} while [ "$((--i))" -ge 0 ]; do - COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} + COMPREPLY[i]=${COMPREPLY[i]#"$colonprefixes"} done return 0 diff --git a/completion/available/minikube.completion.bash b/completion/available/minikube.completion.bash index 44076362ce..c73a4da44f 100644 --- a/completion/available/minikube.completion.bash +++ b/completion/available/minikube.completion.bash @@ -1,6 +1,10 @@ # shellcheck shell=bash -# minikube (Local Kubernetes) completion +about-completion "minikube (Local Kubernetes) completion" -if _command_exists minikube; then - eval "$(minikube completion bash)" -fi +# Make sure minikube is installed +_bash-it-completion-helper-necessary minikube || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient minikube || return + +eval "$(minikube completion bash)" diff --git a/completion/available/minishift.completion.bash b/completion/available/minishift.completion.bash index 5679eae80f..dc872bc1bd 100644 --- a/completion/available/minishift.completion.bash +++ b/completion/available/minishift.completion.bash @@ -1 +1,10 @@ -_command_exists minishift && source <(minishift completion bash) +# shellcheck shell=bash + +# Make sure minishift is installed +_bash-it-completion-helper-necessary minishift || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient minishift || return + +# shellcheck disable=SC1090 +source <(minishift completion bash) diff --git a/completion/available/ng.completion.bash b/completion/available/ng.completion.bash index af2e8374f3..cba49c3b31 100644 --- a/completion/available/ng.completion.bash +++ b/completion/available/ng.completion.bash @@ -1,9 +1,15 @@ # shellcheck shell=bash -if _command_exists ng; then - # No longer supported, please see https://github.com/angular/angular-cli/issues/11043 - # Fix courtesy of https://stackoverflow.com/questions/50194674/ng-completion-no-longer-exists - # . <(ng completion --bash) - - NG_COMMANDS="add build config doc e2e generate help lint new run serve test update version xi18n" - complete -W "$NG_COMMANDS" ng -fi + +# Make sure ng is installed +_bash-it-completion-helper-necessary ng || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient ng || return + +# No longer supported, please see https://github.com/angular/angular-cli/issues/11043 +# Fix courtesy of https://stackoverflow.com/questions/50194674/ng-completion-no-longer-exists +# source <(ng completion --bash) + +_ng_bash_completion_candidates=("add" "build" "config" "doc" "e2e" "generate" "help" "lint" "new" "run" "serve" "test" "update" "version" "xi18n") +complete -W "${_ng_bash_completion_candidates[*]}" ng +unset "${!_ng_bash_completion@}" diff --git a/completion/available/notify-send.completion.bash b/completion/available/notify-send.completion.bash index 676485f83a..4745b2abee 100644 --- a/completion/available/notify-send.completion.bash +++ b/completion/available/notify-send.completion.bash @@ -1,21 +1,22 @@ # shellcheck shell=bash -function __notify-send_completions() { - # shellcheck disable=SC2155 - local curr=$(_get_cword) - # shellcheck disable=SC2155 - local prev=$(_get_pword) +# Make sure notify-send is installed +_bash-it-completion-helper-necessary notify-send || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient notify-send || return + +function _notify-send() { + local prev="${COMP_WORDS[COMP_CWORD - 1]}" case $prev in -u | --urgency) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "low normal critical" -- "$curr")) + COMPREPLY=("low" "normal" "critical") ;; *) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-? --help -u --urgency -t --expire-time -a --app-name -i --icon -c --category -h --hint -v --version" -- "$curr")) + COMPREPLY=("-?" "--help" "-u" "--urgency" "-t" "--expire-time" "-a" "--app-name" "-i" "--icon" "-c" "--category" "-h" "--hint" "-v" "--version") ;; esac } -complete -F __notify-send_completions notify-send +complete -F _notify-send -X '!&*' notify-send diff --git a/completion/available/npm.completion.bash b/completion/available/npm.completion.bash index cf24585ef7..3ceb620252 100644 --- a/completion/available/npm.completion.bash +++ b/completion/available/npm.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "npm (Node Package Manager) completion" -if _command_exists npm; then - eval "$(npm completion)" -fi +# Make sure npm is installed +_bash-it-completion-helper-necessary npm || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient npm || return + +eval "$(npm completion)" diff --git a/completion/available/nvm.completion.bash b/completion/available/nvm.completion.bash index 28a8eea516..9126f4d68b 100644 --- a/completion/available/nvm.completion.bash +++ b/completion/available/nvm.completion.bash @@ -1,7 +1,7 @@ # shellcheck shell=bash +about-completion "nvm (Node Version Manager) completion" -# nvm (Node Version Manager) completion - -if [ "$NVM_DIR" ] && [ -r "$NVM_DIR"/bash_completion ]; then - . "$NVM_DIR"/bash_completion +if [[ -n "${NVM_DIR:-}" && -s "${NVM_DIR}/bash_completion" ]]; then + # shellcheck disable=SC1091 + source "${NVM_DIR}/bash_completion" fi diff --git a/completion/available/openshift.completion.bash b/completion/available/openshift.completion.bash index 1e7b681506..5d0e2dcdc3 100644 --- a/completion/available/openshift.completion.bash +++ b/completion/available/openshift.completion.bash @@ -1 +1,10 @@ -_command_exists oc && source <(oc completion bash) +# shellcheck shell=bash + +# Make sure oc is installed +_bash-it-completion-helper-necessary oc || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient oc || return + +# shellcheck disable=SC1090 +source <(oc completion bash) diff --git a/completion/available/packer.completion.bash b/completion/available/packer.completion.bash index 2301f0f226..049e17ae34 100644 --- a/completion/available/packer.completion.bash +++ b/completion/available/packer.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "packer completion" -if _binary_exists packer; then - complete -C packer packer -fi +# Make sure packer is installed +_bash-it-completion-helper-necessary packer || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient packer || return + +complete -C packer packer diff --git a/completion/available/pew.completion.bash b/completion/available/pew.completion.bash index 24b133f9db..184cf363e2 100644 --- a/completion/available/pew.completion.bash +++ b/completion/available/pew.completion.bash @@ -1,5 +1,11 @@ # shellcheck shell=bash +# shellcheck disable=SC1090 -if _command_exists pew; then - source "$(pew shell_config)" -fi +# Make sure pew is installed +_bash-it-completion-helper-necessary pew || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient pew || return + +# shellcheck disable=SC1090 +source "$(pew shell_config)" diff --git a/completion/available/pipenv.completion.bash b/completion/available/pipenv.completion.bash index 4adfab9595..43cbe74e17 100644 --- a/completion/available/pipenv.completion.bash +++ b/completion/available/pipenv.completion.bash @@ -1,4 +1,9 @@ # shellcheck shell=bash -if _command_exists pipenv; then - eval "$(_PIPENV_COMPLETE=bash_source pipenv)" -fi + +# Make sure pipenv is installed +_bash-it-completion-helper-necessary pipenv || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient pipenv || return + +eval "$(_PIPENV_COMPLETE=bash_source pipenv)" diff --git a/completion/available/rustup.completion.bash b/completion/available/rustup.completion.bash index 1cf8bc95b4..1f1a38af2f 100644 --- a/completion/available/rustup.completion.bash +++ b/completion/available/rustup.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash +about-completion "rustup (Rust toolchain installer) completion" -# rustup (Rust toolchain installer) completion +# Make sure rustup is installed +_bash-it-completion-helper-necessary rustup || return -if _binary_exists rustup; then - eval "$(rustup completions bash)" -fi +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient rustup || return + +eval "$(rustup completions bash)" diff --git a/completion/available/rvm.completion.bash b/completion/available/rvm.completion.bash index cd8ded0468..9bea6ebb67 100644 --- a/completion/available/rvm.completion.bash +++ b/completion/available/rvm.completion.bash @@ -1,5 +1,8 @@ -#!/usr/bin/env bash -# Bash completion support for RVM. +# shellcheck shell=bash +about-completion "Bash completion support for RVM." # Source: https://rvm.io/workflow/completion -[[ -r $rvm_path/scripts/completion ]] && . $rvm_path/scripts/completion +if [[ -n "${rvm_path:-}" && -s "${rvm_path}/scripts/completion" ]]; then + # shellcheck disable=SC1091 + source "${rvm_path}/scripts/completion" +fi diff --git a/completion/available/ssh.completion.bash b/completion/available/ssh.completion.bash index 3252267fb0..dc3ac5b3dd 100644 --- a/completion/available/ssh.completion.bash +++ b/completion/available/ssh.completion.bash @@ -1,7 +1,8 @@ # shellcheck shell=bash # Bash completion support for ssh. -export COMP_WORDBREAKS=${COMP_WORDBREAKS/\:/} +# Remove : and @ from COMP_WORDBREAKS to support user@host completion +export COMP_WORDBREAKS=${COMP_WORDBREAKS//[:@]/} _sshcomplete() { local line CURRENT_PROMPT="${COMP_WORDS[COMP_CWORD]}" diff --git a/completion/available/svn.completion.bash b/completion/available/svn.completion.bash index 2f0a23fe97..8d24066caa 100644 --- a/completion/available/svn.completion.bash +++ b/completion/available/svn.completion.bash @@ -3,13 +3,10 @@ # Locate and load completions for `svn`. # Make sure svn is installed -_command_exists svn || return +_bash-it-completion-helper-necessary svn || : # Don't handle completion if it's already managed -if _completion_exists svn; then - _log_warning "completion already loaded - this usually means it is safe to stop using this completion" - return 0 -fi +_bash-it-completion-helper-sufficient svn || return _svn_bash_completion_xcrun_svn= if _command_exists xcrun; then diff --git a/completion/available/terraform.completion.bash b/completion/available/terraform.completion.bash index 3383a4f7e8..633f420e27 100644 --- a/completion/available/terraform.completion.bash +++ b/completion/available/terraform.completion.bash @@ -1,10 +1,28 @@ # shellcheck shell=bash +about-completion "terraform/tofu completion" -# Make sure terraform is installed -_command_exists terraform || return +# Note, this is not using the _bash-it-completion-helper-necessary function +# because it's a multiple choice case, and will therefore produce more +# sensible log messages. -# Don't handle completion if it's already managed -complete -p terraform &> /dev/null && return +# Check if at least one of the binaries is available (OR logic) +if ! _binary_exists terraform && ! _binary_exists tofu; then + _log_warning "Without 'terraform' or 'tofu' installed, this completion won't be too useful." + return 1 +fi -# Terraform completes itself -complete -C terraform terraform +# Handle terraform completion if available and not already managed +if _binary_exists terraform; then + _bash-it-completion-helper-sufficient terraform || { + # Terraform completes itself + complete -C terraform terraform + } +fi + +# Handle tofu completion if available and not already managed +if _binary_exists tofu; then + _bash-it-completion-helper-sufficient tofu || { + # OpenTofu completes itself + complete -C tofu tofu + } +fi diff --git a/completion/available/tmux.completion.bash b/completion/available/tmux.completion.bash index 674afaf70f..04ccfee61c 100644 --- a/completion/available/tmux.completion.bash +++ b/completion/available/tmux.completion.bash @@ -130,12 +130,13 @@ _tmux() { new-session | new) case "$prev" in -t) _tmux_complete_session "${cur}" ;; + -c) _tmux_filedir -d ;; -[n | d | s]) options="-d -n -s -t --" ;; *) if [[ ${COMP_WORDS[option_index]} == -- ]]; then _command_offset "${option_index}" else - options="-d -n -s -t --" + options="-d -n -s -t -c --" fi ;; esac diff --git a/completion/available/todo.completion.bash b/completion/available/todo.completion.bash index b5517d8654..c5ac4721d0 100644 --- a/completion/available/todo.completion.bash +++ b/completion/available/todo.completion.bash @@ -1,2 +1,4 @@ +# shellcheck shell=bash _log_warning 'Bash completion for "todo.txt-cli" is now deprecated, as it used code with incompatible license. Please disable this completion and use the instructions from "todo.txt-cli" developers instead.' +_disable-completion "todo" diff --git a/completion/available/travis.completion.bash b/completion/available/travis.completion.bash index f533cde037..85fc27c4cd 100644 --- a/completion/available/travis.completion.bash +++ b/completion/available/travis.completion.bash @@ -1,8 +1,14 @@ # shellcheck shell=bash +# shellcheck disable=SC1090 -if _command_exists travis; then - if [[ -s "${__TRAVIS_COMPLETION_SCRIPT:=${TRAVIS_CONFIG_PATH:-${HOME}/.travis}/travis.sh}" ]]; then - source "${__TRAVIS_COMPLETION_SCRIPT}" - fi - unset __TRAVIS_COMPLETION_SCRIPT +# Make sure travis is installed +_bash-it-completion-helper-necessary travis || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient travis || return + +if [[ -s "${_travis_bash_completion_script:=${TRAVIS_CONFIG_PATH:-${HOME}/.travis}/travis.sh}" ]]; then + # shellcheck disable=SC1090 + source "${_travis_bash_completion_script}" fi +unset "${!_travis_bash_completion@}" diff --git a/completion/available/vagrant.completion.bash b/completion/available/vagrant.completion.bash index 31a4ae1369..aadc18ab7e 100644 --- a/completion/available/vagrant.completion.bash +++ b/completion/available/vagrant.completion.bash @@ -1,4 +1,4 @@ -#!/bin/bash +# shellcheck shell=bash # (The MIT License) # @@ -26,21 +26,21 @@ __pwdln() { pwdmod="${PWD}/" itr=0 until [[ -z "$pwdmod" ]]; do - itr=$(($itr + 1)) + itr=$((itr + 1)) pwdmod="${pwdmod#*/}" done - echo -n $(($itr - 1)) + echo -n $((itr - 1)) } __vagrantinvestigate() { - if [ -f "${PWD}/.vagrant" -o -d "${PWD}/.vagrant" ]; then + if [ -f "${PWD}/.vagrant" ] || [ -d "${PWD}/.vagrant" ]; then echo "${PWD}/.vagrant" return 0 else pwdmod2="${PWD}" for ((i = 2; i <= $(__pwdln); i++)); do pwdmod2="${pwdmod2%/*}" - if [ -f "${pwdmod2}/.vagrant" -o -d "${pwdmod2}/.vagrant" ]; then + if [ -f "${pwdmod2}/.vagrant" ] || [ -d "${pwdmod2}/.vagrant" ]; then echo "${pwdmod2}/.vagrant" return 0 fi @@ -54,74 +54,86 @@ _vagrant() { prev="${COMP_WORDS[COMP_CWORD - 1]}" commands="box cloud destroy global-status halt help hostmanager init login package plugin port powershell provision push rdp reload resume scp snapshot ssh ssh-config status suspend up upload validate vbguest version winrm winrm-config" - if [ $COMP_CWORD == 1 ]; then - COMPREPLY=($(compgen -W "${commands}" -- ${cur})) + if ((COMP_CWORD == 1)); then + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${commands}" -- "${cur}") return 0 fi - if [ $COMP_CWORD == 2 ]; then + if ((COMP_CWORD == 2)); then case "$prev" in "init") - local box_list=$(find "$HOME/.vagrant.d/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed -e 's/-VAGRANTSLASH-/\//') - COMPREPLY=($(compgen -W "${box_list}" -- ${cur})) + local box_list + box_list=$(find "$HOME/.vagrant.d/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed -e 's/-VAGRANTSLASH-/\//') + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${box_list}" -- "${cur}") return 0 ;; "up") vagrant_state_file=$(__vagrantinvestigate) || return 1 if [[ -d $vagrant_state_file ]]; then - vm_list=$(find $vagrant_state_file/machines -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) + vm_list=$(find "$vagrant_state_file/machines" -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) fi local up_commands="--no-provision" - COMPREPLY=($(compgen -W "${up_commands} ${vm_list}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${up_commands} ${vm_list}" -- "${cur}") return 0 ;; "ssh" | "provision" | "reload" | "halt" | "suspend" | "resume" | "ssh-config") vagrant_state_file=$(__vagrantinvestigate) || return 1 if [[ -f $vagrant_state_file ]]; then - running_vm_list=$(grep 'active' $vagrant_state_file | sed -e 's/"active"://' | tr ',' '\n' | cut -d '"' -f 2 | tr '\n' ' ') + running_vm_list=$(grep 'active' "$vagrant_state_file" | sed -e 's/"active"://' | tr ',' '\n' | cut -d '"' -f 2 | tr '\n' ' ') else - running_vm_list=$(find $vagrant_state_file -type f -name "id" | awk -F"/" '{print $(NF-2)}') + running_vm_list=$(find "$vagrant_state_file" -type f -name "id" | awk -F"/" '{print $(NF-2)}') fi - COMPREPLY=($(compgen -W "${running_vm_list}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${running_vm_list}" -- "${cur}") return 0 ;; "box") box_commands="add list outdated prune remove repackage update" - COMPREPLY=($(compgen -W "${box_commands}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${box_commands}" -- "${cur}") return 0 ;; "plugin") plugin_commands="expunge install license list repair uninstall update" - COMPREPLY=($(compgen -W "${plugin_commands}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${plugin_commands}" -- "${cur}") return 0 ;; "help") - COMPREPLY=($(compgen -W "${commands}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${commands}" -- "${cur}") return 0 ;; "snapshot") snapshot_commands="delete list pop push restore save" - COMPREPLY=($(compgen -W "${snapshot_commands}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${snapshot_commands}" -- "${cur}") return 0 ;; *) ;; esac fi - if [ $COMP_CWORD == 3 ]; then + if ((COMP_CWORD == 3)); then action="${COMP_WORDS[COMP_CWORD - 2]}" case "$action" in "up") if [ "$prev" == "--no-provision" ]; then - COMPREPLY=($(compgen -W "${vm_list}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${vm_list}" -- "${cur}") return 0 fi ;; "box") case "$prev" in "remove" | "repackage") - local box_list=$(find "$HOME/.vagrant.d/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed -e 's/-VAGRANTSLASH-/\//') - COMPREPLY=($(compgen -W "${box_list}" -- ${cur})) + local box_list + box_list=$(find "$HOME/.vagrant.d/boxes" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; | sed -e 's/-VAGRANTSLASH-/\//') + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${box_list}" -- "${cur}") return 0 ;; *) ;; @@ -129,21 +141,24 @@ _vagrant() { ;; "snapshot") if [ "$prev" == "restore" ]; then - COMPREPLY=($(compgen -W "${vm_list}" -- ${cur})) + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${vm_list}" -- "${cur}") return 0 fi ;; esac fi - if [ $COMP_CWORD == 4 ]; then + if ((COMP_CWORD == 4)); then action="${COMP_WORDS[COMP_CWORD - 3]}" prev="${COMP_WORDS[COMP_CWORD - 2]}" case "$action" in "snapshot") if [ "$prev" == "restore" ]; then - local snapshot_list="$(vagrant snapshot list ${cur} 2> /dev/null | awk '{ORS=" "} /==>/ {next} {print}')" - COMPREPLY=($(compgen -W "${snapshot_list}" -- ${cur})) + local snapshot_list + snapshot_list="$(vagrant snapshot list "${cur}" 2> /dev/null | awk '{ORS=" "} /==>/ {next} {print}')" + COMPREPLY=() + while IFS='' read -r line; do COMPREPLY+=("$line"); done < <(compgen -W "${snapshot_list}" -- "${cur}") return 0 fi ;; diff --git a/completion/available/vault.completion.bash b/completion/available/vault.completion.bash index 9520f166b1..6ce9d736ac 100644 --- a/completion/available/vault.completion.bash +++ b/completion/available/vault.completion.bash @@ -1,7 +1,10 @@ # shellcheck shell=bash -cite "about-completion" about-completion "vault completion" -if _binary_exists vault; then - complete -C vault vault -fi +# Make sure vault is installed +_bash-it-completion-helper-necessary vault || return + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient vault || return + +complete -C vault vault diff --git a/completion/available/virsh.completion.bash b/completion/available/virsh.completion.bash index 6450b4a305..55151d16de 100644 --- a/completion/available/virsh.completion.bash +++ b/completion/available/virsh.completion.bash @@ -1,2 +1,4 @@ +# shellcheck shell=bash _log_warning 'Bash completion for "virsh" is now deprecated, as it used code with incompatible license. Please disable this completion and use the instructions from "virsh" developers instead.' +_disable-completion "virsh" diff --git a/completion/available/vuejs.completion.bash b/completion/available/vuejs.completion.bash index 751658f0c9..b7ee31980e 100644 --- a/completion/available/vuejs.completion.bash +++ b/completion/available/vuejs.completion.bash @@ -1,61 +1,61 @@ # shellcheck shell=bash -__vuejs_completion() { - # shellcheck disable=SC2155 - local prev=$(_get_pword) - # shellcheck disable=SC2155 - local curr=$(_get_cword) +# Make sure vue is installed +_bash-it-completion-helper-necessary vue || : + +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient vue || return + +function _vuejs() { + local prev="${COMP_WORDS[COMP_CWORD - 1]}" case $prev in create) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-p -d -i -m -r -g -n -f -c -x -b -h --help --preset --default --inilinePreset --packageManager --registry --git --no-git --force --merge --clone --proxy --bare --skipGetStarted" -- "$curr")) + COMPREPLY=("-p" "-d" "-i" "-m" "-r" "-g" "-n" "-f" "-c" "-x" "-b" + "-h" "--help" "--preset" "--default" "--inilinePreset" + "--packageManager" "--registry" "--git" "--no-git" "--force" + "--merge" "--clone" "--proxy" "--bare" "" "--skipGetStarted") ;; add | invoke) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "--registry -h --help" -- "$curr")) + COMPREPLY=("--registry" "-h" "--help") ;; inspect) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-v --help --verbose --mode --rule --plugin --plugins --rules" -- "$curr")) + COMPREPLY=("-v" "--help" "--verbose" "--mode" "--rule" "--plugin" + "--plugins" "--rules") ;; serve) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-o -h --help --open -c --copy -p --port" -- "$curr")) + COMPREPLY=("-o" "-h" "--help" "--open" "-c" "--copy" "-p" "--port") ;; build) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-t --target -n --name -d --dest -h --help" -- "$curr")) + COMPREPLY=("-t" "--target" "-n" "--name" "-d" "--dest" "-h" "--help") ;; ui) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-H --host -p --port -D --dev --quiet --headless -h --help" -- "$curr")) + COMPREPLY=("-H" "--host" "-p" "--port" "-D" "--dev" "--quiet" + "--headless" "-h" "--help") ;; init) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-c --clone --offline -h --help" -- "$curr")) + COMPREPLY=("-c" "--clone" "--offline" "-h" "--help") ;; config) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-g --get -s --set -d --delete -e --edit --json -h --help" -- "$curr")) + COMPREPLY=("-g" "--get" "-s" "--set" "-d" "--delete" "-e" "--edit" + "--json" "-h" "--help") ;; outdated) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "--next -h --help" -- "$curr")) + COMPREPLY=("--next" "-h" "--help") ;; upgrade) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-t --to -f --from -r --registry --all --next -h --help" -- "$curr")) + COMPREPLY=("-t" "--to" "-f" "--from" "-r" "--registry" "--all" + "--next" "-h" "--help") ;; migrate) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-f --from -h --help" -- "$curr")) + COMPREPLY=("-f" "--from" "-h" "--help") ;; *) - # shellcheck disable=SC2207 - COMPREPLY=($(compgen -W "-h --help -v --version create add invoke inspect serve build ui init config outdated upgrade migrate info" -- "$curr")) + COMPREPLY=("-h" "--help" "-v" "--version" "create" "add" "invoke" + "inspect" "serve" "build" "ui" "init" "config" "outdated" + "upgrade" "migrate" "info") ;; esac } -complete -F __vuejs_completion vue +complete -F _vuejs -X '!&*' vue diff --git a/completion/available/wpscan.completion.bash b/completion/available/wpscan.completion.bash index 105468a356..9c5a95c13b 100644 --- a/completion/available/wpscan.completion.bash +++ b/completion/available/wpscan.completion.bash @@ -1,8 +1,12 @@ # shellcheck shell=bash -_command_exists wpscan || return +# Make sure wpscan is installed +_bash-it-completion-helper-necessary wpscan || : -function __wpscan_completion() { +# Don't handle completion if it's already managed +_bash-it-completion-helper-sufficient wpscan || return + +function __wpscan() { local _opt_ local OPTS=('--help' '--hh' '--version' '--url' '--ignore-main-redirect' '--verbose' '--output' '--format' '--detection-mode' '--scope' '--headers' '--user-agent' '--vhost' '--random-user-agent' '--user-agents-list' '--http-auth' '--max-threads' '--throttle' '--request-timeout' '--connect-timeout' '--disable-tlc-checks' '--proxy' '--proxy-auth' '--cookie-string' '--cookie-jar' '--cache-ttl' '--clear-cache' '--server' '--cache-dir' '--update' '--no-update' '--wp-content-dir' '--wp-plugins-dir' '--wp-version-detection' '--main-theme-detection' '--enumerate' '--exclude-content-based' '--plugins-list' '--plugins-detection' '--plugins-version-all' '--plugins-version-detection' '--themes-list' '--themes-detection' '--themes-version-all' '--themes-version-detection' '--timthumbs-list' '--timthumbs-detection' '--config-backups-list' '--config-backups-detection' '--db-exports-list' '--db-exports-detection' '--medias-detection' '--users-list' '--users-detection' '--passwords' '--usernames' '--multicall-max-passwords' '--password-attack' '--stealthy') COMPREPLY=() @@ -13,4 +17,4 @@ function __wpscan_completion() { done } -complete -F __wpscan_completion wpscan +complete -F __wpscan wpscan diff --git a/docs/README.md b/docs/README.md index 44c438babe..b56eacff58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,13 +5,17 @@ ![License](https://img.shields.io/github/license/Bash-it/bash-it) ![shell](https://img.shields.io/badge/Shell-Bash-blue) -**Bash-it** is a collection of community Bash commands and scripts for Bash 3.2+. +**Bash-it** is a collection of community Bash commands and scripts for Bash. (And a shameless ripoff of [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) :smiley:) +97% of the code is compatible with bash 3.2+ but we are geared also toward power users, +and one or two of the more complex plugins may need bash 5 features to run. If you +happen to be "stuck" on an older version of bash, we have code in place to prevent you +from running those modules and getting errors. It's a short list though, and none of the core code. Includes autocompletion, themes, aliases, custom functions, a few stolen pieces from Steve Losh, and more. Bash-it provides a solid framework for using, developing and maintaining shell scripts and custom commands for your daily work. -If you're using the _Bourne Again Shell_ (Bash) regularly and have been looking for an easy way on how to keep all of these nice little scripts and aliases under control, then Bash-it is for you! +If you're using the _Bourne Again Shell_ (Bash) regularly and have been looking for an easy way on how to keep all of these nice little scripts and aliases under control, then Bash-it is for you! Stop polluting your `~/bin` directory and your `.bashrc` file, fork/clone Bash-it and start hacking away. - [Main Page](https://bash-it.readthedocs.io/en/latest) @@ -21,6 +25,7 @@ Stop polluting your `~/bin` directory and your `.bashrc` file, fork/clone Bash-i - [via Docker](https://bash-it.readthedocs.io/en/latest/installation/#install-using-docker) - [Updating](https://bash-it.readthedocs.io/en/latest/installation/#updating) - [Help](https://bash-it.readthedocs.io/en/latest/misc/#help-screens) +- [Diagnostics](#diagnostics) - [Search](https://bash-it.readthedocs.io/en/latest/commands/search) - [Syntax](https://bash-it.readthedocs.io/en/latest/commands/search/#syntax) - [Searching with Negations]( @@ -41,9 +46,9 @@ Stop polluting your `~/bin` directory and your `.bashrc` file, fork/clone Bash-i ``git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it`` 2) Run ``~/.bash_it/install.sh`` -That's it! :smiley: +That's it! :smiley: -You can check out more components of Bash-it, and customize it to your desire. +You can check out more components of Bash-it, and customize it to your desire. For more information, see detailed instructions [here](https://bash-it.readthedocs.io/en/latest/installation/). ### custom configuration file location @@ -54,10 +59,30 @@ If this is undesirable, you can create another file, by run the installer: BASH_IT_CONFIG_FILE=path/to/my/custom/location.bash ~/.bash_it/install.sh ``` +## Diagnostics + +If you're experiencing issues with Bash-it or need to report a bug, use the built-in diagnostics tool: + +```bash +bash-it doctor +``` + +This command provides a comprehensive summary including: +- Environment information (OS, Bash version) +- Bash-it version and update status +- Configuration file locations and how Bash-it is loaded +- List of enabled components (aliases, plugins, completions) + +**When reporting bugs**, please include the full output of `bash-it doctor` in your issue report. + +The doctor command can also help you update Bash-it - if you're behind the latest version and it's safe to update, you'll be prompted to merge the latest changes. + ## Contributing Please take a look at the [Contribution Guidelines](https://bash-it.readthedocs.io/en/latest/contributing) before reporting a bug or providing a new feature. +**When reporting bugs**, always run `bash-it doctor` and include its output in your issue report to help maintainers diagnose the problem quickly. + The [Development Guidelines](https://bash-it.readthedocs.io/en/latest/development) have more information on some of the internal workings of Bash-it, please feel free to read through this page if you're interested in how Bash-it loads its components. diff --git a/docs/contributing.rst b/docs/contributing.rst index 2ba3ce7faf..a077546bcc 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -47,8 +47,12 @@ Code Style Take a look at the existing code for an example (e.g. `the base plugin `_\ ). * When adding files, please use the existing file naming conventions, e.g. plugin files need to end in ``.plugin.bash``. This is important for the installation functionality. -* When using the ``$BASH_IT`` variable, please always enclose it in double quotes to ensure that the code also works when Bash-it is installed in a directory that contains spaces in its name: ``for f in "${BASH_IT}/plugins/available"/*.bash ; do echo "$f" ; done`` +* When using the ``$BASH_IT`` variable, please always enclose it in double quotes to ensure that the code also works when + Bash-it is installed in a directory that contains spaces in its name: ``for f in "${BASH_IT}/plugins/available"/*.bash ; do echo "$f" ; done`` * Bash-it supports Bash 3.2 and higher. Please don't use features only available in Bash 4, such as associative arrays. +* That said, if you have a really cool plugin or feature to contribute and it absolutely too slow or hard to implement + without bash4 or higher, please see plugins/available/pack.plugin.bash for an example how to self disable and log the reason + so bash 3.2 users are not stuck with errors that don't need to handle. Unit Tests ---------- diff --git a/docs/installation.rst b/docs/installation.rst index 9688af20f7..068f2da572 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -6,8 +6,8 @@ Installation #. Check out a clone of this repo to a location of your choice, such as ``git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it`` -#. Run ``~/.bash_it/install.sh`` (it automatically backs up your ``~/.bash_profile`` or ``~/.bashrc``\ , depending on your OS) -#. Edit your modified config (\ ``~/.bash_profile`` or ``~/.bashrc``\ ) file in order to customize Bash-it. +#. Run ``~/.bash_it/install.sh`` (it automatically backs up your ``~/.bashrc``\ ) +#. Edit your modified config (\ ``~/.bashrc``\ ) file in order to customize Bash-it. #. Check out available aliases, completions, and plugins and enable the ones you want to use (see the next section for more details). Install Options @@ -18,7 +18,7 @@ The install script can take the following options: * ``--interactive``\ : Asks the user which aliases, completions and plugins to enable. * ``--silent``\ : Ask nothing and install using default settings. -* ``--no-modify-config``\ : Do not modify the existing config file (\ ``~/.bash_profile`` or ``~/.bashrc``\ ). +* ``--no-modify-config``\ : Do not modify the existing config file (\ ``~/.bashrc``\ ). * ``--append-to-config``\ : Back up existing config file and append bash-it templates at the end. When run without the ``--interactive`` switch, Bash-it only enables a sane default set of functionality to keep your shell clean and to avoid issues with missing dependencies. @@ -28,16 +28,14 @@ When you run without the ``--no-modify-config`` switch, the Bash-it installer au Use the ``--no-modify-config`` switch to avoid unwanted modifications, e.g. if your Bash config file already contains the code that loads Bash-it. **NOTE**\ : Keep in mind how Bash loads its configuration files, -``.bash_profile`` for login shells (and in macOS in terminal emulators like `Terminal.app `_ or -`iTerm2 `_\ ) and ``.bashrc`` for interactive shells (default mode in most of the GNU/Linux terminal emulators), -to ensure that Bash-it is loaded correctly. +``.bash_profile`` for login shells and ``.bashrc`` for interactive shells, to ensure that Bash-it is loaded correctly. A good "practice" is sourcing ``.bashrc`` into ``.bash_profile`` to keep things working in all the scenarios. To achieve this, you can add this snippet in your ``.bash_profile``\ : .. code-block:: - if [ -f ~/.bashrc ]; then - . ~/.bashrc + if [[ $- == *"i"* && -f ~/.bashrc ]]; then + source ~/.bashrc fi Refer to the official `Bash documentation `_ to get more info. diff --git a/docs/plans/bash-it-issues-comprehensive-analysis.md b/docs/plans/bash-it-issues-comprehensive-analysis.md new file mode 100644 index 0000000000..544456dc9d --- /dev/null +++ b/docs/plans/bash-it-issues-comprehensive-analysis.md @@ -0,0 +1,404 @@ +# Bash-it Open Issues - Comprehensive Analysis & Action Plan +**Analysis Date**: 2025-10-05 +**Last Updated**: 2025-10-07 +**Total Open Issues**: 32 → 27 (5 fixed) +**Analyzed By**: Claude Code + +--- + +## Executive Summary + +Out of 32 open issues: +- **5 Quick Wins** - ✅ **ALL FIXED** (2025-10-07) +- **6 Require Your Decision** - 3 implemented, 3 still need input +- **18 Stale/Redundant** - Old issues (>2 years) that need closure decisions +- **3 Long-term Roadmap** - Strategic features for future planning + +**Recent Progress**: 5 issues fixed in 1 day with PRs #2349, #2350, #2351, #2352, #2353 +**Critical Finding**: 78% of issues are stale (>2 years old). Recommend aggressive issue gardening to improve project health. + +--- + +## 1. QUICK WINS - ✅ ALL COMPLETED (5/5 issues) + +### ✅ Issue #2317: Auto-infer remote name +**Status**: ✨ **FIXED** - PR #2345 created 2025-10-05 +- Simple helper function to detect git remote name +- No more hardcoded "origin" assumption +- **Action**: None needed + +### ⚡ Issue #2314: Interactive install fails for todo aliases +**Effort**: 5 minutes +**Status**: TODO - Still needs fixing +**Fix**: Rename `todo.txt-cli.aliases.bash` → `todo.aliases.bash` +- Clear bug, clear solution already identified in issue +- Just a file rename to match naming convention +- **Action**: Can be fixed next + +### ✅ Issue #2296: down4me function broken +**Status**: ✨ **FIXED** - PR #2350 created 2025-10-07 +- Fixed URL malformation when passing full URLs with protocols +- Strips http:// and https:// from input +- Uses `command` prefix to bypass aliases +- **Action**: None needed + +### ✅ Issue #2260: SSH completion removes @ symbol +**Status**: ✨ **FIXED** - PR #2351 created 2025-10-07 +- Removed @ from COMP_WORDBREAKS to preserve user@host format +- Now correctly completes ssh root@server instead of ssh rootserver +- **Action**: None needed + +### ✅ Issue #2238: Uninstall script deletes bashrc incorrectly +**Status**: ✨ **FIXED** - PR #2352 created 2025-10-07 +- Now backs up current config before restoring old backup +- Saves to ~/.bashrc.pre-uninstall.bak (or ~/.bash_profile.pre-uninstall.bak) +- Users can review and merge changes if needed +- **Action**: None needed + +--- + +## 2. DECISION REQUIRED - Need Your Input (6 issues) + +### ✅ Issue #2248: Add Laravel Artisan completion +**Status**: ✨ **IMPLEMENTED** - PR #2349 created 2025-10-07 +- Added dynamic completion for Laravel artisan commands +- Works with both `artisan` and `art` aliases +- Only activates when artisan file exists in directory +- **Action**: None needed + +### 🤔 Issue #2245: Add tmux -c completion +**Decision Needed**: Accept feature or close? +- Small enhancement to tmux completion +- **Question**: Accept incremental tmux improvements? +- **Recommendation**: Accept if clean PR submitted +- **Your Call**: Yes/No? + +### ✅ Issue #2216: Show node version only in package.json directories +**Status**: ✨ **IMPLEMENTED** - PR #2353 created 2025-10-07 +- Added NODE_VERSION_CHECK_PROJECT environment variable (default: false) +- When enabled, only shows node version in directories with package.json +- Fully backwards compatible (disabled by default) +- **Action**: None needed + +### 🤔 Issue #2214: Do you need maintainers? +**Decision Needed**: Project governance +- Open question about adding maintainers +- **Action**: You need to respond about maintainer status/needs +- **Your Call**: Are you looking for co-maintainers? + +### 🤔 Issue #1819: Package bash-it with package manager +**Decision Needed**: Distribution strategy +- Request to get bash-it into Homebrew, apt, etc. +- **Major effort** but would improve adoption +- **Question**: Is packaging worth the maintenance burden? +- **Your Call**: Worth pursuing or close? + +### 🤔 Issue #825: Aliases shadowing program names +**Decision Needed**: Philosophy on aliases +- Some aliases override common commands (e.g., `ll`) +- **Question**: Should bash-it be more conservative with alias names? +- **Recommendation**: Document clearly, let users choose +- **Your Call**: Change default alias behavior or close? + +--- + +## 3. STALE/REDUNDANT - Need Closure Decisions (18 issues) + +These are all >2 years old with minimal activity. **Recommend closing most** with option to reopen if someone volunteers. + +### 🗑️ Ancient Issues (>4 years old) - Recommend CLOSE + +#### Issue #517 (2015): Plugin load times +- Created 9 years ago +- Generic performance concern, no specific action items +- **Recommendation**: Close - performance is acceptable now + +#### Issue #825 (2016): Aliases shadowing programs +- Already listed above in "Decision Required" + +#### Issue #922 (2017): Support for enhancd +- 7 years old, labeled "seems abandoned" +- External tool integration request +- **Recommendation**: Close - no activity, unclear if still needed + +#### Issue #1053 (2017): Evaluate kcov code coverage +- 7 years old, technical improvement +- **Recommendation**: Close - we use BATS now, coverage not critical + +#### Issue #1207 (2018): Prompt wrap-around glitches +- 6 years old, prompt theme visual bugs +- **Recommendation**: Close - likely fixed in modern terminals, needs repro + +### 🗑️ Old Issues (2-4 years) - Recommend CLOSE unless someone volunteers + +#### Issue #1640 (2020): Cleanup "base" and "general" +- Vague organizational request +- **Recommendation**: Close - or convert to specific actionable issue + +#### Issue #1680 (2020): Add documentation for all commands +- Massive undertaking, no volunteers +- **Recommendation**: Close - accept incremental doc improvements instead + +#### Issue #1693 (2020): todo plugin doesn't use $TODO variable +- Related to #2314 (todo aliases) +- **Recommendation**: Close as duplicate or fix alongside #2314 + +#### Issue #1696 (2020): Help us clean up Bash-it! +- Meta tracking issue for cleanup +- **Recommendation**: KEEP OPEN - useful for coordinating cleanup efforts +- **Action**: Update with current status (pre-commit hooks working!) + +#### Issue #1818 (2021): Moving external libraries to vendor/ +- Technical debt cleanup +- **Recommendation**: Close - already done, verify and close + +#### Issue #1943 (2021): Performance of bash-preexec DEBUG trap +- Performance concern about DEBUG trap +- **Recommendation**: Close - needs reproduction, likely non-issue + +#### Issue #2080 (2022): Structure all aliases +- Organizational improvement +- **Recommendation**: Close - too vague, accept specific alias improvements + +#### Issue #2084 (2022): Platform dependent config file selection +- Question about macOS vs Linux config differences +- **Recommendation**: Close - working as designed, or needs specific fix proposal + +#### Issue #2149 (2022): pyenv plugin breaks over SSH +- SSH + pyenv interaction issue +- **Recommendation**: Close - needs reproduction, likely user config issue + +#### Issue #2150 (2022): Help information for preview command +- Documentation request +- **Recommendation**: Close - command is self-explanatory, or add quick docs + +#### Issue #2174 (2022): System alias breaks completion +- Completion conflict with user's system alias +- **Recommendation**: Investigate - might be legit bug or user config issue + +#### Issue #2184 (2022): Show plugin source URI +- Feature request for plugin metadata +- **Recommendation**: Close - not worth complexity, plugins are in repo + +#### Issue #2197 (2023): bash-it preview not working +- Preview command bug +- **Recommendation**: Close - needs reproduction on current version + +#### Issue #2202 (2023): Why does install add shebang to bash_profile? +- Question about install behavior +- **Recommendation**: Answer and close - likely incorrect assumption + +### 🕐 Recent but inactive (1-2 years) - Investigate before closing + +#### Issue #2254 (2024): Syntax error in alias_completion +- Bash syntax error in generated completion file +- **Recommendation**: Try to reproduce, fix or close + +#### Issue #2264 (2024): Alias completion doesn't complete +- Already listed in Quick Wins above + +#### Issue #2297 (2025): Powerline multiline SSH padlock miscalculation +- Recent bug (Mar 2025), active (Sept update) +- **Recommendation**: KEEP OPEN - legitimate bug, needs fix + +--- + +## 4. LONG-TERM ROADMAP (3 issues) + +### 📋 Issue #1696: Help us clean up Bash-it! +**Status**: Active coordination issue +- Good place to track pre-commit cleanup progress +- **Action**: Keep open, update regularly with progress +- **Next Steps**: + - List remaining files not in `clean_files.txt` + - Create "good first issue" labels for individual files + +### 📋 Issue #1819: Package Bash-it with package managers +**Status**: Requires decision (see Decision Required section) +- Would significantly improve installation experience +- **Effort**: Epic (months) +- **Benefit**: High - easier adoption +- **Dependencies**: Need CI/CD, release process, semantic versioning + +### 📋 Issue #1053: Code coverage with kcov +**Status**: Low priority technical improvement +- Would be nice to have coverage metrics +- **Effort**: Medium (weeks) +- **Benefit**: Low - we have tests, coverage is nice-to-have + +--- + +## 5. WORK PLAN TO REDUCE TECH DEBT + +### Phase 1: Immediate Wins ✅ COMPLETED (2025-10-07) +**All fixed without user input:** + +1. ✅ Fix #2317 - Auto-detect git remote (PR #2345 - 2025-10-05) +2. ✅ Fix #2248 - Laravel artisan completion (PR #2349 - 2025-10-07) +3. ✅ Fix #2296 - down4me function URL malformation (PR #2350 - 2025-10-07) +4. ✅ Fix #2260 - SSH completion @ symbol (PR #2351 - 2025-10-07) +5. ✅ Fix #2238 - Improve uninstall script (PR #2352 - 2025-10-07) +6. ✅ Fix #2216 - Node version conditional display (PR #2353 - 2025-10-07) + +**Remaining:** +- ⚡ Fix #2314 - Rename todo alias file (5 min) + +**Total Completed**: 6 PRs, 5 issues can be closed once PRs merge + +### Phase 2: Issue Gardening (Next Week) +**Need your approval, then I execute:** + +1. Close stale issues (18 issues) with polite message: + - "Closing due to age/inactivity. Please reopen with reproduction on latest version if still relevant." +2. Update #1696 (cleanup tracking) with current status +3. Label issues needing decisions with "needs-decision" +4. Label quick wins with "good-first-issue" + +**Total Time**: 2 hours, 18 issues closed, improved issue hygiene + +### Phase 3: Strategic Decisions (This Month) +**You decide, I can implement:** + +1. **Decision**: Accept framework-specific completions? (#2248 Laravel) +2. **Decision**: Smart plugin behavior? (#2216 nvm auto-detect) +3. **Decision**: Need co-maintainers? (#2214) +4. **Decision**: Pursue packaging? (#1819) +5. **Decision**: Conservative aliases? (#825) + +**Outcome**: Clear project direction, updated CLAUDE.md with decisions + +### Phase 4: Continued Cleanup (Ongoing) +**Sustaining momentum:** + +1. Continue `clean_files.txt` expansion + - Current: ~50 files clean + - Goal: All files pass pre-commit hooks +2. Add tests for bugs as they're fixed +3. Improve documentation incrementally +4. Monthly issue triage (close stale, label new) + +--- + +## 6. RECOMMENDATIONS + +### Critical Actions +1. ✅ **Fix Quick Wins** - 5 issues, 4 hours work, big impact +2. 🧹 **Close Stale Issues** - Improve project health, reduce noise +3. 🎯 **Make Strategic Decisions** - Give project clear direction + +### Nice to Have +4. 📦 **Consider Packaging** - Would improve adoption significantly +5. 📚 **Incremental Docs** - Fix docs as you touch code +6. 🧪 **Coverage Tracking** - Low priority, would be nice + +### Don't Do +- ❌ Don't try to fix all old issues - most are stale +- ❌ Don't accept vague feature requests - require specific proposals +- ❌ Don't feel bad closing old issues - it's healthy + +--- + +## 7. WHAT I CAN DO WITHOUT YOUR HELP + +### Completed (2025-10-07) +- [x] Fix #2317 - git remote auto-detect (PR #2345) +- [x] Fix #2248 - Laravel artisan completion (PR #2349) +- [x] Fix #2296 - down4me function (PR #2350) +- [x] Fix #2260 - SSH completion (PR #2351) +- [x] Fix #2238 - uninstall script (PR #2352) +- [x] Fix #2216 - node version conditional display (PR #2353) + +### This Week +- [ ] Fix #2314 - todo alias rename +- [ ] Draft issue closure messages for stale issues +- [ ] Update #1696 with cleanup progress +- [ ] Identify next 10 files for `clean_files.txt` + +### Ongoing +- [ ] Continue pre-commit cleanup (add files to clean_files.txt) +- [ ] Write tests for bugs I fix +- [ ] Improve docs as I work + +--- + +## 8. WHAT I NEED FROM YOU + +### Decisions Needed +1. **Close stale issues?** - Should I close the 18 stale issues (>2 years old)? +2. **Framework completions?** (#2248) - Accept Laravel/Artisan completion? +3. **Smart plugins?** (#2216) - Should nvm only show in Node projects? +4. **Maintainer status?** (#2214) - Are you seeking co-maintainers? +5. **Packaging?** (#1819) - Worth pursuing package manager distribution? +6. **Alias philosophy?** (#825) - Stay aggressive or be more conservative? + +### Approval Needed +- Approve me to start making PRs for Quick Wins +- Approve mass closure of stale issues (with template message) + +--- + +## 9. PROPOSED ISSUE CLOSURE TEMPLATE + +For stale issues, I recommend this message: + +```markdown +Closing this issue due to inactivity (2+ years old). + +If this is still relevant, please: +1. Test with latest bash-it version +2. Provide reproduction steps +3. Reopen or create new issue with updated details + +Thanks for your contribution to bash-it! 🎉 +``` + +--- + +## 10. SUCCESS METRICS + +### Short Term (1 month) +- [ ] 5+ Quick Win PRs merged +- [ ] 18 stale issues closed +- [ ] Open issue count < 15 +- [ ] All open issues labeled and categorized + +### Medium Term (3 months) +- [ ] 100+ files in `clean_files.txt` (currently ~50) +- [ ] All quick wins fixed +- [ ] Strategic decisions made and documented +- [ ] Issue response time < 1 week + +### Long Term (6 months) +- [ ] All files pass pre-commit hooks +- [ ] < 10 open issues at any time +- [ ] Clear contribution guidelines +- [ ] Possibly: Package manager distribution + +--- + +## APPENDIX: Issue Reference + +### Quick Wins (6) +- #2317 ✅ Auto-detect git remote (PR #2345) +- #2248 ✅ Laravel artisan completion (PR #2349) +- #2296 ✅ down4me broken (PR #2350) +- #2260 ✅ SSH completion @ issue (PR #2351) +- #2238 ✅ Uninstall script issue (PR #2352) +- #2216 ✅ Smart nvm plugin (PR #2353) +- #2314 ⚡ Todo alias install failure (TODO) + +### Decision Required (3 remaining) +- #2245 tmux completion +- #2214 Need maintainers? +- #1819 Package managers +- #825 Alias philosophy + +### Stale/Close (18) +- #517, #825, #922, #1053, #1207 (Ancient >4yr) +- #1640, #1680, #1693, #1818, #1943, #2080, #2084, #2149, #2150, #2174, #2184, #2197, #2202 (Old 2-4yr) +- #2254 (Recent but needs repro) + +### Keep Open (3) +- #1696 Cleanup tracking issue +- #2297 Powerline bug (recent, active) +- Any issues with recent activity or clear action items diff --git a/docs/plans/bash-it-quick-reference.md b/docs/plans/bash-it-quick-reference.md new file mode 100644 index 0000000000..98c7c7c427 --- /dev/null +++ b/docs/plans/bash-it-quick-reference.md @@ -0,0 +1,133 @@ +# Bash-it Issue Analysis - Quick Reference +**Date**: 2025-10-05 +**Updated**: 2025-10-07 + +## TL;DR + +📊 **32 open issues** → **27 remaining** (5 fixed!) + +### ✅ Completed (2025-10-07) +1. ✅ Fix #2317 - git remote detection (PR #2345) +2. ✅ Fix #2248 - Laravel artisan completion (PR #2349) +3. ✅ Fix #2296 - down4me function (PR #2350) +4. ✅ Fix #2260 - SSH completion (PR #2351) +5. ✅ Fix #2238 - uninstall script (PR #2352) +6. ✅ Fix #2216 - node version conditional (PR #2353) + +### What's Left +- Fix #2314 - todo alias rename (5 min) + +**Progress**: 6 PRs created, 5 issues closed (pending PR merge) + +### What I Need From You + +#### Decision 1: Close Stale Issues? +Close 18 issues that are 2+ years old with no activity? +- ✅ **Recommend YES** - Improves project health +- Template message: "Closing due to inactivity. Reopen if still relevant." + +#### Decision 2: Framework Completions? +~~Accept Laravel/Artisan completions (#2248)?~~ +- ✅ **DONE** - Implemented in PR #2349 + +#### Decision 3: Smart Plugins? +~~Should nvm plugin auto-detect Node projects (#2216)?~~ +- ✅ **DONE** - Implemented in PR #2353 (opt-in via NODE_VERSION_CHECK_PROJECT) + +#### Decision 4: Need Co-Maintainers? +Response to #2214 about project governance? +- ⚖️ **Your call** - Want help maintaining? + +#### Decision 5: Package Managers? +Worth effort to get into Homebrew (#1819)? +- ⚖️ **Recommend YES** - Big UX improvement, modest effort + +#### Decision 6: Alias Philosophy? +Be more conservative with aliases like `ll`? (#825) +- ⚖️ **Recommend NO** - Keep current, improve docs + +--- + +## Issue Breakdown + +### ✅ Fixed (6 completed) +- #2317: git remote (PR #2345) +- #2248: Laravel completion (PR #2349) +- #2296: down4me (PR #2350) +- #2260: SSH completion (PR #2351) +- #2238: uninstall script (PR #2352) +- #2216: Smart nvm (PR #2353) + +### ⚡ Quick Fix Remaining (1) +- #2314: todo alias rename + +### 🤔 Need Your Decision (4) +- #2245: tmux completion +- #2214: Maintainers +- #1819: Packaging +- #825: Alias philosophy + +### 🗑️ Recommend Closing (18) +All are 2+ years old with no activity: +- #517, #922, #1053, #1207 (Ancient >4yr) +- #1640, #1680, #1693, #1818, #1943, #2080, #2084, #2149, #2150, #2174, #2184, #2197, #2202 (Old 2-4yr) +- #2254 (Needs repro) + +### 📌 Keep Open (3) +- #1696: Cleanup tracking issue (still active) +- #2297: Powerline bug (recent, active) +- Any new issues with activity + +--- + +## Recommended Action Plan + +### This Week +1. I fix 5 quick win bugs +2. You review and approve stale issue closure +3. You make strategic decisions + +### Next Week +1. Close stale issues +2. Start pre-commit cleanup +3. Label remaining issues + +### This Month +1. Continue code cleanup +2. Improve documentation +3. Monthly issue triage + +--- + +## Files Created + +1. `/tmp/bash-it-issues-comprehensive-analysis.md` - Full detailed analysis +2. `/tmp/bash-it-roadmap-2025.md` - 6-month technical debt reduction plan +3. `/tmp/bash-it-quick-reference.md` - This file (TL;DR version) +4. `/tmp/bash-it-open-issues.json` - Raw issue data + +--- + +## Key Metrics + +| Metric | Original | Now (2025-10-07) | After Phase 2 | Target | +|--------|----------|------------------|---------------|--------| +| Open Issues | 32 | 27 | 9 | <10 | +| Stale Issues | 25 | 25 | 0 | 0 | +| Quick Wins Done | 0 | 6 | 7 | 7 | +| Clean Files | ~50 | ~50 | ~100 | 400+ | +| PRs Created | 0 | 6 | 6+ | Ongoing | + +--- + +## Next Action + +**Status Update (2025-10-07)**: +- ✅ 6 Quick Win PRs created and ready for review +- ✅ Issues #2248 and #2216 implemented (were in "Decision" category) +- ⚡ 1 more quick fix remaining (#2314) + +**Remaining Decisions**: +1. Approve stale issue closure? +2. Make strategic decisions (#2214, #1819, #825, #2245)? +3. Review and merge PRs #2345, #2349, #2350, #2351, #2352, #2353 diff --git a/docs/plans/bash-it-roadmap-2025.md b/docs/plans/bash-it-roadmap-2025.md new file mode 100644 index 0000000000..d9b5dce504 --- /dev/null +++ b/docs/plans/bash-it-roadmap-2025.md @@ -0,0 +1,416 @@ +# Bash-it Technical Debt Reduction Roadmap 2025 +**Created**: 2025-10-05 +**Last Updated**: 2025-10-07 +**Owner**: Maintainers +**Goal**: Reduce open issues from 32 to <10, improve code quality to 100% pre-commit clean + +--- + +## Current State Assessment + +### Health Metrics (2025-10-07 Update) +- 📊 **Open Issues**: 32 → **27** (5 closed pending PR merge) +- 🧹 **Clean Files**: ~50 files in `clean_files.txt` +- ✅ **Pre-commit Coverage**: ~15% of codebase +- ⏰ **Stale Issues**: 78% (>2 years old) - **25 remaining** +- 🐛 **Active Bugs**: ~~5~~ **1** fixable quickly (4 fixed!) +- 🎯 **Issue Response Time**: Variable (some years old) +- 🚀 **PRs Created**: **6** in 2 days + +### Technical Debt Categories +1. **Code Quality**: Many files don't pass shellcheck/shfmt +2. **Issue Backlog**: 25 stale issues creating noise +3. **Documentation**: Inconsistent, incomplete +4. **Testing**: Good BATS coverage, but could expand +5. **Distribution**: Manual install only, no package managers + +--- + +## Phase 1: Quick Wins Sprint ✅ COMPLETED (2025-10-07) +**Goal**: Fix bugs, close issues, build momentum +**Effort**: 2 days, 6 PRs created + +### Tasks +- [x] #2317: Auto-detect git remote (PR #2345 - 2025-10-05) +- [x] #2248: Laravel artisan completion (PR #2349 - 2025-10-07) +- [x] #2296: Fix down4me function (PR #2350 - 2025-10-07) +- [x] #2260: Fix SSH completion @ removal (PR #2351 - 2025-10-07) +- [x] #2238: Improve uninstall script (PR #2352 - 2025-10-07) +- [x] #2216: Node version conditional display (PR #2353 - 2025-10-07) +- [ ] #2314: Rename todo alias file (TODO - 5 min) + +### Success Criteria +- ✅ 6 PRs created (awaiting review/merge) +- ✅ 5 issues can be closed (pending PR merge) +- ⏳ Tests included where applicable +- ✅ Clean git history, all linting passed + +### Deliverables +- Working fixes for real user problems +- Test coverage for fixed bugs +- Updated documentation where needed +- Template for future quick-win sprints + +--- + +## Phase 2: Issue Garden Cleanup (Week 3-4) +**Goal**: Reduce noise, improve project health +**Effort**: ~4 hours + +### Strategy: Aggressive Stale Issue Closure +Close issues that are: +- >2 years old with no recent activity +- Vague feature requests with no volunteers +- Questions that were never answered +- Fixed but not closed +- No longer relevant + +### Execution Plan +1. **Week 3**: Draft closure messages for each issue +2. **Get maintainer approval** on closure list +3. **Week 4**: Close issues with polite template message +4. **Add labels**: "stale-closed", "reopen-if-relevant" + +### Issues to Close (18 total) +**Ancient** (>4 years, likely irrelevant): +- #517: Plugin load times (2015) +- #922: Support for enhancd (2017) +- #1053: Evaluate kcov coverage (2017) +- #1207: Prompt wrap-around (2018) + +**Old** (2-4 years, no activity): +- #1640: Cleanup base/general +- #1680: Document all commands +- #1693: todo plugin $TODO variable +- #1818: Move libs to vendor +- #1943: preexec performance +- #2080: Structure aliases +- #2084: Platform config question +- #2149: pyenv over SSH +- #2150: Preview help +- #2174: System alias breaks completion +- #2184: Show plugin source URI +- #2197: Preview not working +- #2202: Install shebang question + +**Recent but stale** (needs repro): +- #2254: Syntax error in completion + +### Success Criteria +- ✅ Open issues reduced from 32 to <15 +- ✅ All remaining issues labeled appropriately +- ✅ Clear "why closed" rationale for each +- ✅ Template for future issue gardening + +--- + +## Phase 3: Strategic Decisions (Month 2) +**Goal**: Establish clear project direction +**Effort**: Discussion + documentation + +### Decisions Required + +#### 1. Framework-Specific Completions (#2248, #2245) +**Question**: Accept framework-specific completions (Laravel, etc.)? +**Options**: +- A) Accept all quality completions (grow features) +- B) Only popular/maintained frameworks (selective) +- C) Reject (keep bash-it focused) + +**Recommendation**: Option B - Selective acceptance +- Require: Good tests, maintained upstream, popular (>10k stars) +- Reject: Niche frameworks, unmaintained, poor code quality + +#### 2. Smart Plugin Behavior (#2216) +**Question**: Should plugins auto-detect context (e.g., nvm only in Node projects)? +**Options**: +- A) Add smart detection (better UX, more complexity) +- B) Keep simple (user configures, less magic) + +**Recommendation**: Option B - Keep simple +- Document how users can add conditional logic themselves +- Avoid complexity in core plugins + +#### 3. Maintainer/Governance (#2214) +**Question**: Need co-maintainers? How to govern? +**Options**: +- A) Seek co-maintainers (share workload) +- B) Stay solo (full control) +- C) Create contributor tiers (core + trusted) + +**Recommendation**: Option C - Tiered contributors +- Core maintainer(s): Can merge to master +- Trusted contributors: Can label, triage issues +- Contributors: Submit PRs + +#### 4. Package Manager Distribution (#1819) +**Question**: Worth effort to get into Homebrew, apt, etc.? +**Options**: +- A) Full packaging effort (Homebrew, apt, yum) +- B) Homebrew only (most requested) +- C) Git install only (current) + +**Recommendation**: Option B - Homebrew first +- Create Homebrew formula (2-4 hours work) +- Improves adoption significantly +- Low maintenance once set up +- Defer other package managers until demand proven + +#### 5. Alias Philosophy (#825) +**Question**: How aggressive with default aliases? +**Options**: +- A) Very conservative (no common command shadowing) +- B) Current approach (some shadowing, documented) +- C) More aggressive (convenience > safety) + +**Recommendation**: Option B - Current + better docs +- Keep current aliases (many users depend on them) +- Add BIG WARNING in docs about ll, la, etc. +- Add `bash-it doctor --check-conflicts` command +- Let users decide (enable/disable) + +### Outcome +- All decisions documented in CLAUDE.md +- Issues closed or converted to tracked work +- Clear contributor guidelines + +--- + +## Phase 4: Pre-commit Expansion (Month 2-3) +**Goal**: Get 80%+ of files passing pre-commit hooks +**Effort**: ~20 hours spread over 6 weeks + +### Current State +- `clean_files.txt` has ~50 entries +- Remaining: ~450 bash files need cleanup +- Pre-commit hooks: shellcheck, shfmt, trailing whitespace, etc. + +### Strategy: Chip Away Weekly +- **Weekly goal**: Add 10 files to `clean_files.txt` +- **Prioritize**: Most-used files first (lib/, install.sh, bash_it.sh) +- **Batch fixes**: Group similar files (all themes, all plugins of type X) + +### Target Files (Priority Order) +1. **Core** (Week 1-2): + - bash_it.sh + - scripts/reloader.bash + - All files in lib/ + +2. **Install/Uninstall** (Week 3): + - install.sh (partially done) + - uninstall.sh + +3. **Popular Plugins** (Week 4-5): + - plugins/available/base.plugin.bash + - plugins/available/git.plugin.bash + - plugins/available/docker.plugin.bash + - plugins/available/nvm.plugin.bash + +4. **Themes** (Week 6-7): + - Focus on most popular themes first + - bobby, powerline, atomic, etc. + +5. **Completions** (Week 8-9): + - System completions + - Popular tool completions + +6. **Aliases** (Week 10+): + - Lower priority (users can disable) + - Fix as time permits + +### Success Criteria +- ✅ 80% of files in `clean_files.txt` +- ✅ All core files (lib/, scripts/) clean +- ✅ Install scripts clean +- ✅ Top 10 plugins/themes clean + +--- + +## Phase 5: Documentation Refresh (Month 3-4) +**Goal**: Improve docs incrementally as we work +**Effort**: ~10 hours + +### Key Documentation Needs +1. **README.md**: Update with current state +2. **CONTRIBUTING.md**: Clear guidelines for PRs +3. **CLAUDE.md**: Document decisions, patterns +4. **Wiki**: Troubleshooting common issues + +### Approach: Doc-as-you-go +- Fix bug → Update relevant docs +- Add feature → Update examples +- Close stale issue → Document decision + +### Priority Docs +1. Pre-commit hook usage (for contributors) +2. Plugin development guide +3. Theme development guide +4. Troubleshooting guide +5. Performance optimization guide + +--- + +## Phase 6: Testing Expansion (Month 4-5) +**Goal**: Increase test coverage for critical paths +**Effort**: ~15 hours + +### Current Testing +- BATS framework in place +- Good coverage of core functionality +- Some plugins/completions lack tests + +### Testing Priorities +1. **Core Functions**: lib/helpers.bash functions +2. **Bug Fixes**: Every bug fix gets a test +3. **Plugins**: At least smoke tests for all +4. **Completions**: Test completion generation + +### Success Criteria +- ✅ All functions in lib/ have tests +- ✅ All fixed bugs have regression tests +- ✅ CI runs tests on every PR +- ✅ Test coverage >70% + +--- + +## Phase 7: Packaging & Distribution (Month 5-6) +**Goal**: Get bash-it into Homebrew (if decision approved) +**Effort**: ~8 hours initial + ongoing maintenance + +### Homebrew Formula Steps +1. Create formula in homebrew-core +2. Define installation steps +3. Add update mechanism +4. Add uninstall support +5. Submit PR to Homebrew + +### Requirements +- Semantic versioning (start tagging releases) +- Stable release process +- Update mechanism (bash-it update needs to work) +- CI to test formula + +### Success Criteria +- ✅ Homebrew formula accepted +- ✅ Users can `brew install bash-it` +- ✅ Formula auto-updates with releases +- ✅ Documented in README + +--- + +## Success Metrics & KPIs + +### Issue Health +| Metric | Current | 1 Month | 3 Months | 6 Months | +|--------|---------|---------|----------|----------| +| Open Issues | 32 | <15 | <10 | <10 | +| Stale Issues | 25 | 0 | 0 | 0 | +| Response Time | Variable | <1 week | <3 days | <3 days | +| Issues with Labels | 50% | 100% | 100% | 100% | + +### Code Quality +| Metric | Current | 1 Month | 3 Months | 6 Months | +|--------|---------|---------|----------|----------| +| Clean Files | 50 | 100 | 250 | 400+ | +| Pre-commit Coverage | 15% | 30% | 60% | 80%+ | +| Shellcheck Pass | ~15% | ~30% | ~60% | 80%+ | +| Test Coverage | Good | Good | Better | 70%+ | + +### Project Health +| Metric | Current | 1 Month | 3 Months | 6 Months | +|--------|---------|---------|----------|----------| +| Documentation | Fair | Good | Good | Excellent | +| Contributor Guidelines | Basic | Clear | Clear | Comprehensive | +| Distribution | Git only | Git only | Git only | + Homebrew | +| Active Contributors | Few | Growing | Growing | Community | + +--- + +## Risk Management + +### Risks & Mitigations + +#### Risk: Closing issues angers contributors +**Mitigation**: +- Polite closure messages +- Clear "reopen if relevant" policy +- Respond promptly to reopens + +#### Risk: Pre-commit slows down contributors +**Mitigation**: +- Clear docs on running pre-commit +- Auto-fix where possible (shfmt -w) +- Allow incremental improvement + +#### Risk: Feature decisions split community +**Mitigation**: +- Be transparent about reasoning +- Accept feedback, be willing to reverse +- Plugins are optional - defaults matter less + +#### Risk: Packaging creates maintenance burden +**Mitigation**: +- Start with Homebrew only +- Automate release process +- Only pursue if demand is real + +--- + +## Timeline Summary + +``` +Month 1: Quick Wins + Issue Cleanup + Week 1-2: Fix 5 bugs + Week 3-4: Close 18 stale issues + +Month 2: Decisions + Pre-commit Start + Week 5-6: Make strategic decisions + Week 7-8: Clean core files + +Month 3: Pre-commit Expansion + Week 9-12: Add 40+ files to clean_files.txt + +Month 4: Documentation + Testing + Week 13-16: Improve docs, add tests + +Month 5-6: Polish + Optional Packaging + Week 17-20: Continue cleanup + Week 21-24: Homebrew formula (if approved) +``` + +--- + +## Resource Requirements + +### Time Investment +- **Maintainer**: 2-4 hours/week decision-making, review +- **Contributor(s)**: 4-8 hours/week implementation +- **Total**: ~6-12 hours/week for 6 months + +### Skills Needed +- Bash scripting (existing) +- Testing with BATS (existing) +- Git workflow (existing) +- GitHub Actions (light, for packaging) +- Homebrew packaging (learn, ~4 hours) + +--- + +## Next Steps + +1. **Review this roadmap** with maintainer(s) +2. **Approve Phase 1** Quick Wins sprint +3. **Decide on stale issue closure** approach +4. **Make strategic decisions** (Phase 3) +5. **Start executing** week by week + +--- + +## Questions for Maintainer + +1. Approve Quick Wins sprint? (5 bug fixes) +2. Approve stale issue closure? (18 issues) +3. Which strategic decisions need discussion? +4. What's the priority: features vs. cleanup? +5. Interest in co-maintainers/trusted contributors? +6. Should I start Phase 1 immediately? diff --git a/docs/themes-list/atomic.rst b/docs/themes-list/atomic.rst index 7d471ba908..73197c29ea 100644 --- a/docs/themes-list/atomic.rst +++ b/docs/themes-list/atomic.rst @@ -36,7 +36,6 @@ Automatically via terminal #. You can install the theme automatically using the ``sed`` command from your Linux or OSX Terminal. -#. On macOS, the ~/.bash_profile is used, not the ~/.bashrc. #. For installation on windows you should use `\ ``Git-Bash`` `_ or make sure the terminal emulator you use (ej: cygwin, mintty, etc) has the ``sed`` command installed. Command to execute For Windows and Linux: @@ -51,7 +50,7 @@ Command to execute for macOS: .. code-block:: bash # Set the "atomic" theme replacing the theme you are using of bash-it - sed -i '' 's/'"$BASH_IT_THEME"'/atomic/g' ~/.bash_profile + sed -i '' 's/'"$BASH_IT_THEME"'/atomic/g' ~/.bashrc Features -------- diff --git a/docs/themes-list/powerline-base.rst b/docs/themes-list/powerline-base.rst index f38f940daa..b23068191f 100644 --- a/docs/themes-list/powerline-base.rst +++ b/docs/themes-list/powerline-base.rst @@ -8,7 +8,7 @@ all powerline themes. **IMPORTANT:** This theme requires that `a font with the Powerline symbols `_ needs to be used in your terminal emulator, otherwise the prompt won't be displayed correctly, i.e. some of the additional icons and characters will be missing. Please follow your operating system's instructions to install one of the fonts from the above link and select it in your terminal emulator. -**NOTICE:** The default behavior of this theme assumes that you have sudo privileges on your workstation. If that is not the case (e.g. if you are running on a corporate network where ``sudo`` usage is tracked), you can set the flag 'export THEME_CHECK_SUDO=false' in your ``~/.bashrc`` or ``~/.bash_profile`` to disable the Powerline theme's ``sudo`` check. This will apply to all ``powerline*`` themes. +**NOTICE:** The default behavior of this theme assumes that you have sudo privileges on your workstation. If that is not the case (e.g. if you are running on a corporate network where ``sudo`` usage is tracked), you can set the flag 'export THEME_CHECK_SUDO=false' in your ``~/.bashrc`` to disable the Powerline theme's ``sudo`` check. This will apply to all ``powerline*`` themes. Provided Information -------------------- @@ -24,7 +24,7 @@ Provided Information * An indicator when connected by SSH * An indicator when ``sudo`` has the credentials cached (see the ``sudo`` manpage for more info about this) * An indicator when the current shell is inside the Vim editor -* Battery charging status (depends on the battery plugin) +* Battery charging status (depends on the battery library) * SCM Repository status (e.g. Git, SVN) * The current Kubernetes environment * The current Python environment (Virtualenv, venv, and Conda are supported) in use diff --git a/docs/themes-list/powerline-multiline.rst b/docs/themes-list/powerline-multiline.rst index f525f02230..2e9aeb36ab 100644 --- a/docs/themes-list/powerline-multiline.rst +++ b/docs/themes-list/powerline-multiline.rst @@ -19,7 +19,7 @@ To get the length of the left and right segments right, a *padding* value is use In most cases, the default value (\ *2*\ ) works fine, but on some operating systems, this needs to be adjusted. One example is *macOS High Sierra*\ , where the default padding causes the right segment to extend to the next line. On macOS High Sierra, the padding value needs to be changed to *3* to make the theme look right. -This can be done by setting the ``POWERLINE_PADDING`` variable before Bash-it is loaded, e.g. in your ``~/.bash_profile`` or ``~/.bashrc`` file: +This can be done by setting the ``POWERLINE_PADDING`` variable before Bash-it is loaded, e.g. in your ``~/.bashrc`` file: .. code-block:: bash diff --git a/docs/vcs_user.rst b/docs/vcs_user.rst index c6d31a5795..1c082de76c 100644 --- a/docs/vcs_user.rst +++ b/docs/vcs_user.rst @@ -10,7 +10,7 @@ Turn version control checking off to prevent slow directory navigation within la Controlling Flags ^^^^^^^^^^^^^^^^^ -Bash-it provides a flag (\ ``SCM_CHECK``\ ) within the ``~/.bash_profile`` file that turns off/on version control information checking and display within all themes. +Bash-it provides a flag (\ ``SCM_CHECK``\ ) within the ``~/.bashrc`` file that turns off/on version control information checking and display within all themes. Version control checking is on by default unless explicitly turned off. Set ``SCM_CHECK`` to 'false' to **turn off** version control checks for all themes: diff --git a/install.sh b/install.sh index 4063f516ed..a99993e4ef 100755 --- a/install.sh +++ b/install.sh @@ -2,7 +2,7 @@ # bash-it installer # Show how to use this installer -function _bash-it_show_usage() { +function _bash-it-install-help() { echo -e "\n$0 : Install bash-it" echo -e "Usage:\n$0 [arguments] \n" echo "Arguments:" @@ -14,76 +14,135 @@ function _bash-it_show_usage() { echo "--overwrite-backup (-f): Overwrite existing backup" } -# enable a thing -function _bash-it_load_one() { - file_type=$1 - file_to_enable=$2 - mkdir -p "$BASH_IT/${file_type}/enabled" - - dest="${BASH_IT}/${file_type}/enabled/${file_to_enable}" - if [ ! -e "${dest}" ]; then - ln -sf "../available/${file_to_enable}" "${dest}" - else - echo "File ${dest} exists, skipping" - fi -} - # Interactively enable several things -function _bash-it_load_some() { +function _bash-it-install-enable() { + local file_type single_type enable_func file_name just_the_name RESP file_type=$1 single_type=$(echo "$file_type" | sed -e "s/aliases$/alias/g" | sed -e "s/plugins$/plugin/g") enable_func="_enable-$single_type" - [ -d "$BASH_IT/$file_type/enabled" ] || mkdir "$BASH_IT/$file_type/enabled" - for path in "$BASH_IT/${file_type}/available/"[^_]*; do - file_name=$(basename "$path") + for path in "${BASH_IT?}/${file_type}/available/"[^_]*; do + file_name="${path##*/}" while true; do - just_the_name="${file_name%%.*}" + just_the_name="${file_name%".${file_type}.bash"}" read -r -e -n 1 -p "Would you like to enable the $just_the_name $file_type? [y/N] " RESP case $RESP in [yY]) - $enable_func "$just_the_name" + "$enable_func" "$just_the_name" break ;; [nN] | "") break ;; *) - echo -e "\033[91mPlease choose y or n.\033[m" + echo -e "${echo_orange:-}Please choose y or n.${echo_normal:-}" ;; esac done done } +# Ensure .bashrc is sourced from profile files on macOS/BSD/Solaris +function _bash-it-install-ensure-bashrc-sourcing() { + # Only needed on platforms where login shells don't source .bashrc + case "$(uname -s)" in + Darwin | SunOS | Illumos | *BSD) ;; + *) return 0 ;; # Not needed on Linux + esac + + # Find which profile file exists + local profile_file + if [[ -f "$HOME/.bash_profile" ]]; then + profile_file="$HOME/.bash_profile" + elif [[ -f "$HOME/.profile" ]]; then + profile_file="$HOME/.profile" + else + # No profile file exists, create .bash_profile + profile_file="$HOME/.bash_profile" + echo -e "${echo_yellow:-}Creating $profile_file to source .bashrc${echo_normal:-}" + fi + + # Check if already sourced (reuse helper from doctor) + if _bash-it-doctor-check-profile-sourcing-grep "$profile_file" 2> /dev/null; then + return 0 # Already configured + fi + + # Not sourced, offer to add it + echo "" + echo -e "${echo_yellow:-}Warning: .bashrc is not sourced from $profile_file${echo_normal:-}" + echo "On macOS/BSD/Solaris, login shells won't load bash-it without this." + echo "" + + local RESP + if [[ -z "${silent:-}" ]]; then + read -r -e -n 1 -p "Would you like to add .bashrc sourcing to $profile_file? [Y/n] " RESP + case $RESP in + [nN]) + echo "" + echo -e "${echo_orange:-}Skipping. You can add this manually later:${echo_normal:-}" + echo "" + echo " if [ -n \"\${BASH_VERSION-}\" ]; then" + echo " if [ -f \"\$HOME/.bashrc\" ]; then" + echo " . \"\$HOME/.bashrc\"" + echo " fi" + echo " fi" + echo "" + return 0 + ;; + esac + fi + + # Backup profile file if it exists + if [[ -f "$profile_file" ]]; then + local backup_file + backup_file="${profile_file}.bak.$(date +%Y%m%d_%H%M%S)" + command cp "$profile_file" "$backup_file" + echo -e "${echo_green:-}Backed up $profile_file to $backup_file${echo_normal:-}" + fi + + # Add the sourcing snippet + cat >> "$profile_file" << 'EOF' + +# Source .bashrc if running bash +if [ -n "${BASH_VERSION-}" ]; then + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi +EOF + + echo -e "${echo_green:-}✓ Added .bashrc sourcing to $profile_file${echo_normal:-}" + echo "" +} + # Back up existing profile -function _bash-it_backup() { - test -w "$HOME/$CONFIG_FILE" \ - && cp -aL "$HOME/$CONFIG_FILE" "$HOME/$CONFIG_FILE.bak" \ - && echo -e "\033[0;32mYour original $CONFIG_FILE has been backed up to $CONFIG_FILE.bak\033[0m" +function _bash-it-install-backup-config() { + test -w "${HOME?}/${CONFIG_FILE?}" \ + && cp -aL "${HOME?}/${CONFIG_FILE?}" "${HOME?}/${CONFIG_FILE?}.bak" \ + && echo -e "${echo_green:-}Your original ${CONFIG_FILE?} has been backed up to ${CONFIG_FILE?}.bak${echo_normal:-}" } # Back up existing profile and create new one for bash-it -function _bash-it_backup_new() { - _bash-it_backup - sed "s|{{BASH_IT}}|$BASH_IT|" "$BASH_IT/template/bash_profile.template.bash" > "$HOME/$CONFIG_FILE" - echo -e "\033[0;32mCopied the template $CONFIG_FILE into ~/$CONFIG_FILE, edit this file to customize bash-it\033[0m" +function _bash-it-install-backup-new() { + _bash-it-install-backup-config + sed "s|{{BASH_IT}}|${BASH_IT?}|" "${BASH_IT?}/template/bashrc.template.bash" > "${HOME?}/${CONFIG_FILE?}" + echo -e "${echo_green:-}Copied the template ${CONFIG_FILE?} into ~/${CONFIG_FILE?}, edit this file to customize bash-it${echo_normal:-}" } # Back up existing profile and append bash-it templates at the end -function _bash-it_backup_append() { - _bash-it_backup - (sed "s|{{BASH_IT}}|$BASH_IT|" "$BASH_IT/template/bash_profile.template.bash" | tail -n +2) >> "$HOME/$CONFIG_FILE" - echo -e "\033[0;32mBash-it template has been added to your $CONFIG_FILE\033[0m" +function _bash-it-install-backup-append() { + _bash-it-install-backup-config + (sed "s|{{BASH_IT}}|${BASH_IT?}|" "${BASH_IT?}/template/bashrc.template.bash" | tail -n +2) >> "${HOME?}/${CONFIG_FILE?}" + echo -e "${echo_green:-}Bash-it template has been added to your ${CONFIG_FILE?}${echo_normal:-}" } -function _bash-it_check_for_backup() { - if ! [[ -e "$HOME/$BACKUP_FILE" ]]; then +function _bash-it-install-backup-check() { + if ! [[ -e "${HOME?}/$BACKUP_FILE" ]]; then return fi - echo -e "\033[0;33mBackup file already exists. Make sure to backup your .bashrc before running this installation.\033[0m" >&2 + echo -e "${echo_yellow:-}Backup file already exists. Make sure to backup your .bashrc before running this installation.${echo_normal:-}" >&2 - if [[ -z "${overwrite_backup}" ]]; then - while [[ -z "${silent}" ]]; do + if [[ -z "${overwrite_backup:-}" ]]; then + while [[ -z "${silent:-}" ]]; do read -e -n 1 -r -p "Would you like to overwrite the existing backup? This will delete your existing backup file ($HOME/$BACKUP_FILE) [y/N] " RESP case $RESP in [yY]) @@ -94,27 +153,27 @@ function _bash-it_check_for_backup() { break ;; *) - echo -e "\033[91mPlease choose y or n.\033[m" + echo -e "${echo_orange:-}Please choose y or n.${echo_normal:-}" ;; esac done fi - if [[ -z "${overwrite_backup}" ]]; then - echo -e "\033[91mInstallation aborted. Please come back soon!\033[m" - if [[ -n "${silent}" ]]; then - echo -e "\033[91mUse \"-f\" flag to force overwrite of backup.\033[m" + if [[ -z "${overwrite_backup:-}" ]]; then + echo -e "${echo_orange:-}Installation aborted. Please come back soon!${echo_normal:-}" + if [[ -n "${silent:-}" ]]; then + echo -e "${echo_orange:-}Use \"-f\" flag to force overwrite of backup.${echo_normal:-}" fi exit 1 else - echo -e "\033[0;32mOverwriting backup...\033[m" + echo -e "${echo_green:-}Overwriting backup...${echo_normal:-}" fi } -function _bash-it_modify_config_files() { - _bash-it_check_for_backup +function _bash-it-install-modify-config() { + _bash-it-install-backup-check - if [[ -z "${silent}" ]]; then - while [[ -z "${append_to_config}" ]]; do + if [[ -z "${silent:-}" ]]; then + while [[ -z "${append_to_config:-}" ]]; do read -e -n 1 -r -p "Would you like to keep your $CONFIG_FILE and append bash-it templates at the end? [y/N] " choice case $choice in [yY]) @@ -125,17 +184,28 @@ function _bash-it_modify_config_files() { break ;; *) - echo -e "\033[91mPlease choose y or n.\033[m" + echo -e "${echo_orange:-}Please choose y or n.${echo_normal:-}" ;; esac done fi - if [[ -n "${append_to_config}" ]]; then + if [[ -n "${append_to_config:-}" ]]; then # backup/append - _bash-it_backup_append + _bash-it-install-backup-append else # backup/new by default - _bash-it_backup_new + _bash-it-install-backup-new + fi + _bash-it-install-modify-profile +} + +function _bash-it-install-modify-profile() { + local choice profile_string=$'if [[ $- == *i* && -s ~/.bashrc ]]; then\n\tsource ~/.bashrc\nfi' + if [[ ! -f ~/.bash_profile ]]; then + printf '%s\n' "${profile_string}" > ~/.bash_profile + else + printf "${echo_yellow:-}%s${echo_normal:-}" "You may need to update your ~/.bash_profile (or ~/.profile) to source your ~/.bashrc:" + printf '%s\n' "${profile_string}" fi } @@ -156,7 +226,7 @@ OPTIND=1 while getopts "hsinaf" opt; do case "$opt" in "h") - _bash-it_show_usage + _bash-it-install-help exit 0 ;; "s") silent=true ;; @@ -165,7 +235,7 @@ while getopts "hsinaf" opt; do "a") append_to_config=true ;; "f") overwrite_backup=true ;; "?") - _bash-it_show_usage >&2 + _bash-it-install-help >&2 exit 1 ;; esac @@ -173,26 +243,19 @@ done shift $((OPTIND - 1)) -if [[ -n "${silent}" && -n "${interactive}" ]]; then - echo -e "\033[91mOptions --silent and --interactive are mutually exclusive. Please choose one or the other.\033[m" +if [[ -n "${silent:-}" && -n "${interactive:-}" ]]; then + echo -e "${echo_orange:-}Options --silent and --interactive are mutually exclusive. Please choose one or the other.${echo_normal:-}" exit 1 fi -if [[ -n "${no_modify_config}" && -n "${append_to_config}" ]]; then - echo -e "\033[91mOptions --no-modify-config and --append-to-config are mutually exclusive. Please choose one or the other.\033[m" +if [[ -n "${no_modify_config:-}" && -n "${append_to_config:-}" ]]; then + echo -e "${echo_orange:-}Options --no-modify-config and --append-to-config are mutually exclusive. Please choose one or the other.${echo_normal:-}" exit 1 fi BASH_IT="$(cd "${BASH_SOURCE%/*}" && pwd)" -case $OSTYPE in - darwin*) - CONFIG_FILE=.bash_profile - ;; - *) - CONFIG_FILE=.bashrc - ;; -esac +CONFIG_FILE=".bashrc" # overriding CONFIG_FILE: CONFIG_FILE="${BASH_IT_CONFIG_FILE:-"${CONFIG_FILE}"}" @@ -201,39 +264,43 @@ if [[ "${CONFIG_FILE%/*}" != "${CONFIG_FILE}" ]]; then mkdir -p "${HOME}/${CONFIG_FILE%/*}" fi -BACKUP_FILE=$CONFIG_FILE.bak +BACKUP_FILE="${CONFIG_FILE?}.bak" echo "Installing bash-it" if [[ -z "${no_modify_config}" ]]; then - _bash-it_modify_config_files + _bash-it-install-modify-config fi # Disable auto-reload in case its enabled export BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE='' # Load dependencies for enabling components -# shellcheck disable=SC1090 -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" +# shellcheck source-path=SCRIPTPATH/vendor/github.com/erichs/composure +source "${BASH_IT}/vendor/github.com/erichs/composure/composure.sh" cite _about _param _example _group _author _version -# shellcheck source=./lib/helpers.bash -source "$BASH_IT/lib/helpers.bash" +# shellcheck source-path=SCRIPTDIR/lib +source "${BASH_IT}/lib/log.bash" +# shellcheck source-path=SCRIPTDIR/lib +source "${BASH_IT?}/lib/utilities.bash" +# shellcheck source-path=SCRIPTDIR/lib +source "${BASH_IT?}/lib/helpers.bash" +# shellcheck source-path=SCRIPTDIR/lib +source "${BASH_IT?}/lib/colors.bash" -if [[ -n $interactive && -z "${silent}" ]]; then +if [[ -n ${interactive:-} && -z "${silent:-}" ]]; then for type in "aliases" "plugins" "completion"; do - echo -e "\033[0;32mEnabling ${type}\033[0m" - _bash-it_load_some "$type" + echo -e "${echo_green:-}Enabling ${type}${echo_normal:-}" + _bash-it-install-enable "$type" done else echo "" _bash-it-profile-load "default" fi +# Ensure .bashrc sourcing is set up on macOS/BSD/Solaris +_bash-it-install-ensure-bashrc-sourcing + echo "" -echo -e "\033[0;32mInstallation finished successfully! Enjoy bash-it!\033[0m" -# shellcheck disable=SC2086 -echo -e "\033[0;32mTo start using it, open a new tab or 'source "~/$CONFIG_FILE"'.\033[0m" +echo -e "${echo_green:-}Installation finished successfully! Enjoy bash-it!${echo_normal:-}" +echo -e "${echo_green:-}To start using it, open a new tab or 'source ~/${CONFIG_FILE?}'.${echo_normal:-}" echo "" echo "To show the available aliases/completions/plugins, type one of the following:" echo " bash-it show aliases" diff --git a/lib/appearance.bash b/lib/appearance.bash deleted file mode 100644 index e77a1a8032..0000000000 --- a/lib/appearance.bash +++ /dev/null @@ -1,18 +0,0 @@ -# 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 diff --git a/plugins/available/battery.plugin.bash b/lib/battery.bash similarity index 100% rename from plugins/available/battery.plugin.bash rename to lib/battery.bash diff --git a/lib/completion.bash b/lib/completion.bash new file mode 100644 index 0000000000..fb74f1f94b --- /dev/null +++ b/lib/completion.bash @@ -0,0 +1,49 @@ +# shellcheck shell=bash +# Functions for working with _Bash_'s Programmable Completion + +# +## +# Testing Completion Functions +## +# + +# + +# +## +# Generating Completion Results +## +# + +# + +# +## +# Loading _Bash It_'s Completion Plugins +## + +function _bash-it-completion-helper-necessary() { + local requirement _result=0 + for requirement in "$@"; do + if ! _binary_exists "${requirement}"; then + _result=1 + fi + done + if [[ ${_result} -gt 0 ]]; then + _log_warning "Without '${!#}' installed, this completion won't be too useful." + fi + return "${_result}" +} + +function _bash-it-completion-helper-sufficient() { + local completion _result=0 + for completion in "$@"; do + if _completion_exists "${completion}"; then + _result=1 + fi + done + if [[ ${_result} -gt 0 ]]; then + _log_warning "completion already loaded - this usually means it is safe to stop using this completion." + fi + return "${_result}" +} diff --git a/lib/helpers.bash b/lib/helpers.bash index 3675b0f259..a6ff1fcd34 100644 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -3,7 +3,7 @@ # # A collection of reusable functions. -: "${BASH_IT_LOAD_PRIORITY_ALIAS:=150}" +: "${BASH_IT_LOAD_PRIORITY_ALIAS:=750}" : "${BASH_IT_LOAD_PRIORITY_PLUGIN:=250}" : "${BASH_IT_LOAD_PRIORITY_COMPLETION:=350}" BASH_IT_LOAD_PRIORITY_SEPARATOR="---" @@ -22,51 +22,6 @@ else BASH_IT_SED_I_PARAMETERS=('-i' '') fi -function _command_exists() { - _about 'checks for existence of a command' - _param '1: command to check' - _param '2: (optional) log message to include when command not found' - _example '$ _command_exists ls && echo exists' - _group 'lib' - local msg="${2:-Command '$1' does not exist}" - if type -t "$1" > /dev/null; then - return 0 - else - _log_debug "$msg" - return 1 - fi -} - -function _binary_exists() { - _about 'checks for existence of a binary' - _param '1: binary to check' - _param '2: (optional) log message to include when binary not found' - _example '$ _binary_exists ls && echo exists' - _group 'lib' - local msg="${2:-Binary '$1' does not exist}" - if type -P "$1" > /dev/null; then - return 0 - else - _log_debug "$msg" - return 1 - fi -} - -function _completion_exists() { - _about 'checks for existence of a completion' - _param '1: command to check' - _param '2: (optional) log message to include when completion is found' - _example '$ _completion_exists gh && echo exists' - _group 'lib' - local msg="${2:-Completion for '$1' already exists}" - if complete -p "$1" &> /dev/null; then - _log_debug "$msg" - return 0 - else - return 1 - fi -} - function _bash_it_homebrew_check() { if _binary_exists 'brew'; then # Homebrew is installed @@ -117,7 +72,7 @@ function bash-it() { 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' + example '$ bash-it doctor errors|warnings|all|summary' local verb=${1:-} shift local component=${1:-} @@ -203,22 +158,6 @@ function bash-it() { fi } -function _is_function() { - _about 'sets $? to true if parameter is the name of a function' - _param '1: name of alleged function' - _param '2: (optional) log message to include when function not found' - _group 'lib' - _example '$ _is_function ls && echo exists' - _group 'lib' - local msg="${2:-Function '$1' does not exist}" - if LC_ALL=C type -t "$1" | _bash-it-fgrep -q 'function'; then - return 0 - else - _log_debug "$msg" - return 1 - fi -} - function _bash-it-aliases() { _about 'summarizes available bash_it aliases' _group 'lib' @@ -295,7 +234,7 @@ function _bash-it-update-() { fi if [[ -z "$BASH_IT_REMOTE" ]]; then - BASH_IT_REMOTE="origin" + BASH_IT_REMOTE=$(_get-git-default-remote-name) fi git fetch "$BASH_IT_REMOTE" --tags &> /dev/null @@ -413,7 +352,7 @@ function _bash-it-version() { pushd "${BASH_IT?}" > /dev/null || return if [[ -z "${BASH_IT_REMOTE:-}" ]]; then - BASH_IT_REMOTE="origin" + BASH_IT_REMOTE=$(_get-git-default-remote-name) fi BASH_IT_GIT_REMOTE="$(git remote get-url "$BASH_IT_REMOTE")" @@ -475,11 +414,293 @@ function _bash-it-doctor-errors() { _bash-it-doctor "${BASH_IT_LOG_LEVEL_ERROR?}" } +function _bash-it-doctor-check-profile-sourcing-grep() { + _about 'checks if .bashrc is sourced from profile using grep' + _param '1: profile file path' + _group 'lib' + + local profile_file="${1}" + [[ ! -f "$profile_file" ]] && return 1 + + # Look for common patterns that source .bashrc + command grep -qE '(source|\.)\s+(~|\$HOME|"\$HOME")?/\.bashrc|if.*BASH_VERSION.*bashrc' "$profile_file" +} + +function _bash-it-doctor-check-profile-sourcing-test() { + _about 'checks if .bashrc is actually sourced using brute force test' + _group 'lib' + + local bashrc="$HOME/.bashrc" + [[ ! -f "$bashrc" ]] && return 1 + + local backup_bashrc="/tmp/.bashrc_backup_$$" + + # Move .bashrc aside + command mv "$bashrc" "$backup_bashrc" 2> /dev/null || return 1 + + # Create test .bashrc that just echoes + echo 'echo "__BASHRC_WAS_SOURCED__"' > "$bashrc" + + # Test in login shell, capture output + local output + output=$(bash -l -c ':' 2>&1) + + # Restore immediately + command mv "$backup_bashrc" "$bashrc" + + # Check if our marker appeared + command grep -q "__BASHRC_WAS_SOURCED__" <<< "$output" +} + +function _bash-it-doctor-check-profile-sourcing() { + _about 'checks if .bashrc is sourced from login shell profile files' + _group 'lib' + + local profile_file + if [[ -f "$HOME/.bash_profile" ]]; then + profile_file="$HOME/.bash_profile" + elif [[ -f "$HOME/.profile" ]]; then + profile_file="$HOME/.profile" + else + echo "${YELLOW}No .bash_profile or .profile found${RESET}" + echo "Login shells may not load bash-it configuration" + return + fi + + # Show if it's a symlink + if [[ -L "$profile_file" ]]; then + echo "${YELLOW}Note:${RESET} $profile_file is a symlink to $(readlink "$profile_file")" + fi + + # Try grep detection first (fast and safe) + if _bash-it-doctor-check-profile-sourcing-grep "$profile_file"; then + echo "${GREEN}✓${RESET} .bashrc is sourced from $profile_file" + return 0 + fi + + # Grep didn't find it, try brute force test + echo "Grep detection unclear, testing if .bashrc actually loads..." + if _bash-it-doctor-check-profile-sourcing-test; then + echo "${GREEN}✓${RESET} .bashrc is sourced (confirmed via test)" + return 0 + fi + + # Not sourced + echo "${RED}✗${RESET} .bashrc is NOT sourced from $profile_file" + echo " ${YELLOW}Warning:${RESET} bash-it will not load in login shells (Terminal.app, SSH sessions)" + echo " ${YELLOW}Fix:${RESET} Add the following to $profile_file:" + echo "" + echo " if [ -n \"\$BASH_VERSION\" ]; then" + echo " if [ -f \"\$HOME/.bashrc\" ]; then" + echo " . \"\$HOME/.bashrc\"" + echo " fi" + echo " fi" + echo "" +} + +function _bash-it-doctor-summary() { + _about 'shows a comprehensive diagnostic summary for bug reports' + _group 'lib' + + local component_type enabled_count enabled_list f component_name + + # Color definitions + local BOLD CYAN GREEN YELLOW RESET + BOLD=$(tput bold 2> /dev/null || echo "") + CYAN=$(tput setaf 6 2> /dev/null || echo "") + GREEN=$(tput setaf 2 2> /dev/null || echo "") + YELLOW=$(tput setaf 3 2> /dev/null || echo "") + RESET=$(tput sgr0 2> /dev/null || echo "") + + echo "${BOLD}${CYAN}Bash-it Doctor Summary${RESET}" + echo "${CYAN}======================${RESET}" + echo "" + + # Environment Information + echo "${BOLD}## Environment${RESET}" + echo "${GREEN}OS:${RESET} $(uname -s) $(uname -r)" + echo "${GREEN}Bash Version:${RESET} ${BASH_VERSION}" + echo "${GREEN}Bash-it Location:${RESET} ${BASH_IT}" + + # Check which config file is used + local config_file + if [[ -n "${BASH_IT_BASHRC:-}" ]]; then + config_file="${BASH_IT_BASHRC}" + elif [[ -f "${HOME}/.bashrc" ]]; then + config_file="${HOME}/.bashrc" + elif [[ -f "${HOME}/.bash_profile" ]]; then + config_file="${HOME}/.bash_profile" + else + config_file="unknown" + fi + echo "${GREEN}Config File:${RESET} ${config_file}" + echo "" + + # Bash-it Version Information + echo "${BOLD}## Bash-it Version${RESET}" + pushd "${BASH_IT}" > /dev/null 2>&1 || { + echo "Error: Cannot access Bash-it directory" + return 1 + } + + local current_commit current_tag commits_behind latest_tag commits_since_tag + current_commit="$(git rev-parse --short HEAD 2> /dev/null || echo 'unknown')" + current_tag="$(git describe --exact-match --tags 2> /dev/null || echo 'none')" + + if [[ -z "${BASH_IT_REMOTE:-}" ]]; then + BASH_IT_REMOTE="origin" + fi + + # Get version info relative to tags + latest_tag="$(git describe --tags --abbrev=0 2> /dev/null || echo 'none')" + commits_since_tag="$(git rev-list --count "${latest_tag}..HEAD" 2> /dev/null || echo '0')" + + if [[ "${current_tag}" != "none" ]]; then + echo "${GREEN}Current Version:${RESET} ${current_tag} (${current_commit})" + elif [[ "${latest_tag}" != "none" && "${commits_since_tag}" != "0" ]]; then + echo "${GREEN}Current Version:${RESET} ${latest_tag} +${commits_since_tag} (${current_commit})" + else + echo "${GREEN}Current Commit:${RESET} ${current_commit}" + fi + + # Check how far behind we are + git fetch "${BASH_IT_REMOTE}" --quiet 2> /dev/null + if [[ -z "${BASH_IT_DEVELOPMENT_BRANCH:-}" ]]; then + BASH_IT_DEVELOPMENT_BRANCH="master" + fi + commits_behind="$(git rev-list --count HEAD.."${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH}" 2> /dev/null || echo 'unknown')" + + if [[ "${commits_behind}" == "0" ]]; then + echo "${GREEN}Status:${RESET} Up to date with ${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH} ✓" + elif [[ "${commits_behind}" != "unknown" ]]; then + echo "${YELLOW}Status:${RESET} ${commits_behind} commits behind ${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH}" + + # Offer to update if behind and it's safe to do so + local git_status untracked_files merge_base can_ff + git_status="$(git status --porcelain 2> /dev/null)" + untracked_files="$(echo "$git_status" | command grep -c '^??' || true)" + + # Check if we can fast-forward + merge_base="$(git merge-base HEAD "${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH}" 2> /dev/null)" + can_ff=false + if [[ "$(git rev-parse HEAD 2> /dev/null)" == "$merge_base" ]]; then + can_ff=true + fi + + # Only offer merge if: + # 1. No modified/staged files (untracked are OK) + # 2. Can fast-forward OR no untracked files that would conflict + if ! echo "$git_status" | command grep -v '^??' -q; then + if [[ "$can_ff" == "true" ]] || [[ "$untracked_files" == "0" ]]; then + echo "" + echo "Would you like to update now? This will merge ${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH} into your current branch." + read -r -p "Update? [y/N] " response + case "$response" in + [yY] | [yY][eE][sS]) + echo "Updating bash-it..." + if git merge "${BASH_IT_REMOTE}/${BASH_IT_DEVELOPMENT_BRANCH}" --ff-only 2> /dev/null; then + echo "✓ Successfully updated to latest version!" + echo "" + echo "Please restart your shell or run: source ~/.bashrc" + else + echo "✗ Fast-forward merge failed. Please run 'bash-it update' for a guided update." + fi + ;; + *) + echo "Skipping update. You can update later with: bash-it update" + ;; + esac + else + echo "" + echo "Note: Cannot safely auto-update (untracked files may conflict). Use: bash-it update" + fi + else + echo "" + echo "Note: Cannot auto-update (uncommitted changes present). Use: bash-it update" + fi + fi + + popd > /dev/null 2>&1 || true + echo "" + + # Bash-it Loading Configuration + echo "${BOLD}## Bash-it Loading${RESET}" + local config_files_to_check=() + local config_file_path + + # Check all common config files + for config_file_path in "${HOME}/.bashrc" "${HOME}/.bash_profile" "${HOME}/.profile"; do + [[ -f "$config_file_path" ]] && config_files_to_check+=("$config_file_path") + done + + if [[ ${#config_files_to_check[@]} -gt 0 ]]; then + for config_file_path in "${config_files_to_check[@]}"; do + if command grep -i "bash.it\|bash_it" "$config_file_path" > /dev/null 2>&1; then + echo "From ${config_file_path}:" + command grep -n -i "bash.it\|bash_it" -B2 -A2 "$config_file_path" 2> /dev/null + echo "" + fi + done + else + echo "No config files found (.bashrc, .bash_profile, .profile)" + fi + + # Profile Sourcing Check (macOS/Solaris/BSD) + echo "${BOLD}## Profile Configuration${RESET}" + case "$(uname -s)" in + Darwin | SunOS | Illumos | *BSD) + _bash-it-doctor-check-profile-sourcing + ;; + *) + echo "Not applicable (Linux uses .bashrc for non-login shells by default)" + ;; + esac + echo "" + + # Enabled Components Summary + echo "${BOLD}## Enabled Components${RESET}" + + # Process each component type + for component_type in aliases plugins completion; do + enabled_count=0 + enabled_list=() + + # Get singular form for display + local display_type="${component_type}" + if [[ "$component_type" == "aliases" ]]; then + display_type="Aliases" + elif [[ "$component_type" == "plugins" ]]; then + display_type="Plugins" + else + display_type="Completions" + fi + + # Count and collect enabled components + for f in "${BASH_IT?}/$component_type/available"/*.*.bash; do + [[ -f "$f" ]] || continue + component_name="$(_bash-it-get-component-name-from-path "$f")" + if _bash-it-component-item-is-enabled "$f"; then + enabled_list+=("$component_name") + ((enabled_count++)) + fi + done + + # Display the summary with colors + if [[ $enabled_count -eq 0 ]]; then + printf '%s%s%s (%s): %s\n' "$CYAN" "$display_type" "$RESET" "$enabled_count" "${YELLOW}none${RESET}" + else + printf '%s%s%s (%s): %s\n' "$CYAN" "$display_type" "$RESET" "$enabled_count" "${enabled_list[*]}" + fi + done + echo "" + echo "${YELLOW}Tip:${RESET} To copy this report: ${CYAN}bash-it doctor${RESET} | pbcopy (macOS) or xclip (Linux)" +} + function _bash-it-doctor-() { - _about 'default bash-it doctor behavior, behaves like bash-it doctor all' + _about 'default bash-it doctor behavior, shows component summary' _group 'lib' - _bash-it-doctor-all + _bash-it-doctor-summary } function _bash-it-profile-save() { @@ -1012,6 +1233,21 @@ function pathmunge() { fi } +function _get-git-default-remote-name() { + local branch + branch=$(command git --git-dir="${BASH_IT?}/.git" --work-tree="${BASH_IT?}" branch --show-current) + + local remote_name= + remote_name=$(command git --git-dir="${BASH_IT?}/.git" --work-tree="${BASH_IT?}" config --get --default '' "branch.$branch.remote") + if [[ -n "$remote_name" ]]; then + printf '%s\n' "$remote_name" + return + fi + + remote_name=$(command git --git-dir="${BASH_IT?}/.git" --work-tree="${BASH_IT?}" remote -v | awk 'NR==1 { print $1 }') + printf '%s\n' "${remote_name:-origin}" +} + # `_bash-it-find-in-ancestor` uses the shell's ability to run a function in # a subshell to simplify our search to a simple `cd ..` and `[[ -r $1 ]]` # without any external dependencies. Let the shell do what it's good at. diff --git a/lib/utilities.bash b/lib/utilities.bash index 75e914b8c6..e6d0d648c7 100644 --- a/lib/utilities.bash +++ b/lib/utilities.bash @@ -78,6 +78,42 @@ function _bash-it-egrep() { "${BASH_IT_GREP:-/usr/bin/grep}" -E "$@" } +function _command_exists() { + : _about 'checks for existence of a command' + : _param '1: command to check' + : _example '$ _command_exists ls && echo exists' + : _group 'lib' + + type -t "${1?}" > /dev/null +} + +function _binary_exists() { + : _about 'checks for existence of a binary' + : _param '1: binary to check' + : _example '$ _binary_exists ls && echo exists' + : _group 'lib' + + type -P "${1?}" > /dev/null +} + +function _completion_exists() { + : _about 'checks for existence of a completion' + : _param '1: command to check' + : _example '$ _completion_exists gh && echo exists' + : _group 'lib' + + complete -p "${1?}" &> /dev/null +} + +function _is_function() { + : _about 'sets $? to true if parameter is the name of a function' + : _param '1: name of alleged function' + : _example '$ _is_function ls && echo exists' + : _group 'lib' + + declare -F "${1?}" > /dev/null +} + ########################################################################### # Component-specific functions (component is either an alias, a plugin, or a # completion). @@ -181,7 +217,7 @@ function _bash-it-component-item-is-enabled() { component_type="${1}" item_name="${2?}" fi - for each_file in "${BASH_IT}/enabled"/*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}${item_name}.${component_type}"*."bash" \ + 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 diff --git a/plugins/available/base.plugin.bash b/plugins/available/base.plugin.bash index 1a905163e4..b9a1f4ca1d 100644 --- a/plugins/available/base.plugin.bash +++ b/plugins/available/base.plugin.bash @@ -16,10 +16,16 @@ function ips() { function down4me() { about 'checks whether a website is down for you, or everybody' - param '1: website url' + param '1: website url or domain' example '$ down4me http://www.google.com' + example '$ down4me google.com' group 'base' - curl -Ls "http://downforeveryoneorjustme.com/$1" | sed '/just you/!d;s/<[^>]*>//g' + # Strip protocol (http:// or https://) if present + local site="${1#http://}" + site="${site#https://}" + # Strip trailing slash if present + site="${site%/}" + command curl -Ls "http://downforeveryoneorjustme.com/${site}" | command sed '/just you/!d;s/<[^>]*>//g' } function myip() { @@ -183,3 +189,19 @@ if ! _command_exists del; then mkdir -p /tmp/.trash && mv "$@" /tmp/.trash } fi + +# replace multiple file extensions at once +function renex() { + about 'mass replace of the extension of multiple files' + param '1: extension to replace' + param '2: new extenstion' + example 'rex txt md' + group 'base' + local ext2replace="${1:-}" + local newext="${2:-}" + local files=(*."$ext2replace") + for file in "${files[@]}"; do + local dst=${file/%."$ext2replace"/."$newext"} + mv "$file" "$dst" + done +} diff --git a/plugins/available/blesh.plugin.bash b/plugins/available/blesh.plugin.bash index 6acd19ff9d..202a4d3bb1 100644 --- a/plugins/available/blesh.plugin.bash +++ b/plugins/available/blesh.plugin.bash @@ -1,8 +1,7 @@ # shellcheck shell=bash -cite about-plugin about-plugin 'load ble.sh, the Bash line editor!' -if [[ ${BLE_VERSION-} ]]; then +if [[ -n "${BLE_VERSION-}" ]]; then _log_warning "ble.sh is already loaded!" return fi @@ -11,6 +10,10 @@ _bash_it_ble_path=${XDG_DATA_HOME:-$HOME/.local/share}/blesh/ble.sh if [[ -f $_bash_it_ble_path ]]; then # shellcheck disable=1090 source "$_bash_it_ble_path" --attach=prompt + if _bash-it-component-item-is-enabled plugin fzf; then + ble-import -d integration/fzf-key-bindings + ble-import -d integration/fzf-completion + fi else _log_error "Could not find ble.sh in $_bash_it_ble_path" _log_error "Please install using the following command:" diff --git a/plugins/available/extract.plugin.bash b/plugins/available/extract.plugin.bash index b43a723271..3ee6821428 100644 --- a/plugins/available/extract.plugin.bash +++ b/plugins/available/extract.plugin.bash @@ -28,9 +28,13 @@ End-Of-Usage done shift $((OPTIND - 1)) - [ $# -eq 0 ] && extract -h && return 1 - while [ $# -gt 0 ]; do - if [[ ! -f "$1" ]]; then + if [[ $# -eq 0 ]]; then + extract -h + return 1 + fi + + while [[ $# -gt 0 ]]; do + if [[ ! -f "${1:-}" ]]; then echo "extract: '$1' is not a valid file" >&2 shift continue @@ -39,23 +43,23 @@ End-Of-Usage local -r filename=$(basename -- "$1") local -r filedirname=$(dirname -- "$1") local targetdirname - # shellcheck disable=SC2001 + # shellcheck disable=SC2001 # we don't depend on `extglob`... targetdirname=$(sed 's/\(\.tar\.bz2$\|\.tbz$\|\.tbz2$\|\.tar\.gz$\|\.tgz$\|\.tar$\|\.tar\.xz$\|\.txz$\|\.tar\.Z$\|\.7z$\|\.nupkg$\|\.zip$\|\.war$\|\.jar$\)//g' <<< "$filename") - if [ "$filename" = "$targetdirname" ]; then + if [[ "$filename" == "$targetdirname" ]]; then # archive type either not supported or it doesn't need dir creation targetdirname="" else mkdir -v "$filedirname/$targetdirname" fi - if [ -f "$1" ]; then + if [[ -f "$1" ]]; then case "$1" in *.tar.bz2 | *.tbz | *.tbz2) tar "x${verbose}jf" "$1" -C "$filedirname/$targetdirname" ;; *.tar.gz | *.tgz) tar "x${verbose}zf" "$1" -C "$filedirname/$targetdirname" ;; *.tar.xz | *.txz) tar "x${verbose}Jf" "$1" -C "$filedirname/$targetdirname" ;; *.tar.Z) tar "x${verbose}Zf" "$1" -C "$filedirname/$targetdirname" ;; *.bz2) bunzip2 "$1" ;; - *.deb) dpkg-deb "-x${verbose}" "$1" "${1:0:-4}" ;; + *.deb) dpkg-deb -x"${verbose}" "$1" "${1:0:-4}" ;; *.pax.gz) gunzip "$1" set -- "$@" "${1:0:-3}" @@ -64,7 +68,7 @@ End-Of-Usage *.pax) pax -r -f "$1" ;; *.pkg) pkgutil --expand "$1" "${1:0:-4}" ;; *.rar) unrar x "$1" ;; - *.rpm) rpm2cpio "$1" | cpio "-idm${verbose}" ;; + *.rpm) rpm2cpio "$1" | cpio -idm"${verbose}" ;; *.tar) tar "x${verbose}f" "$1" -C "$filedirname/$targetdirname" ;; *.xz) xz --decompress "$1" ;; *.zip | *.war | *.jar | *.nupkg) unzip "$1" -d "$filedirname/$targetdirname" ;; @@ -77,3 +81,6 @@ End-Of-Usage shift done } + +# Shorten extract +alias xt='extract' diff --git a/plugins/available/fzf.plugin.bash b/plugins/available/fzf.plugin.bash index 8bb6b63fcb..e6f66676a4 100644 --- a/plugins/available/fzf.plugin.bash +++ b/plugins/available/fzf.plugin.bash @@ -5,13 +5,15 @@ cite about-plugin about-plugin 'load fzf, if you are using it' -if [ -r ~/.fzf.bash ]; then - # shellcheck disable=SC1090 - source ~/.fzf.bash -elif [ -r "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash ]; then - # shellcheck disable=SC1091 - source "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash -fi +if ! _bash-it-component-item-is-enabled plugin blesh; then + if [ -r ~/.fzf.bash ]; then + # shellcheck disable=SC1090 + source ~/.fzf.bash + elif [ -r "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash ]; then + # shellcheck disable=SC1091 + source "${XDG_CONFIG_HOME:-$HOME/.config}"/fzf/fzf.bash + fi +fi # only sources the keybindings and integration if blesh is not integrated already # No need to continue if the command is not present _command_exists fzf || return diff --git a/plugins/available/go.plugin.bash b/plugins/available/go.plugin.bash index 5592a006a7..9c503319f0 100644 --- a/plugins/available/go.plugin.bash +++ b/plugins/available/go.plugin.bash @@ -19,18 +19,14 @@ export GOPATH="${GOPATH:-$(go env GOPATH)}" _bash-it-gopath-pathmunge() { _about 'Ensures paths in GOPATH are added to PATH using pathmunge, with /bin appended' _group 'go' - if [[ -z $GOPATH ]]; then - echo 'GOPATH empty' >&2 + if [[ -z "${GOPATH:-}" ]]; then + _log_warning 'GOPATH empty' return 1 fi - local paths i + local paths apath IFS=: read -r -a paths <<< "$GOPATH" - i=${#paths[@]} - while [[ $i -gt 0 ]]; do - i=$((i - 1)) - if [[ -n "${paths[i]}" ]]; then - pathmunge "${paths[i]}/bin" - fi + for apath in "${paths[@]}"; do + pathmunge "${apath}/bin" || true done } _bash-it-gopath-pathmunge diff --git a/plugins/available/history-eternal.plugin.bash b/plugins/available/history-eternal.plugin.bash index 829868df4a..26bea839e4 100644 --- a/plugins/available/history-eternal.plugin.bash +++ b/plugins/available/history-eternal.plugin.bash @@ -10,13 +10,13 @@ fi # truncating the history file early. # "Numeric values less than zero result in every command being saved on the history list (there is no limit)" -readonly HISTSIZE=-1 2> /dev/null || true +HISTSIZE=-1 2> /dev/null || true # "Non-numeric values and numeric values less than zero inhibit truncation" -readonly HISTFILESIZE='unlimited' 2> /dev/null || true +HISTFILESIZE='unlimited' 2> /dev/null || true # Use a custom history file location so history is not truncated # if the environment ever loses this "eternal" configuration. HISTDIR="${XDG_STATE_HOME:-${HOME?}/.local/state}/bash" [[ -d ${HISTDIR?} ]] || mkdir -p "${HISTDIR?}" -readonly HISTFILE="${HISTDIR?}/history" 2> /dev/null || true +HISTFILE="${HISTDIR?}/history" 2> /dev/null || true diff --git a/plugins/available/man.plugin.bash b/plugins/available/man.plugin.bash index b981565f95..33fd16843d 100644 --- a/plugins/available/man.plugin.bash +++ b/plugins/available/man.plugin.bash @@ -1,14 +1,9 @@ # shellcheck shell=bash about-plugin 'colorize man pages for better readability' -: "${LESS_TERMCAP_mb:=$'\e[1;32m'}" -: "${LESS_TERMCAP_md:=$'\e[1;32m'}" -: "${LESS_TERMCAP_me:=$'\e[0m'}" -: "${LESS_TERMCAP_se:=$'\e[0m'}" -: "${LESS_TERMCAP_so:=$'\e[01;33m'}" -: "${LESS_TERMCAP_ue:=$'\e[0m'}" -: "${LESS_TERMCAP_us:=$'\e[1;4;31m'}" - -: "${LESS:=}" -export "${!LESS_TERMCAP@}" -export LESS="R${LESS#-}" +alias man="\ +LESS_TERMCAP_mb=$'\e[1;32m' \ +LESS_TERMCAP_md=$'\e[1;32m' LESS_TERMCAP_me=$'\e[0m' \ +LESS_TERMCAP_se=$'\e[0m' LESS_TERMCAP_so=$'\e[01;33m' \ +LESS_TERMCAP_ue=$'\e[0m' LESS_TERMCAP_us=$'\e[1;4;31m' \ +LESS=--RAW-CONTROL-CHARS \man" diff --git a/plugins/available/ruby.plugin.bash b/plugins/available/ruby.plugin.bash index aed8daf8cd..37f8ceb529 100644 --- a/plugins/available/ruby.plugin.bash +++ b/plugins/available/ruby.plugin.bash @@ -5,7 +5,9 @@ about-plugin 'ruby and rubygems specific functions and settings' # Make commands installed with 'gem install --user-install' available # ~/.gem/ruby/${RUBY_VERSION}/bin/ if _command_exists ruby && _command_exists gem; then - pathmunge "$(ruby -e 'print Gem.user_dir')/bin" after + pathmunge "$(ruby -e 'print Gem.user_dir')/bin" after || true +else + _log_warning "Unable to load Ruby plugin as a working 'ruby', or 'gem', was not found." fi function remove_gem() { diff --git a/plugins/available/virtualenv.plugin.bash b/plugins/available/virtualenv.plugin.bash index 5bc5c651fc..9f80fbac8f 100644 --- a/plugins/available/virtualenv.plugin.bash +++ b/plugins/available/virtualenv.plugin.bash @@ -5,11 +5,14 @@ cite about-plugin about-plugin 'virtualenvwrapper and pyenv-virtualenvwrapper helper functions' -if _command_exists pyenv; then +# Check for whole command instead of just pyenv +if [ -n "$(command pyenv virtualenvwrapper --help 2> /dev/null)" ]; then pyenv virtualenvwrapper elif _command_exists virtualenvwrapper.sh; then # shellcheck disable=SC1091 source virtualenvwrapper.sh +else + _log_debug "${2:-'virtualenvwrapper' was not found}" fi function mkvenv { diff --git a/plugins/available/xterm.plugin.bash b/plugins/available/xterm.plugin.bash index 740460e491..168081f253 100644 --- a/plugins/available/xterm.plugin.bash +++ b/plugins/available/xterm.plugin.bash @@ -2,7 +2,7 @@ cite about-plugin about-plugin 'automatically set your xterm title with host and location info' -_short-dirname() { +function _short-dirname() { local dir_name="${PWD/~/\~}" if [[ "${SHORT_TERM_LINE:-}" == true && "${#dir_name}" -gt 8 ]]; then echo "${dir_name##*/}" @@ -11,7 +11,7 @@ _short-dirname() { fi } -_short-command() { +function _short-command() { local input_command="$*" if [[ "${SHORT_TERM_LINE:-}" == true && "${#input_command}" -gt 8 ]]; then echo "${input_command%% *}" @@ -20,16 +20,16 @@ _short-command() { fi } -set_xterm_title() { +function set_xterm_title() { local title="${1:-}" echo -ne "\033]0;${title}\007" } -precmd_xterm_title() { +function precmd_xterm_title() { set_xterm_title "${SHORT_USER:-${USER}}@${SHORT_HOSTNAME:-${HOSTNAME}} $(_short-dirname) ${PROMPT_CHAR:-\$}" } -preexec_xterm_title() { +function preexec_xterm_title() { local command_line="${BASH_COMMAND:-${1:-}}" local directory_name short_command directory_name="$(_short-dirname)" @@ -38,8 +38,24 @@ preexec_xterm_title() { } case "${TERM:-dumb}" in - xterm* | rxvt*) - precmd_functions+=(precmd_xterm_title) - preexec_functions+=(preexec_xterm_title) + xterm* | rxvt* | gnome-terminal | konsole | zvt | dtterm | kterm | Eterm | zterm) + # Check for safe_append functions and use fallback if not available + if _is_function safe_append_prompt_command; then + safe_append_prompt_command 'precmd_xterm_title' + elif [[ -n "${PROMPT_COMMAND:-}" ]]; then + # Fallback: append to PROMPT_COMMAND if it exists + PROMPT_COMMAND="precmd_xterm_title;${PROMPT_COMMAND}" + else + PROMPT_COMMAND='precmd_xterm_title' + fi + + if _is_function safe_append_preexec; then + safe_append_preexec 'preexec_xterm_title' + else + # Fallback: register function directly if preexec array is available + if [[ -n "${preexec_functions:-}" ]]; then + preexec_functions+=('preexec_xterm_title') + fi + fi ;; esac diff --git a/profiles/default.bash_it b/profiles/default.bash_it index 9a55f6c7de..7985e501a9 100644 --- a/profiles/default.bash_it +++ b/profiles/default.bash_it @@ -10,3 +10,6 @@ completion system # aliases aliases general +aliases bash-it +aliases directory +aliases editor diff --git a/template/bash_profile.template.bash b/template/bashrc.template.bash old mode 100755 new mode 100644 similarity index 68% rename from template/bash_profile.template.bash rename to template/bashrc.template.bash index c331dd8964..4b07c32fed --- a/template/bash_profile.template.bash +++ b/template/bashrc.template.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # If not running interactively, don't do anything case $- in @@ -7,7 +8,7 @@ case $- in esac # Path to the bash it configuration -export BASH_IT="{{BASH_IT}}" +BASH_IT="{{BASH_IT}}" # Lock and Load a custom theme file. # Leave empty to disable theming. @@ -20,14 +21,14 @@ export BASH_IT_THEME='bobby' # (Advanced): Change this to the name of your remote repo if you # cloned bash-it with a remote other than origin such as `bash-it`. -# export BASH_IT_REMOTE='bash-it' +#BASH_IT_REMOTE='bash-it' # (Advanced): Change this to the name of the main development branch if # you renamed it or if it was changed for some reason -# export BASH_IT_DEVELOPMENT_BRANCH='master' +#BASH_IT_DEVELOPMENT_BRANCH='master' # Your place for hosting Git repos. I use this for private repos. -export GIT_HOSTING='git@git.domain.com' +#GIT_HOSTING='git@git.domain.com' # Don't check mail when opening terminal. unset MAILCHECK @@ -36,49 +37,40 @@ unset MAILCHECK export IRC_CLIENT='irssi' # Set this to the command you use for todo.txt-cli -export TODO="t" +TODO="t" # Set this to the location of your work or project folders #BASH_IT_PROJECT_PATHS="${HOME}/Projects:/Volumes/work/src" # Set this to false to turn off version control status checking within the prompt for all themes -export SCM_CHECK=true +#SCM_CHECK=true + # Set to actual location of gitstatus directory if installed -#export SCM_GIT_GITSTATUS_DIR="$HOME/gitstatus" +#SCM_GIT_GITSTATUS_DIR="$HOME/gitstatus" # per default gitstatus uses 2 times as many threads as CPU cores, you can change this here if you must #export GITSTATUS_NUM_THREADS=8 -# Set Xterm/screen/Tmux title with only a short hostname. -# Uncomment this (or set SHORT_HOSTNAME to something else), -# Will otherwise fall back on $HOSTNAME. -#export SHORT_HOSTNAME=$(hostname -s) - -# Set Xterm/screen/Tmux title with only a short username. -# Uncomment this (or set SHORT_USER to something else), -# Will otherwise fall back on $USER. -#export SHORT_USER=${USER:0:8} - # If your theme use command duration, uncomment this to # enable display of last command duration. -#export BASH_IT_COMMAND_DURATION=true +#BASH_IT_COMMAND_DURATION=true # You can choose the minimum time in seconds before # command duration is displayed. -#export COMMAND_DURATION_MIN_SECONDS=1 +#COMMAND_DURATION_MIN_SECONDS=1 # Set Xterm/screen/Tmux title with shortened command and directory. # Uncomment this to set. -#export SHORT_TERM_LINE=true +#SHORT_TERM_LINE=true # Set vcprompt executable path for scm advance info in prompt (demula theme) # https://github.com/djl/vcprompt -#export VCPROMPT_EXECUTABLE=~/.vcprompt/bin/vcprompt +#VCPROMPT_EXECUTABLE=~/.vcprompt/bin/vcprompt # (Advanced): Uncomment this to make Bash-it reload itself automatically # after enabling or disabling aliases, plugins, and completions. -# export BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE=1 +# BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE=1 # Uncomment this to make Bash-it create alias reload. -# export BASH_IT_RELOAD_LEGACY=1 +# BASH_IT_RELOAD_LEGACY=1 # Load Bash It -source "$BASH_IT"/bash_it.sh +source "${BASH_IT?}/bash_it.sh" diff --git a/test/bash_it/bash_it.bats b/test/bash_it/bash_it.bats index e43ab988cd..c86e043e46 100644 --- a/test/bash_it/bash_it.bats +++ b/test/bash_it/bash_it.bats @@ -14,18 +14,23 @@ function local_setup_file() { } @test "bash-it: load aliases in order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/aliases/enabled/750---a.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/aliases/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---b.aliases.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -34,18 +39,23 @@ function local_setup_file() { } @test "bash-it: load aliases in priority order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/175---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/175---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/175---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/aliases/enabled/755---a.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/755---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/aliases/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---b.aliases.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -54,20 +64,27 @@ function local_setup_file() { } @test "bash-it: load aliases and plugins in priority order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/aliases/enabled/750---a.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/aliases/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---b.aliases.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/plugins/enabled/250---c.plugin.bash" + assert_link_exist "$BASH_IT/plugins/enabled/250---c.plugin.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -76,20 +93,27 @@ function local_setup_file() { } @test "bash-it: load aliases, plugins and completions in priority order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/completion/enabled/350---b.completion.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/completion/enabled/350---b.completion.bash" assert_link_exist "${BASH_IT?}/completion/enabled/350---b.completion.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/aliases/enabled/750---a.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/completion/enabled/350---b.completion.bash" + assert_link_exist "$BASH_IT/completion/enabled/350---b.completion.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/plugins/enabled/250---c.plugin.bash" + assert_link_exist "$BASH_IT/plugins/enabled/250---c.plugin.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -99,14 +123,14 @@ function local_setup_file() { } @test "bash-it: load aliases, plugins and completions in priority order, even if the priority says otherwise" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/450---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/450---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/450---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/completion/enabled/350---b.completion.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/completion/enabled/350---b.completion.bash" assert_link_exist "${BASH_IT?}/completion/enabled/350---b.completion.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/950---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/950---c.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/950---c.plugin.bash" # The `test_alias` alias should not exist @@ -122,20 +146,27 @@ function local_setup_file() { } @test "bash-it: load aliases and plugins in priority order, with one alias higher than plugins" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/350---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/aliases/enabled/350---a.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/350---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---c.plugin.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/aliases/enabled/350---a.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/350---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/aliases/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---b.aliases.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/plugins/enabled/250---c.plugin.bash" + assert_link_exist "$BASH_IT/plugins/enabled/250---c.plugin.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -146,18 +177,23 @@ function local_setup_file() { } @test "bash-it: load global aliases in order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/150---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/150---a.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---b.aliases.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/enabled/750---a.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---b.aliases.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -166,18 +202,23 @@ function local_setup_file() { } @test "bash-it: load global aliases in priority order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/175---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/175---a.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/175---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---b.aliases.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/enabled/755---a.aliases.bash" + assert_link_exist "$BASH_IT/enabled/755---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---b.aliases.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -186,20 +227,27 @@ function local_setup_file() { } @test "bash-it: load global aliases and plugins in priority order" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/150---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/150---a.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---b.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---c.plugin.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/enabled/755---a.aliases.bash" + assert_link_exist "$BASH_IT/enabled/755---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---b.aliases.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/enabled/850---c.plugin.bash" + assert_link_exist "$BASH_IT/enabled/850---c.plugin.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -208,20 +256,27 @@ function local_setup_file() { } @test "bash-it: load global aliases and plugins in priority order, with one alias higher than plugins" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/350---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/350---a.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/350---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---b.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---c.plugin.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/enabled/950---a.aliases.bash" + assert_link_exist "$BASH_IT/enabled/950---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---b.aliases.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/enabled/850---c.plugin.bash" + assert_link_exist "$BASH_IT/enabled/850---c.plugin.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -232,23 +287,33 @@ function local_setup_file() { } @test "bash-it: load global aliases and plugins in priority order, individual old directories are loaded later" { - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/350---a.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/a.aliases.bash" "${BASH_IT?}/enabled/350---a.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/350---a.aliases.bash" - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---b.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/c.plugin.bash" "${BASH_IT?}/enabled/250---c.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---c.plugin.bash" # Add one file in the old directory structure - ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/b.aliases.bash" "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---b.aliases.bash" # The `test_alias` alias should not exist run alias test_alias &> /dev/null assert_failure + run ln -s "$BASH_IT/aliases/available/a.aliases.bash" "$BASH_IT/enabled/350---a.aliases.bash" + assert_link_exist "$BASH_IT/enabled/350---a.aliases.bash" + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---b.aliases.bash" + run ln -s "$BASH_IT/plugins/available/c.plugin.bash" "$BASH_IT/enabled/250---c.aplugin.bash" + assert_link_exist "$BASH_IT/enabled/250---c.plugin.bash" + # Add one file in the old directory structure + run ln -s "$BASH_IT/aliases/available/b.aliases.bash" "$BASH_IT/aliases/enabled/750---b.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---b.aliases.bash" + load "${BASH_IT?}/bash_it.sh" run alias test_alias &> /dev/null @@ -259,11 +324,17 @@ function local_setup_file() { } @test "bash-it: load enabled aliases from new structure, priority-based" { - ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/enabled/150---atom.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/enabled/150---atom.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/150---atom.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" + mkdir -p "$BASH_IT/enabled" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---atom.aliases.bash" + run ln -s "$BASH_IT/plugins/available/base.plugin.bash" "$BASH_IT/enabled/250---base.plugin.bash" + assert_link_exist "$BASH_IT/enabled/250---base.plugin.bash" + # The `ah` alias should not exist run alias ah &> /dev/null assert_failure @@ -275,11 +346,18 @@ function local_setup_file() { } @test "bash-it: load enabled aliases from old structure, priority-based" { - ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/aliases/enabled/150---atom.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/aliases/enabled/150---atom.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/150---atom.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---base.plugin.bash" + mkdir -p "$BASH_IT/aliases/enabled" + mkdir -p "$BASH_IT/plugins/enabled" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/aliases/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---atom.aliases.bash" + run ln -s "$BASH_IT/plugins/available/base.plugin.bash" "$BASH_IT/plugins/enabled/250---base.plugin.bash" + assert_link_exist "$BASH_IT/plugins/enabled/250---base.plugin.bash" + # The `ah` alias should not exist run alias ah &> /dev/null assert_failure @@ -291,9 +369,9 @@ function local_setup_file() { } @test "bash-it: load enabled aliases from old structure, without priorities" { - ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/aliases/enabled/atom.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/atom.aliases.bash" "${BASH_IT?}/aliases/enabled/atom.aliases.bash" assert_link_exist "${BASH_IT?}/aliases/enabled/atom.aliases.bash" - ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/base.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/base.plugin.bash" "${BASH_IT?}/plugins/enabled/base.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/base.plugin.bash" # The `ah` alias should not exist diff --git a/test/completion/bash-it.completion.bats b/test/completion/bash-it.completion.bats index 8ee9ef0722..56e4b341c3 100644 --- a/test/completion/bash-it.completion.bats +++ b/test/completion/bash-it.completion.bats @@ -169,8 +169,8 @@ function __check_completion() { } @test "completion bash-it: disable - provide the a* aliases when atom is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/aliases/enabled/150---atom.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---atom.aliases.bash" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/aliases/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---atom.aliases.bash" run ln -s "$BASH_IT/completion/available/apm.completion.bash" "$BASH_IT/completion/enabled/350---apm.completion.bash" assert_link_exist "$BASH_IT/completion/enabled/350---apm.completion.bash" @@ -180,8 +180,8 @@ function __check_completion() { } @test "completion bash-it: disable - provide the a* aliases when atom is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/enabled/150---atom.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---atom.aliases.bash" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---atom.aliases.bash" run ln -s "$BASH_IT/completion/available/apm.completion.bash" "$BASH_IT/enabled/350---apm.completion.bash" assert_link_exist "$BASH_IT/enabled/350---apm.completion.bash" @@ -202,8 +202,8 @@ function __check_completion() { } @test "completion bash-it: disable - provide the docker-machine plugin when docker-machine is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" run ln -s "$BASH_IT/plugins/available/docker-machine.plugin.bash" "$BASH_IT/plugins/enabled/350---docker-machine.plugin.bash" assert_link_exist "$BASH_IT/plugins/enabled/350---docker-machine.plugin.bash" @@ -213,8 +213,8 @@ function __check_completion() { } @test "completion bash-it: disable - provide the docker-machine plugin when docker-machine is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---docker-compose.aliases.bash" run ln -s "$BASH_IT/plugins/available/docker-machine.plugin.bash" "$BASH_IT/enabled/350---docker-machine.plugin.bash" assert_link_exist "$BASH_IT/enabled/350---docker-machine.plugin.bash" @@ -224,36 +224,36 @@ function __check_completion() { } @test "completion bash-it: disable - provide the todo.txt-cli aliases when todo plugin is enabled with the old location and name" { - run ln -s "$BASH_IT/aliases/available/todo.txt-cli.aliases.bash" "$BASH_IT/aliases/enabled/todo.txt-cli.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/todo.txt-cli.aliases.bash" + run ln -s "$BASH_IT/aliases/available/todo.aliases.bash" "$BASH_IT/aliases/enabled/todo.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/todo.aliases.bash" run ln -s "$BASH_IT/plugins/available/todo.plugin.bash" "$BASH_IT/plugins/enabled/todo.plugin.bash" assert_link_exist "$BASH_IT/plugins/enabled/todo.plugin.bash" run __check_completion 'bash-it disable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } @test "completion bash-it: disable - provide the todo.txt-cli aliases when todo plugin is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/todo.txt-cli.aliases.bash" "$BASH_IT/aliases/enabled/150---todo.txt-cli.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---todo.txt-cli.aliases.bash" + run ln -s "$BASH_IT/aliases/available/todo.aliases.bash" "$BASH_IT/aliases/enabled/750---todo.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---todo.aliases.bash" run ln -s "$BASH_IT/plugins/available/todo.plugin.bash" "$BASH_IT/plugins/enabled/350---todo.plugin.bash" assert_link_exist "$BASH_IT/plugins/enabled/350---todo.plugin.bash" run __check_completion 'bash-it disable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } @test "completion bash-it: disable - provide the todo.txt-cli aliases when todo plugin is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/todo.txt-cli.aliases.bash" "$BASH_IT/enabled/150---todo.txt-cli.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---todo.txt-cli.aliases.bash" + run ln -s "$BASH_IT/aliases/available/todo.aliases.bash" "$BASH_IT/enabled/750---todo.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---todo.aliases.bash" run ln -s "$BASH_IT/plugins/available/todo.plugin.bash" "$BASH_IT/enabled/350---todo.plugin.bash" assert_link_exist "$BASH_IT/enabled/350---todo.plugin.bash" run __check_completion 'bash-it disable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } @test "completion bash-it: enable - provide the atom aliases when not enabled" { @@ -275,16 +275,16 @@ function __check_completion() { } @test "completion bash-it: enable - provide the a* aliases when atom is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/aliases/enabled/150---atom.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---atom.aliases.bash" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/aliases/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---atom.aliases.bash" run __check_completion 'bash-it enable alias a' assert_output "all ag ansible apt" } @test "completion bash-it: enable - provide the a* aliases when atom is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/enabled/150---atom.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---atom.aliases.bash" + run ln -s "$BASH_IT/aliases/available/atom.aliases.bash" "$BASH_IT/enabled/750---atom.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---atom.aliases.bash" run __check_completion 'bash-it enable alias a' assert_output "all ag ansible apt" @@ -299,16 +299,16 @@ function __check_completion() { } @test "completion bash-it: enable - provide the docker-* plugins when docker-compose is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" run __check_completion 'bash-it enable plugin docker' assert_output "docker docker-compose docker-machine" } @test "completion bash-it: enable - provide the docker-* plugins when docker-compose is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---docker-compose.aliases.bash" run __check_completion 'bash-it enable plugin docker' assert_output "docker docker-compose docker-machine" @@ -323,16 +323,16 @@ function __check_completion() { } @test "completion bash-it: enable - provide the docker* completions when docker-compose is enabled with the old location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/aliases/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/aliases/enabled/750---docker-compose.aliases.bash" run __check_completion 'bash-it enable completion docker' assert_output "docker docker-compose docker-machine" } @test "completion bash-it: enable - provide the docker* completions when docker-compose is enabled with the new location and priority-based name" { - run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/150---docker-compose.aliases.bash" - assert_link_exist "$BASH_IT/enabled/150---docker-compose.aliases.bash" + run ln -s "$BASH_IT/aliases/available/docker-compose.aliases.bash" "$BASH_IT/enabled/750---docker-compose.aliases.bash" + assert_link_exist "$BASH_IT/enabled/750---docker-compose.aliases.bash" run __check_completion 'bash-it enable completion docker' assert_output "docker docker-compose docker-machine" @@ -343,7 +343,7 @@ function __check_completion() { assert_link_exist "$BASH_IT/plugins/enabled/todo.plugin.bash" run __check_completion 'bash-it enable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } @test "completion bash-it: enable - provide the todo.txt-cli aliases when todo plugin is enabled with the old location and priority-based name" { @@ -351,7 +351,7 @@ function __check_completion() { assert_link_exist "$BASH_IT/plugins/enabled/350---todo.plugin.bash" run __check_completion 'bash-it enable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } @test "completion bash-it: enable - provide the todo.txt-cli aliases when todo plugin is enabled with the new location and priority-based name" { @@ -359,5 +359,5 @@ function __check_completion() { assert_link_exist "$BASH_IT/enabled/350---todo.plugin.bash" run __check_completion 'bash-it enable alias to' - assert_output "todo.txt-cli" + assert_output "todo" } diff --git a/test/install/install.bats b/test/install/install.bats old mode 100644 new mode 100755 index 5288907e8f..3b483bc99b --- a/test/install/install.bats +++ b/test/install/install.bats @@ -8,15 +8,7 @@ function local_setup() { function local_setup_file() { # Determine which config file to use based on OS. - case $OSTYPE in - darwin*) - export BASH_IT_CONFIG_FILE=.bash_profile - ;; - *) - export BASH_IT_CONFIG_FILE=.bashrc - ;; - esac - # don't load any libraries as the tests here test the *whole* kit + export BASH_IT_CONFIG_FILE=.bashrc } @test "install: verify that the install script exists" { @@ -30,7 +22,7 @@ function local_setup_file() { assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE" - assert_link_exist "${BASH_IT?}/enabled/150---general.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---general.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/800---aliases.completion.bash" assert_link_exist "${BASH_IT?}/enabled/350---bash-it.completion.bash" @@ -85,5 +77,5 @@ function local_setup_file() { run cat "$HOME/$BASH_IT_CONFIG_FILE" assert_line "test file content" - assert_line "source \"\$BASH_IT\"/bash_it.sh" + assert_line "source \"\${BASH_IT?}/bash_it.sh\"" } diff --git a/test/install/uninstall.bats b/test/install/uninstall.bats index 48ad21623f..ef3c9d157a 100644 --- a/test/install/uninstall.bats +++ b/test/install/uninstall.bats @@ -23,41 +23,82 @@ function local_setup_file() { assert_file_exist "${BASH_IT?}/uninstall.sh" } -@test "uninstall: run the uninstall script with an existing backup file" { +@test "uninstall: run the uninstall script with existing backup 'bashrc'" { local md5_bak md5_conf cd "${BASH_IT?}" - echo "test file content for backup" > "$HOME/$BASH_IT_CONFIG_FILE.bak" - echo "test file content for original file" > "$HOME/$BASH_IT_CONFIG_FILE" - md5_bak=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') + echo "test file cont BASH_IT_COent for backup" > "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + echo "test file content for original BASH_IT file" > "${HOME?}/$BASH_IT_CONFIG_FILE" + md5_bak=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') - run ./uninstall.sh + run "${BASH_IT?}/uninstall.sh" assert_success + assert_output --partial "Your original ~/$BASH_IT_CONFIG_FILE has been restored." - assert_file_not_exist "$HOME/$BASH_IT_CONFIG_FILE.uninstall" - assert_file_not_exist "$HOME/$BASH_IT_CONFIG_FILE.bak" - assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + assert_file_exist "${HOME?}/$BASH_IT_CONFIG_FILE" - md5_conf=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + md5_conf=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE" | awk '{print $1}') assert_equal "$md5_bak" "$md5_conf" } -@test "uninstall: run the uninstall script without an existing backup file" { +@test "uninstall: run the uninstall script with existing backup 'bash_profile'" { + local md5_bak md5_conf + BASH_IT_CONFIG_FILE=.bash_profile + + echo "test file content for backup file" > "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + echo "test file content for original BASH_IT file" > "${HOME?}/$BASH_IT_CONFIG_FILE" + md5_bak=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') + + run "${BASH_IT?}/uninstall.sh" + assert_success + + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + assert_file_exist "${HOME?}/$BASH_IT_CONFIG_FILE" + + md5_conf=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + + assert_equal "$md5_bak" "$md5_conf" +} + +@test "uninstall: run the uninstall script without existing backup 'bashrc" { local md5_orig md5_uninstall - cd "${BASH_IT?}" + BASH_IT_CONFIG_FILE=.bashrc + + echo "test file content for original BASH_IT file" > "${HOME?}/$BASH_IT_CONFIG_FILE" + md5_orig=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + + run "${BASH_IT?}/uninstall.sh" + assert_success + + assert_file_exist "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE" + + md5_uninstall=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" | awk '{print $1}') + + assert_equal "$md5_orig" "$md5_uninstall" +} + +@test "uninstall: run the uninstall script without existing backup 'bash_profile" { + local md5_orig md5_uninstall + BASH_IT_CONFIG_FILE=.bash_profile + + echo "test file content for original BASH_IT file" > "${HOME?}/$BASH_IT_CONFIG_FILE" + md5_orig=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE" | awk '{print $1}') - echo "test file content for original file" > "$HOME/$BASH_IT_CONFIG_FILE" - md5_orig=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + run "${BASH_IT?}/uninstall.sh" - run ./uninstall.sh assert_success - assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE.uninstall" - assert_file_not_exist "$HOME/$BASH_IT_CONFIG_FILE.bak" - assert_file_not_exist "$HOME/$BASH_IT_CONFIG_FILE" + assert_file_exist "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE.bak" + assert_file_not_exist "${HOME?}/$BASH_IT_CONFIG_FILE" - md5_uninstall=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE.uninstall" | awk '{print $1}') + md5_uninstall=$(md5sum "${HOME?}/$BASH_IT_CONFIG_FILE.uninstall" | awk '{print $1}') assert_equal "$md5_orig" "$md5_uninstall" } diff --git a/test/plugins/battery.plugin.bats b/test/lib/battery.bats similarity index 99% rename from test/plugins/battery.plugin.bats rename to test/lib/battery.bats index aa4aef5471..3fed46be15 100644 --- a/test/plugins/battery.plugin.bats +++ b/test/lib/battery.bats @@ -4,7 +4,7 @@ load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" function local_setup_file() { setup_libs "helpers" - load "${BASH_IT?}/plugins/available/battery.plugin.bash" + load "${BASH_IT?}/lib/battery.bash" } # Sets up the `_command_exists` function so that it only responds `true` if called with diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats index 5806ac552d..f813e16389 100644 --- a/test/lib/helpers.bats +++ b/test/lib/helpers.bats @@ -19,48 +19,6 @@ function local_setup() { assert_file_exist "${BASH_IT?}/profiles/test-bad-type.bash_it" } -@test "helpers: _command_exists function exists" { - run type -t _command_exists - assert_success - assert_output "function" -} - -@test "helpers: _command_exists function positive test ls" { - run _command_exists ls - assert_success -} - -@test "helpers: _command_exists function positive test bash-it" { - run _command_exists bash-it - assert_success -} - -@test "helpers: _command_exists function negative test" { - run _command_exists __addfkds_dfdsjdf - assert_failure -} - -@test "helpers: _binary_exists function exists" { - run type -t _binary_exists - assert_success - assert_output "function" -} - -@test "helpers: _binary_exists function positive test ls" { - run _binary_exists ls - assert_success -} - -@test "helpers: _binary_exists function negative test function" { - run _binary_exists _binary_exists - assert_failure -} - -@test "helpers: _binary_exists function negative test" { - run _binary_exists __addfkds_dfdsjdf - assert_failure -} - @test "helpers: bash-it help aliases ag" { run bash-it help aliases "ag" assert_line -n 0 "ag='ag --smart-case --pager=\"less -MIRFX'" @@ -82,40 +40,40 @@ function local_setup() { } @test "helpers: bash-it help list aliases with ag aliases enabled" { - ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/aliases/enabled/150---ag.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/150---ag.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/aliases/enabled/750---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/750---ag.aliases.bash" - run _help-list-aliases "${BASH_IT?}/aliases/enabled/150---ag.aliases.bash" + run _help-list-aliases "${BASH_IT?}/aliases/enabled/750---ag.aliases.bash" assert_line -n 0 "ag:" } -@test "helpers: bash-it help list aliases with todo.txt-cli aliases enabled" { - ln -s "${BASH_IT?}/aliases/available/todo.txt-cli.aliases.bash" "${BASH_IT?}/aliases/enabled/150---todo.txt-cli.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/150---todo.txt-cli.aliases.bash" +@test "helpers: bash-it help list aliases with todo aliases enabled" { + ln -s "${BASH_IT?}/aliases/available/todo.aliases.bash" "${BASH_IT?}/aliases/enabled/750---todo.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/750---todo.aliases.bash" - run _help-list-aliases "${BASH_IT?}/aliases/enabled/150---todo.txt-cli.aliases.bash" - assert_line -n 0 "todo.txt-cli:" + run _help-list-aliases "${BASH_IT?}/aliases/enabled/750---todo.aliases.bash" + assert_line -n 0 "todo:" } @test "helpers: bash-it help list aliases with docker-compose aliases enabled" { - ln -s "${BASH_IT?}/aliases/available/docker-compose.aliases.bash" "${BASH_IT?}/aliases/enabled/150---docker-compose.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/150---docker-compose.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/docker-compose.aliases.bash" "${BASH_IT?}/aliases/enabled/750---docker-compose.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/750---docker-compose.aliases.bash" - run _help-list-aliases "${BASH_IT?}/aliases/enabled/150---docker-compose.aliases.bash" + run _help-list-aliases "${BASH_IT?}/aliases/enabled/750---docker-compose.aliases.bash" assert_line -n 0 "docker-compose:" } @test "helpers: bash-it help list aliases with ag aliases enabled in global directory" { - ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/enabled/150---ag.aliases.bash" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/enabled/750---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" - run _help-list-aliases "${BASH_IT?}/enabled/150---ag.aliases.bash" + run _help-list-aliases "${BASH_IT?}/enabled/750---ag.aliases.bash" assert_line -n 0 "ag:" } @test "helpers: bash-it help aliases one alias enabled in the old directory" { - ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/aliases/enabled/150---ag.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/150---ag.aliases.bash" + run ln -s "${BASH_IT?}/aliases/available/ag.aliases.bash" "${BASH_IT?}/aliases/enabled/750---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/750---ag.aliases.bash" run bash-it help aliases assert_line -n 0 "ag:" @@ -123,8 +81,8 @@ function local_setup() { @test "helpers: bash-it help aliases one alias enabled in global directory" { run bash-it enable alias "ag" - assert_line -n 0 'ag enabled with priority 150.' - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_line -n 0 'ag enabled with priority 750.' + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" run bash-it enable plugin "aws" assert_line -n 0 'aws enabled with priority 250.' @@ -135,16 +93,16 @@ function local_setup() { assert_line -n 1 "ag='ag --smart-case --pager=\"less -MIRFX'" } -@test "helpers: enable the todo.txt-cli aliases through the bash-it function" { - run bash-it enable alias "todo.txt-cli" - assert_line -n 0 'todo.txt-cli enabled with priority 150.' - assert_link_exist "${BASH_IT?}/enabled/150---todo.txt-cli.aliases.bash" +@test "helpers: enable the todo aliases through the bash-it function" { + run bash-it enable alias "todo" + assert_line -n 0 'todo enabled with priority 750.' + assert_link_exist "${BASH_IT?}/enabled/750---todo.aliases.bash" } @test "helpers: enable the curl aliases" { run _enable-alias "curl" - assert_line -n 0 'curl enabled with priority 150.' - assert_link_exist "${BASH_IT?}/enabled/150---curl.aliases.bash" + assert_line -n 0 'curl enabled with priority 750.' + assert_link_exist "${BASH_IT?}/enabled/750---curl.aliases.bash" } @test "helpers: enable the apm completion through the bash-it function" { @@ -234,7 +192,7 @@ function local_setup() { } @test "helpers: disable the nvm plugin if it was enabled with a priority, but in the component-specific directory" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" assert [ ! -L "${BASH_IT?}/enabled/225---nvm.plugin.bash" ] @@ -245,7 +203,7 @@ function local_setup() { } @test "helpers: disable the nvm plugin if it was enabled without a priority" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" run _disable-plugin "nvm" @@ -254,7 +212,7 @@ function local_setup() { } @test "helpers: enable the nvm plugin if it was enabled without a priority" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" run _enable-plugin "nvm" @@ -265,7 +223,7 @@ function local_setup() { } @test "helpers: enable the nvm plugin if it was enabled with a priority, but in the component-specific directory" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" run _enable-plugin "nvm" @@ -289,7 +247,7 @@ function local_setup() { run _bash-it-profile-load "default" assert_success - assert_link_exist "${BASH_IT?}/enabled/150---general.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---general.aliases.bash" assert_link_exist "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/800---aliases.completion.bash" assert_link_exist "${BASH_IT?}/enabled/350---bash-it.completion.bash" @@ -357,7 +315,7 @@ function local_setup() { run _bash-it-profile-load "test" assert_success assert_line -n 0 "Trying to parse profile 'test'..." - assert_link_not_exist "${BASH_IT?}/enabled/150---general.aliases.bash" + assert_link_not_exist "${BASH_IT?}/enabled/750---general.aliases.bash" assert_link_not_exist "${BASH_IT?}/enabled/250---base.plugin.bash" assert_link_not_exist "${BASH_IT?}/enabled/800---aliases.completion.bash" assert_link_not_exist "${BASH_IT?}/enabled/350---bash-it.completion.bash" @@ -382,10 +340,10 @@ function local_setup() { run _disable-alias "general" assert_success assert_output "general disabled." - assert_link_not_exist "${BASH_IT?}/enabled/150---general.aliases.bash" + assert_link_not_exist "${BASH_IT?}/enabled/750---general.aliases.bash" run _bash-it-profile-load "test" assert_success - assert_link_exist "${BASH_IT?}/enabled/150---general.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---general.aliases.bash" } @test "helpers: profile load corrupted profile file: bad component" { @@ -446,10 +404,10 @@ function local_setup() { } @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" + run 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" - ln -s "${BASH_IT?}/plugins/available/dirs.plugin.bash" "${BASH_IT?}/plugins/enabled/250---dirs.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/dirs.plugin.bash" "${BASH_IT?}/plugins/enabled/250---dirs.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---dirs.plugin.bash" run _bash-it-migrate @@ -468,41 +426,41 @@ function local_setup() { } @test "helpers: migrate enabled plugins that don't use the new priority-based configuration" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" - ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/node.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/node.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/node.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/todo.txt-cli.aliases.bash" "${BASH_IT?}/aliases/enabled/todo.txt-cli.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/todo.txt-cli.aliases.bash" + ln -s "${BASH_IT?}/aliases/available/todo.aliases.bash" "${BASH_IT?}/aliases/enabled/todo.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/todo.aliases.bash" run _enable-plugin "ssh" assert_link_exist "${BASH_IT?}/enabled/250---ssh.plugin.bash" run _bash-it-migrate - assert_line -n 0 'Migrating alias todo.txt-cli.' - assert_line -n 1 'todo.txt-cli disabled.' - assert_line -n 2 'todo.txt-cli enabled with priority 150.' + assert_line -n 0 'Migrating alias todo.' + assert_line -n 1 'todo disabled.' + assert_line -n 2 'todo enabled with priority 750.' assert_link_exist "${BASH_IT?}/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---node.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---ssh.plugin.bash" - assert_link_exist "${BASH_IT?}/enabled/150---todo.txt-cli.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---todo.aliases.bash" assert [ ! -L "${BASH_IT?}/plugins/enabled/node.plugin.bash" ] assert [ ! -L "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" ] - assert [ ! -L "${BASH_IT?}/aliases/enabled/todo.txt-cli.aliases.bash" ] + assert [ ! -L "${BASH_IT?}/aliases/enabled/todo.aliases.bash" ] } @test "helpers: migrate enabled plugins that use the new priority-based configuration in the individual directories" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" - ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" - ln -s "${BASH_IT?}/aliases/available/todo.txt-cli.aliases.bash" "${BASH_IT?}/aliases/enabled/250---todo.txt-cli.aliases.bash" - assert_link_exist "${BASH_IT?}/aliases/enabled/250---todo.txt-cli.aliases.bash" + ln -s "${BASH_IT?}/aliases/available/todo.aliases.bash" "${BASH_IT?}/aliases/enabled/250---todo.aliases.bash" + assert_link_exist "${BASH_IT?}/aliases/enabled/250---todo.aliases.bash" run _enable-plugin "ssh" assert_link_exist "${BASH_IT?}/enabled/250---ssh.plugin.bash" @@ -511,10 +469,10 @@ function local_setup() { assert_link_exist "${BASH_IT?}/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---node.plugin.bash" assert_link_exist "${BASH_IT?}/enabled/250---ssh.plugin.bash" - assert_link_exist "${BASH_IT?}/enabled/150---todo.txt-cli.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---todo.aliases.bash" assert [ ! -L "${BASH_IT?}/plugins/enabled/225----node.plugin.bash" ] assert [ ! -L "${BASH_IT?}/plugins/enabled/250----nvm.plugin.bash" ] - assert [ ! -L "${BASH_IT?}/aliases/enabled/250----todo.txt-cli.aliases.bash" ] + assert [ ! -L "${BASH_IT?}/aliases/enabled/250----todo.aliases.bash" ] } @test "helpers: run the migrate command without anything to migrate and nothing enabled" { @@ -537,9 +495,9 @@ function __migrate_all_components() { for f in "${BASH_IT}/$subdirectory/available/"*.bash; do to_enable=$(basename "$f") if [[ -z "$priority" ]]; then - ln -s "../available/$to_enable" "${BASH_IT}/${subdirectory}/enabled/$to_enable" + run ln -s "../available/$to_enable" "${BASH_IT}/${subdirectory}/enabled/$to_enable" else - ln -s "../available/$to_enable" "${BASH_IT}/${subdirectory}/enabled/$priority---$to_enable" + run ln -s "../available/$to_enable" "${BASH_IT}/${subdirectory}/enabled/$priority---$to_enable" fi done @@ -608,7 +566,7 @@ function __migrate_all_components() { } @test "helpers: verify that existing components are automatically migrated when something is enabled" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" run bash-it enable plugin "node" @@ -623,9 +581,9 @@ function __migrate_all_components() { } @test "helpers: verify that existing components are automatically migrated when something is disabled" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" - ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" run bash-it disable plugin "node" @@ -659,52 +617,52 @@ function __migrate_all_components() { assert_equal "$available" "$enabled" run _enable-alias "ag" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" run _disable-plugin "all" enabled2=$(find "${BASH_IT?}/enabled" -name '[0-9]*.plugin.bash' | wc -l | xargs) assert_equal "0" "$enabled2" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" } @test "helpers: disable all plugins in the old directory structure" { local enabled enabled2 - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" - ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/node.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/node.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/node.plugin.bash" enabled=$(find "${BASH_IT?}/plugins/enabled" -name '*.plugin.bash' | wc -l | xargs) assert_equal "2" "$enabled" run _enable-alias "ag" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" run _disable-plugin "all" enabled2=$(find "${BASH_IT?}/plugins/enabled" -name '*.plugin.bash' | wc -l | xargs) assert_equal "0" "$enabled2" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" } @test "helpers: disable all plugins in the old directory structure with priority" { local enabled enabled2 - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/250---nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/250---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---nvm.plugin.bash" - ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/node.plugin.bash" "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/250---node.plugin.bash" enabled=$(find "${BASH_IT?}/plugins/enabled" -name '*.plugin.bash' | wc -l | xargs) assert_equal "2" "$enabled" run _enable-alias "ag" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" run _disable-plugin "all" enabled2=$(find "${BASH_IT?}/plugins/enabled" -name '*.plugin.bash' | wc -l | xargs) assert_equal "0" "$enabled2" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" } @test "helpers: disable all plugins without anything enabled" { @@ -713,18 +671,18 @@ function __migrate_all_components() { assert_equal "0" "$enabled" run _enable-alias "ag" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" run _disable-plugin "all" enabled2=$(find "${BASH_IT?}/enabled" -name '[0-9]*.plugin.bash' | wc -l | xargs) assert_equal "0" "$enabled2" - assert_link_exist "${BASH_IT?}/enabled/150---ag.aliases.bash" + assert_link_exist "${BASH_IT?}/enabled/750---ag.aliases.bash" } @test "helpers: enable the ansible aliases through the bash-it function" { run bash-it enable alias "ansible" - assert_line -n 0 'ansible enabled with priority 150.' - assert_link_exist "${BASH_IT?}/enabled/150---ansible.aliases.bash" + assert_line -n 0 'ansible enabled with priority 750.' + assert_link_exist "${BASH_IT?}/enabled/750---ansible.aliases.bash" } @test "helpers: describe the nvm plugin without enabling it" { @@ -740,20 +698,20 @@ function __migrate_all_components() { } @test "helpers: describe the nvm plugin after enabling it in the old directory" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/nvm.plugin.bash" _bash-it-plugins | grep "nvm" | grep "\[x\]" } @test "helpers: describe the nvm plugin after enabling it in the old directory with priority" { - ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" + run ln -s "${BASH_IT?}/plugins/available/nvm.plugin.bash" "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" assert_link_exist "${BASH_IT?}/plugins/enabled/225---nvm.plugin.bash" _bash-it-plugins | grep "nvm" | grep "\[x\]" } -@test "helpers: describe the todo.txt-cli aliases without enabling them" { +@test "helpers: describe the todo aliases without enabling them" { run _bash-it-aliases - assert_line "todo.txt-cli [ ] todo.txt-cli abbreviations" + assert_line "todo [ ] todo.txt-cli abbreviations" } diff --git a/test/lib/search.bats b/test/lib/search.bats index bcd67168f0..0848bc9436 100644 --- a/test/lib/search.bats +++ b/test/lib/search.bats @@ -20,8 +20,14 @@ function local_setup() { @test "search: git" { local plugin completion run _bash-it-search 'git' --no-color + + assert_line -n 0 -p ' aliases:' assert_success - assert_line -n 0 ' aliases: git gitsvn ' + for alias in 'git' 'gitsvn' 'git-omz'; do + echo $alias + assert_line -n 0 -p $alias + done + assert_line -n 1 -p ' plugins:' for plugin in "autojump" "git" "gitstatus" "git-subrepo" "jgitflow" "jump"; do assert_line -n 1 -p "$plugin" diff --git a/test/lib/utilities.bats b/test/lib/utilities.bats old mode 100644 new mode 100755 index 7d8284e6a4..ac219acccc --- a/test/lib/utilities.bats +++ b/test/lib/utilities.bats @@ -6,6 +6,71 @@ function local_setup_file() { setup_libs "helpers" } +@test "utilities: _is_function: _command_exists" { + run _is_function _command_exists + assert_success +} + +@test "utilities: _command_exists function positive test ls" { + run _command_exists ls + assert_success +} + +@test "utilities: _command_exists function positive test bash-it" { + run _command_exists bash-it + assert_success +} + +@test "utilities: _command_exists function negative test" { + run _command_exists "__addfkds_dfdsjdf_${RANDOM:-}" + assert_failure +} + +@test "utilities: _is_function: _binary_exists" { + run _is_function _binary_exists + assert_success +} + +@test "utilities: _binary_exists function positive test ls" { + run _binary_exists ls + assert_success +} + +@test "utilities: _binary_exists function negative test function" { + run _binary_exists _binary_exists + assert_failure +} + +@test "utilities: _binary_exists function negative test" { + run _binary_exists "__addfkds_dfdsjdf_${RANDOM:-}" + assert_failure +} + +@test "utilities: _is_function: _completion_exists" { + run _is_function _completion_exists + assert_success +} + +@test "utilities: _is_function new function" { + local teh_new_func="__addfkds_dfdsjdf_${RANDOM:-}" + run _is_function "${teh_new_func?}" + assert_failure + + cite "${teh_new_func?}" + run _is_function "${teh_new_func?}" + assert_success +} + +@test "utilities: _command_exists new function" { + local teh_new_func="__addfkds_dfdsjdf_${RANDOM:-}" + run _command_exists "${teh_new_func?}" + assert_failure + + cite "${teh_new_func?}" + run _command_exists "${teh_new_func?}" + assert_success +} + @test "_bash-it-component-item-is-enabled() - for a disabled item" { run _bash-it-component-item-is-enabled aliases svn assert_failure @@ -13,7 +78,7 @@ function local_setup_file() { @test "_bash-it-component-item-is-enabled() - for an enabled/disabled item" { run bash-it enable alias svn - assert_line -n 0 'svn enabled with priority 150.' + assert_line -n 0 'svn enabled with priority 750.' run _bash-it-component-item-is-enabled alias svn assert_success @@ -36,7 +101,7 @@ function local_setup_file() { @test "_bash-it-component-item-is-disabled() - for an enabled/disabled item" { run bash-it enable alias svn - assert_line -n 0 'svn enabled with priority 150.' + assert_line -n 0 'svn enabled with priority 750.' run _bash-it-component-item-is-disabled alias svn assert_failure diff --git a/test/plugins/base.plugin.bats b/test/plugins/base.plugin.bats index b45ae07999..7398212494 100644 --- a/test/plugins/base.plugin.bats +++ b/test/plugins/base.plugin.bats @@ -8,10 +8,14 @@ function local_setup_file() { } @test 'plugins base: ips()' { - readonly localhost='127.0.0.1' + if [[ -n "${CI:-}" ]]; then + skip 'ifconfig probably requires sudo on TravisCI' + fi + + declare -r localhost='127.0.0.1' run ips assert_success - assert_line "$localhost" + assert_line $localhost } @test 'plugins base: myip()' { diff --git a/test/plugins/go.plugin.bats b/test/plugins/go.plugin.bats index 69cb8fef61..b0c2bd1035 100644 --- a/test/plugins/go.plugin.bats +++ b/test/plugins/go.plugin.bats @@ -53,7 +53,7 @@ function setup_go_path() { setup_go_path "$BASH_IT/test/fixtures/go/gopath" setup_go_path "$BASH_IT/test/fixtures/go/gopath2" load "${BASH_IT?}/plugins/available/go.plugin.bash" - assert_equal "$(cut -d':' -f1,2 <<< "$PATH")" "$BASH_IT/test/fixtures/go/gopath2/bin:$BASH_IT/test/fixtures/go/gopath/bin" + assert_equal "$(cut -d':' -f1,2 <<< "$PATH")" "$BASH_IT/test/fixtures/go/gopath/bin:$BASH_IT/test/fixtures/go/gopath2/bin" } @test 'plugins go: multiple entries in GOPATH, with space' { @@ -61,7 +61,7 @@ function setup_go_path() { setup_go_path "$BASH_IT/test/fixtures/go/gopath" setup_go_path "$BASH_IT/test/fixtures/go/go path" load "${BASH_IT?}/plugins/available/go.plugin.bash" - assert_equal "$(cut -d':' -f1,2 <<< "$PATH")" "$BASH_IT/test/fixtures/go/go path/bin:$BASH_IT/test/fixtures/go/gopath/bin" + assert_equal "$(cut -d':' -f1,2 <<< "$PATH")" "$BASH_IT/test/fixtures/go/gopath/bin:$BASH_IT/test/fixtures/go/go path/bin" } @test 'plugins go: multiple entries in GOPATH, with escaped space' { diff --git a/test/themes/base.theme.bats b/test/themes/base.theme.bats index 0cf93d6a97..9384de5cda 100644 --- a/test/themes/base.theme.bats +++ b/test/themes/base.theme.bats @@ -12,8 +12,8 @@ function local_setup_file() { assert_failure } -@test 'themes base: battery_percentage should exist if battery plugin loaded' { - load "${BASH_IT?}/plugins/available/battery.plugin.bash" +@test 'themes base: battery_percentage should exist if battery library loaded' { + load "${BASH_IT?}/lib/battery.bash" run type -a battery_percentage &> /dev/null assert_success @@ -28,10 +28,10 @@ function local_setup_file() { assert_output "" } -@test 'themes base: battery_char should exist if battery plugin loaded' { +@test 'themes base: battery_char should exist if battery library loaded' { unset -f battery_char - load "${BASH_IT?}/plugins/available/battery.plugin.bash" + load "${BASH_IT?}/lib/battery.bash" run type -t battery_percentage assert_success assert_line "function" @@ -57,9 +57,9 @@ function local_setup_file() { assert_output "" } -@test 'themes base: battery_charge should exist if battery plugin loaded' { +@test 'themes base: battery_charge should exist if battery library loaded' { unset -f battery_charge - load "${BASH_IT?}/plugins/available/battery.plugin.bash" + load "${BASH_IT?}/lib/battery.bash" load "${BASH_IT?}/themes/base.theme.bash" run type -a battery_charge &> /dev/null diff --git a/themes/agnoster/agnoster.theme.bash b/themes/agnoster/agnoster.theme.bash index d5bac5ca69..c274058994 100644 --- a/themes/agnoster/agnoster.theme.bash +++ b/themes/agnoster/agnoster.theme.bash @@ -235,7 +235,8 @@ prompt_histdt() { } git_status_dirty() { - dirty=$(git status -s 2> /dev/null | tail -n 1) + local dirty + dirty=$(git status --porcelain 2> /dev/null | tail -n 1) [[ -n $dirty ]] && echo " ●" } diff --git a/themes/barbuk/barbuk.theme.bash b/themes/barbuk/barbuk.theme.bash index 3bf80a77d2..46b37e2b7e 100644 --- a/themes/barbuk/barbuk.theme.bash +++ b/themes/barbuk/barbuk.theme.bash @@ -27,13 +27,14 @@ SCALEWAY_PROFILE_CHAR=${BARBUK_SCALEWAY_PROFILE_CHAR:=" scw "} GCLOUD_CHAR=${BARBUK_GCLOUD_CHAR:=" google "} # Command duration -COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-1} +: "${COMMAND_DURATION_MIN_SECONDS:=1}" +: "${COMMAND_DURATION_COLOR:="${normal?}"}" # Ssh user and hostname display SSH_INFO=${BARBUK_SSH_INFO:=true} HOST_INFO=${BARBUK_HOST_INFO:=long} -# Bash-it default glyphs customization +# Bash-it default glyphs overrides SCM_NONE_CHAR= SCM_THEME_PROMPT_DIRTY=" ${bold_red?}✗" SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓" @@ -59,20 +60,20 @@ RBFU_THEME_PROMPT_PREFIX='' RBFU_THEME_PROMPT_SUFFIX='' function __git-uptream-remote-logo_prompt() { - [[ "$(_git-upstream)" == "" ]] && SCM_GIT_CHAR="$SCM_GIT_CHAR_DEFAULT" + [[ -z "$(_git-upstream)" ]] && SCM_GIT_CHAR="${SCM_GIT_CHAR_DEFAULT:-}" local remote remote_domain - remote=$(_git-upstream-remote) - remote_domain=$(git config --get remote."$remote".url | awk -F'[@:.]' '{print $2}') + remote="$(_git-upstream-remote)" + remote_domain="$(git config --get remote."${remote}".url | awk -F'[@:.]' '{print $2}')" # remove // suffix for https:// url - remote_domain=${remote_domain//\//} + remote_domain="${remote_domain//\//}" - case $remote_domain in - github) SCM_GIT_CHAR="$SCM_GIT_CHAR_GITHUB" ;; - gitlab) SCM_GIT_CHAR="$SCM_GIT_CHAR_GITLAB" ;; - bitbucket) SCM_GIT_CHAR="$SCM_GIT_CHAR_BITBUCKET" ;; - *) SCM_GIT_CHAR="$SCM_GIT_CHAR_DEFAULT" ;; + case "${remote_domain}" in + github) SCM_GIT_CHAR="${SCM_GIT_CHAR_GITHUB:-}" ;; + gitlab) SCM_GIT_CHAR="${SCM_GIT_CHAR_GITLAB:-}" ;; + bitbucket) SCM_GIT_CHAR="${SCM_GIT_CHAR_BITBUCKET:-}" ;; + *) SCM_GIT_CHAR="${SCM_GIT_CHAR_DEFAULT:-}" ;; esac echo "${purple?}$(scm_char)" @@ -141,8 +142,8 @@ function __ruby_prompt() { function __ssh_prompt() { # Detect ssh - if [[ -n "${SSH_CONNECTION}" ]] && [ "$SSH_INFO" = true ]; then - if [ "$HOST_INFO" = long ]; then + if [[ -n "${SSH_CONNECTION:-}" && "${SSH_INFO:-}" == true ]]; then + if [[ "${HOST_INFO:-}" == long ]]; then host="\H" else host="\h" diff --git a/themes/base.theme.bash b/themes/base.theme.bash index d78baa6adf..47e09b24d2 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -175,6 +175,7 @@ function scm_prompt_vars() { scm_prompt_char SCM_DIRTY=0 SCM_STATE='' + SCM_BRANCH='' local prompt_vars="${SCM}_prompt_vars" _is_function "${prompt_vars}" && "${prompt_vars}" @@ -393,28 +394,68 @@ function hg_prompt_vars() { fi } +function node_command_version_prompt() { + # Set to 'true' to only show node version in directories with package.json + NODE_VERSION_CHECK_PROJECT="${NODE_VERSION_CHECK_PROJECT:-false}" + + # If NODE_VERSION_CHECK_PROJECT is enabled, only show version in Node.js projects + if [[ "${NODE_VERSION_CHECK_PROJECT}" == "true" ]] && ! _is_node_project; then + return 0 + fi + + local node_version + if _command_exists node; then + node_version="$(node --version 2> /dev/null)" + if [[ -n ${node_version} ]]; then + echo -e "${NVM_THEME_PROMPT_PREFIX}${node_version}${NVM_THEME_PROMPT_SUFFIX}" + fi + fi +} + function nvm_version_prompt() { - local node + local nvm_ver if _is_function nvm; then - node=$(nvm current 2> /dev/null) - [[ "${node}" == "system" ]] && return - echo -ne "${NVM_THEME_PROMPT_PREFIX-}${node}${NVM_THEME_PROMPT_SUFFIX-}" + nvm_ver=$(nvm current 2> /dev/null) + [[ "${nvm_ver}" == "system" ]] && return + echo -ne "${NVM_THEME_PROMPT_PREFIX-}${nvm_ver}${NVM_THEME_PROMPT_SUFFIX-}" fi } function node_native_version_prompt() { - local node + local node_ver if _command_exists node; then - node=$(node --version 2> /dev/null) - echo -ne "${NODE_THEME_PROMPT_PREFIX-}${node}${NODE_THEME_PROMPT_SUFFIX-}" + node_ver=$(node --version 2> /dev/null) + echo -ne "${NODE_THEME_PROMPT_PREFIX-}${node_ver}${NODE_THEME_PROMPT_SUFFIX-}" fi } +function _is_node_project() { + # Check if we're in a Node.js project by looking for package.json + # Search current directory and parent directories up to $HOME + local dir="${PWD}" + while [[ "${dir}" != "${HOME-}" && "${dir}" != "/" ]]; do + if [[ -f "${dir}/package.json" ]]; then + return 0 + fi + dir=$(dirname "${dir}") + done + # Also check $HOME itself + [[ -f "${HOME-}/package.json" ]] && return 0 + return 1 +} + function node_version_prompt() { NODE_VERSION_STRATEGY="${NODE_VERSION_STRATEGY:-nvm}" + # Set to 'true' to only show node version in directories with package.json + NODE_VERSION_CHECK_PROJECT="${NODE_VERSION_CHECK_PROJECT:-false}" _log_debug "node: using version strategy '$NODE_VERSION_STRATEGY'" + # If NODE_VERSION_CHECK_PROJECT is enabled, only show version in Node.js projects + if [[ "${NODE_VERSION_CHECK_PROJECT}" == "true" ]] && ! _is_node_project; then + return 0 + fi + if [ "$NODE_VERSION_STRATEGY" == "nvm" ]; then nvm_version_prompt elif [ "$NODE_VERSION_STRATEGY" == "node" ]; then @@ -574,23 +615,30 @@ function prompt_char() { } function battery_char() { - # The battery_char function depends on the presence of the battery_percentage function. - if [[ "${THEME_BATTERY_PERCENTAGE_CHECK}" == true ]] && _command_exists battery_percentage; then - echo -ne "${bold_red?}$(battery_percentage)%" + local battery_percentage + if _is_function battery_percentage; then + battery_percentage="$(battery_percentage)" + if [[ "${THEME_BATTERY_PERCENTAGE_CHECK}" == true ]]; then + echo -e "${bold_red?}${battery_percentage}%" + else + false + fi else false fi } if ! _command_exists battery_charge; then - # if user has installed battery plugin, skip this... function battery_charge() { - : # no op + # Provide a stub that always returns empty - the real implementation is in lib/battery.bash + echo "" } fi function aws_profile() { - if [[ -n "${AWS_DEFAULT_PROFILE:-}" ]]; then + if [[ -n "${AWS_PROFILE:-}" ]]; then + echo -ne "${AWS_PROFILE}" + elif [[ -n "${AWS_DEFAULT_PROFILE:-}" ]]; then echo -ne "${AWS_DEFAULT_PROFILE}" else echo -ne "default" @@ -602,3 +650,11 @@ function _save-and-reload-history() { [[ ${autosave} -eq 1 ]] && local HISTCONTROL="${HISTCONTROL:-}${HISTCONTROL:+:}autoshare" _bash-it-history-auto-save && _bash-it-history-auto-load } + +function conda_or_venv_prompt() { + if [[ -n "${CONDA_DEFAULT_ENV:-}" ]]; then + condaenv_prompt + elif [[ -n "${VIRTUAL_ENV:-}" ]]; then + virtualenv_prompt + fi +} diff --git a/themes/binaryanomaly/binaryanomaly.theme.bash b/themes/binaryanomaly/binaryanomaly.theme.bash index c4488c4c96..3501e8d469 100644 --- a/themes/binaryanomaly/binaryanomaly.theme.bash +++ b/themes/binaryanomaly/binaryanomaly.theme.bash @@ -1,12 +1,11 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. # Detect whether a reboot is required function show_reboot_required() { - if [ -n "$_bf_prompt_reboot_info" ]; then - if [ -f /var/run/reboot-required ]; then - printf "Reboot required!" + if [[ -n "${_bf_prompt_reboot_info:-}" ]]; then + if [[ -f /var/run/reboot-required ]]; then + printf '%s' "Reboot required!" fi fi } @@ -14,21 +13,21 @@ function show_reboot_required() { # Set different host color for local and remote sessions function set_host_color() { # Detect if connection is through SSH - if [[ -n $SSH_CLIENT ]]; then - printf '%s' "${lime_yellow}" + if [[ -n "${SSH_CLIENT:-}" ]]; then + printf '%s' "${lime_yellow?}" else - printf '%s' "${light_orange}" + printf '%s' "${light_orange?}" fi } # Set different username color for users and root function set_user_color() { - case $(id -u) in + case ${EUID:-$UID} in 0) - printf '%s' "${red}" + printf '%s' "${red?}" ;; *) - printf '%s' "${cyan}" + printf '%s' "${cyan?}" ;; esac } @@ -47,40 +46,48 @@ function set_custom_colors() { powder_blue="\[$(tput setaf 153)\]" } -__ps_time() { - printf '%s' "$(clock_prompt)${normal}\n" +function __ps_time() { + local clock_prompt + clock_prompt="$(clock_prompt)" + printf '%s\n' "${clock_prompt}${normal?}" } function prompt_command() { - ps_reboot="${bright_yellow}$(show_reboot_required)${normal}\n" + local show_reboot_required set_user_color set_host_color scm_prompt ps_time + show_reboot_required="$(show_reboot_required)" + ps_reboot="${bright_yellow?}${show_reboot_required}${normal?}\n" - ps_username="$(set_user_color)\u${normal}" - ps_uh_separator="${dark_grey}@${normal}" - ps_hostname="$(set_host_color)\h${normal}" + set_user_color="$(set_user_color)" + ps_username="${set_user_color}\u${normal}" + ps_uh_separator="${dark_grey?}@${normal}" + set_host_color="$(set_host_color)" + ps_hostname="${set_host_color}\h${normal}" - ps_path="${yellow}\w${normal}" - ps_scm_prompt="${light_grey}$(scm_prompt)" + ps_path="${yellow?}\w${normal}" + scm_prompt="$(scm_prompt)" + ps_scm_prompt="${light_grey?}${scm_prompt}" ps_user_mark="${normal} ${normal}" ps_user_input="${normal}" # Set prompt - PS1="$ps_reboot$(__ps_time)$ps_username$ps_uh_separator$ps_hostname $ps_path $ps_scm_prompt$ps_user_mark$ps_user_input" + ps_time="$(__ps_time)" + PS1="$ps_reboot${ps_time}$ps_username$ps_uh_separator$ps_hostname $ps_path $ps_scm_prompt$ps_user_mark$ps_user_input" } # Initialize custom colors set_custom_colors -THEME_CLOCK_COLOR=${THEME_CLOCK_COLOR:-"$dark_grey"} +: "${THEME_CLOCK_COLOR:="$dark_grey"}" # scm theming SCM_THEME_PROMPT_PREFIX="" SCM_THEME_PROMPT_SUFFIX="" -SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${light_grey}" -SCM_THEME_PROMPT_CLEAN=" ${green}✓${light_grey}" -SCM_GIT_CHAR="${green}±${light_grey}" -SCM_SVN_CHAR="${bold_cyan}⑆${light_grey}" -SCM_HG_CHAR="${bold_red}☿${light_grey}" +SCM_THEME_PROMPT_DIRTY=" ${bold_red?}✗${light_grey?}" +SCM_THEME_PROMPT_CLEAN=" ${green?}✓${light_grey?}" +SCM_GIT_CHAR="${green?}±${light_grey?}" +SCM_SVN_CHAR="${bold_cyan?}⑆${light_grey?}" +SCM_HG_CHAR="${bold_red?}☿${light_grey?}" safe_append_prompt_command prompt_command diff --git a/themes/codeword/codeword.theme.bash b/themes/codeword/codeword.theme.bash index 0966d6212d..9237ebd7df 100644 --- a/themes/codeword/codeword.theme.bash +++ b/themes/codeword/codeword.theme.bash @@ -1,4 +1,5 @@ # shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. SCM_THEME_PROMPT_PREFIX="${SCM_THEME_PROMPT_SUFFIX:-}" SCM_THEME_PROMPT_DIRTY="${bold_red?} ✗${normal?}" diff --git a/themes/cooperkid/cooperkid.theme.bash b/themes/cooperkid/cooperkid.theme.bash index 1b9c9c1163..b0ea4b385b 100644 --- a/themes/cooperkid/cooperkid.theme.bash +++ b/themes/cooperkid/cooperkid.theme.bash @@ -1,16 +1,18 @@ +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # ------------------------------------------------------------------# # FILE: cooperkid.zsh-theme # # BY: Alfredo Bejarano # # BASED ON: Mr Briggs by Matt Brigg (matt@mattbriggs.net) # # ------------------------------------------------------------------# -SCM_THEME_PROMPT_DIRTY="${red} ✗${reset_color}" -SCM_THEME_PROMPT_AHEAD="${yellow} ↑${reset_color}" -SCM_THEME_PROMPT_CLEAN="${green} ✓${reset_color}" +SCM_THEME_PROMPT_DIRTY="${red?} ✗${reset_color?}" +SCM_THEME_PROMPT_AHEAD="${yellow?} ↑${reset_color?}" +SCM_THEME_PROMPT_CLEAN="${green?} ✓${reset_color?}" SCM_THEME_PROMPT_PREFIX=" " SCM_THEME_PROMPT_SUFFIX="" -GIT_SHA_PREFIX="${blue}" -GIT_SHA_SUFFIX="${reset_color}" +GIT_SHA_PREFIX="${blue?}" +GIT_SHA_SUFFIX="${reset_color?}" function rvm_version_prompt { if which rvm &> /dev/null; then @@ -27,11 +29,13 @@ function git_short_sha() { function prompt() { local return_status="" - local ruby="${red}$(ruby_version_prompt)${reset_color}" - local user_host="${green}\h @ \w${reset_color}" - local git_branch="$(git_short_sha)${cyan}$(scm_prompt_info)${reset_color}" + local ruby + ruby="${red?}$(ruby_version_prompt)${reset_color?}" + local user_host="${green?}\h @ \w${reset_color?}" + local git_branch + git_branch="$(git_short_sha)${cyan?}$(scm_prompt_info)${reset_color?}" local prompt_symbol=' ' - local prompt_char="${purple}>_${reset_color} " + local prompt_char="${purple?}>_${reset_color?} " PS1="\n${user_host}${prompt_symbol}${ruby} ${git_branch} ${return_status}\n${prompt_char}" } diff --git a/themes/cupcake/cupcake.theme.bash b/themes/cupcake/cupcake.theme.bash index f1b9b3c95b..5956bc465a 100644 --- a/themes/cupcake/cupcake.theme.bash +++ b/themes/cupcake/cupcake.theme.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # Emoji-based theme to display source control management and # virtual environment info beside the ordinary bash prompt. @@ -19,11 +20,11 @@ VIRTUALENV_THEME_PROMPT_SUFFIX="" # SCM prompts SCM_NONE_CHAR="" SCM_GIT_CHAR="[±] " -SCM_GIT_BEHIND_CHAR="${red}↓${normal}" -SCM_GIT_AHEAD_CHAR="${bold_green}↑${normal}" +SCM_GIT_BEHIND_CHAR="${red?}↓${normal?}" +SCM_GIT_AHEAD_CHAR="${bold_green?}↑${normal?}" SCM_GIT_UNTRACKED_CHAR="⌀" -SCM_GIT_UNSTAGED_CHAR="${bold_yellow}•${normal}" -SCM_GIT_STAGED_CHAR="${bold_green}+${normal}" +SCM_GIT_UNSTAGED_CHAR="${bold_yellow?}•${normal?}" +SCM_GIT_STAGED_CHAR="${bold_green?}+${normal?}" SCM_THEME_PROMPT_DIRTY="" SCM_THEME_PROMPT_CLEAN="" @@ -31,8 +32,8 @@ SCM_THEME_PROMPT_PREFIX="" SCM_THEME_PROMPT_SUFFIX="" # Git status prompts -GIT_THEME_PROMPT_DIRTY=" ${red}✗${normal}" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" +GIT_THEME_PROMPT_DIRTY=" ${red?}✗${normal?}" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓${normal?}" GIT_THEME_PROMPT_PREFIX="" GIT_THEME_PROMPT_SUFFIX="" @@ -59,19 +60,19 @@ function virtualenv_prompt { # Rename tab function tabname { - printf "\e]1;$1\a" + printf "\e]1;%s\a" "$1" } # Rename window function winname { - printf "\e]2;$1\a" + printf "\e]2;%s\a" "$1" } # PROMPT OUTPUT =============================================================== # Displays the current prompt function prompt_command() { - PS1="\n${icon_start}$(virtualenv_prompt)${icon_user}${bold_red}\u${normal}${icon_host}${bold_cyan}\h${normal}${icon_directory}${bold_purple}\W${normal}\$([[ -n \$(git branch 2> /dev/null) ]] && echo \" on ${icon_branch} \")${white}$(scm_prompt_info)${normal}\n${icon_end}" + PS1="\n${icon_start}$(virtualenv_prompt)${icon_user}${bold_red?}\u${normal?}${icon_host}${bold_cyan?}\h${normal?}${icon_directory}${bold_purple?}\W${normal?}\$([[ -n \$(git branch 2> /dev/null) ]] && echo \" on ${icon_branch} \")${white?}$(scm_prompt_info)${normal?}\n${icon_end}" PS2="${icon_end}" } diff --git a/themes/demula/demula.theme.bash b/themes/demula/demula.theme.bash index f20e6097aa..8171abea92 100644 --- a/themes/demula/demula.theme.bash +++ b/themes/demula/demula.theme.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # Theme inspired on: # - Ronacher's dotfiles (mitsuhikos) - http://github.com/mitsuhiko/dotfiles/tree/master/bash/ @@ -10,40 +11,40 @@ # Screenshot: http://goo.gl/VCmX5 # by Jesus de Mula -# For the real Monokai colors you should add these to your .XDefaults or -# terminal configuration: -#! ----------------------------------------------------------- TERMINAL COLORS -#! monokai - http://www.monokai.nl/blog/2006/07/15/textmate-color-theme/ -#*background: #272822 -#*foreground: #E2DA6E -#*color0: black -#! mild red -#*color1: #CD0000 -#! light green -#*color2: #A5E02D -#! orange (yellow) -#*color3: #FB951F -#! "dark" blue -#*color4: #076BCC -#! hot pink -#*color5: #F6266C -#! cyan -#*color6: #64D9ED -#! gray -#*color7: #E5E5E5 +## For the real Monokai colors you should add these to your .XDefaults or +## terminal configuration: +## ! ----------------------------------------------------------- TERMINAL COLORS +## ! monokai - http://www.monokai.nl/blog/2006/07/15/textmate-color-theme/ +## *background: #272822 +## *foreground: #E2DA6E +## *color0: black +## ! mild red +## *color1: #CD0000 +## ! light green +## *color2: #A5E02D +## ! orange (yellow) +## *color3: #FB951F +## ! "dark" blue +## *color4: #076BCC +## ! hot pink +## *color5: #F6266C +## ! cyan +## *color6: #64D9ED +## ! gray +## *color7: #E5E5E5 # ----------------------------------------------------------------- COLOR CONF -D_DEFAULT_COLOR="${normal}" -D_INTERMEDIATE_COLOR="${white}" -D_USER_COLOR="${purple}" -D_SUPERUSER_COLOR="${red}" -D_MACHINE_COLOR="${cyan}" -D_DIR_COLOR="${green}" -D_SCM_COLOR="${yellow}" -D_BRANCH_COLOR="${yellow}" -D_CHANGES_COLOR="${white}" -D_CMDFAIL_COLOR="${red}" -D_VIMSHELL_COLOR="${cyan}" +D_DEFAULT_COLOR="${normal?}" +D_INTERMEDIATE_COLOR="${white?}" +D_USER_COLOR="${purple?}" +D_SUPERUSER_COLOR="${red?}" +D_MACHINE_COLOR="${cyan?}" +D_DIR_COLOR="${green?}" +D_SCM_COLOR="${yellow?}" +D_BRANCH_COLOR="${yellow?}" +D_CHANGES_COLOR="${white?}" +D_CMDFAIL_COLOR="${red?}" +D_VIMSHELL_COLOR="${cyan?}" # ------------------------------------------------------------------ FUNCTIONS case $TERM in @@ -56,7 +57,7 @@ case $TERM in esac is_vim_shell() { - if [ ! -z "$VIMRUNTIME" ]; then + if [ -n "$VIMRUNTIME" ]; then echo "${D_INTERMEDIATE_COLOR}on ${D_VIMSHELL_COLOR}\ vim shell${D_DEFAULT_COLOR} " fi @@ -72,23 +73,17 @@ $code ${D_DEFAULT_COLOR}" # vcprompt for scm instead of bash_it default demula_vcprompt() { - if [ ! -z "$VCPROMPT_EXECUTABLE" ]; then + if [ -n "$VCPROMPT_EXECUTABLE" ]; then local D_VCPROMPT_FORMAT="on ${D_SCM_COLOR}%s${D_INTERMEDIATE_COLOR}:\ ${D_BRANCH_COLOR}%b %r ${D_CHANGES_COLOR}%m%u ${D_DEFAULT_COLOR}" $VCPROMPT_EXECUTABLE -f "$D_VCPROMPT_FORMAT" fi } -# checks if the plugin is installed before calling battery_charge -safe_battery_charge() { - if _command_exists battery_charge; then - battery_charge - fi -} - # -------------------------------------------------------------- PROMPT OUTPUT prompt() { - local LAST_COMMAND_FAILED=$(mitsuhikos_lastcommandfailed) + local LAST_COMMAND_FAILED + LAST_COMMAND_FAILED=$(mitsuhikos_lastcommandfailed) local SAVE_CURSOR='\033[s' local RESTORE_CURSOR='\033[u' local MOVE_CURSOR_RIGHTMOST='\033[500C' @@ -96,7 +91,7 @@ prompt() { if [[ "$OSTYPE" = 'linux'* ]]; then PS1="${TITLEBAR}${SAVE_CURSOR}${MOVE_CURSOR_RIGHTMOST}${MOVE_CURSOR_5_LEFT} -$(safe_battery_charge)${RESTORE_CURSOR}\ +$(battery_charge)${RESTORE_CURSOR}\ ${D_USER_COLOR}\u ${D_INTERMEDIATE_COLOR}\ at ${D_MACHINE_COLOR}\h ${D_INTERMEDIATE_COLOR}\ in ${D_DIR_COLOR}\w ${D_INTERMEDIATE_COLOR}\ @@ -112,7 +107,7 @@ in ${D_DIR_COLOR}\w ${D_INTERMEDIATE_COLOR}\ ${LAST_COMMAND_FAILED}\ $(demula_vcprompt)\ $(is_vim_shell)\ -$(safe_battery_charge) +$(battery_charge) ${D_INTERMEDIATE_COLOR}$ ${D_DEFAULT_COLOR}" fi diff --git a/themes/dos/dos.theme.bash b/themes/dos/dos.theme.bash index 17f0cff646..d7e072c2e9 100644 --- a/themes/dos/dos.theme.bash +++ b/themes/dos/dos.theme.bash @@ -1 +1,3 @@ +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. PROMPT="\w>>" diff --git a/themes/doubletime_multiline/doubletime_multiline.theme.bash b/themes/doubletime_multiline/doubletime_multiline.theme.bash index bd6d7f0ddc..32e789ea5f 100644 --- a/themes/doubletime_multiline/doubletime_multiline.theme.bash +++ b/themes/doubletime_multiline/doubletime_multiline.theme.bash @@ -1,4 +1,5 @@ # shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. source "$BASH_IT/themes/doubletime/doubletime.theme.bash" @@ -6,7 +7,7 @@ function prompt_setter() { # Save history _save-and-reload-history 1 PS1=" -$(clock_prompt) $(scm_char) [$THEME_PROMPT_HOST_COLOR\u@${THEME_PROMPT_HOST}$reset_color] $(virtualenv_prompt)$(ruby_version_prompt) +$(clock_prompt) $(scm_char) [$THEME_PROMPT_HOST_COLOR\u@${THEME_PROMPT_HOST}${reset_color?}] $(virtualenv_prompt)$(ruby_version_prompt) \w $(scm_prompt)$reset_color $ " PS2='> ' diff --git a/themes/doubletime_multiline_pyonly/doubletime_multiline_pyonly.theme.bash b/themes/doubletime_multiline_pyonly/doubletime_multiline_pyonly.theme.bash index 4d1e493a19..aa078e788d 100644 --- a/themes/doubletime_multiline_pyonly/doubletime_multiline_pyonly.theme.bash +++ b/themes/doubletime_multiline_pyonly/doubletime_multiline_pyonly.theme.bash @@ -1,4 +1,5 @@ # shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. source "$BASH_IT/themes/doubletime/doubletime.theme.bash" @@ -6,7 +7,7 @@ function prompt_setter() { # Save history _save-and-reload-history 1 PS1=" -$(clock_prompt) $(scm_char) [$THEME_PROMPT_HOST_COLOR\u@${THEME_PROMPT_HOST}$reset_color] $(virtualenv_prompt) +$(clock_prompt) $(scm_char) [$THEME_PROMPT_HOST_COLOR\u@${THEME_PROMPT_HOST}${reset_color?}] $(virtualenv_prompt) \w $(scm_prompt)$reset_color $ " PS2='> ' diff --git a/themes/dulcie/dulcie.theme.bash b/themes/dulcie/dulcie.theme.bash old mode 100755 new mode 100644 index cad0d22e7a..be08940344 --- a/themes/dulcie/dulcie.theme.bash +++ b/themes/dulcie/dulcie.theme.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # Simplistic one-liner theme to display source control management info beside # the ordinary Linux bash prompt. @@ -25,7 +26,7 @@ dulcie_background() { dulcie_prompt() { color_user_root=$(dulcie_color 169) - color_user_nonroot="${green}" + color_user_nonroot="${green?}" color_host_local=$(dulcie_color 230) color_host_remote=$(dulcie_color 214) color_rootdir=$(dulcie_color 117) @@ -48,18 +49,18 @@ dulcie_prompt() { color_host="${color_host_local}" fi - DULCIE_USER="${color_user}\u${reset_color}" - DULCIE_HOST="${color_host}\h${reset_color}" - DULCIE_WORKINGDIR="${color_workingdir}\W${reset_color}" - DULCIE_PROMPTCHAR="${color_user}"'\$'"${reset_color}" + DULCIE_USER="${color_user?}\u${reset_color?}" + DULCIE_HOST="${color_host?}\h${reset_color?}" + DULCIE_WORKINGDIR="${color_workingdir?}\W${reset_color?}" + DULCIE_PROMPTCHAR="${color_user?}"'\$'"${reset_color?}" - SCM_THEME_PROMPT_DIRTY=" ${red}✗${reset_color}" - SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" + SCM_THEME_PROMPT_DIRTY=" ${red?}✗${reset_color}" + SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓${normal?}" DULCIE_SCM_BACKGROUND="${background_scm}" DULCIE_SCM_DIR_COLOR="${color_rootdir}" SCM_THEME_ROOT_SUFFIX="${reset_color}${SCM_THEME_ROOT_SUFFIX}" - SCM_THEME_PROMPT_DIRTY=" $(dulcie_color 1)✗${reset_color}" - SCM_THEME_PROMPT_CLEAN=" $(dulcie_color 10)✓${reset_color}" + SCM_THEME_PROMPT_DIRTY=" $(dulcie_color 1)✗${reset_color?}" + SCM_THEME_PROMPT_CLEAN=" $(dulcie_color 10)✓${reset_color?}" else DULCIE_USER='\u' DULCIE_HOST='\h' @@ -79,9 +80,9 @@ dulcie_prompt() { # Open the new terminal in the same directory _is_function __vte_osc7 && __vte_osc7 - PS1="${reset_color}[${DULCIE_USER}@${DULCIE_HOST}$(scm_prompt_info)${reset_color} ${DULCIE_WORKINGDIR}]" + PS1="${reset_color}[${DULCIE_USER}@${DULCIE_HOST}$(scm_prompt_info)${reset_color?} ${DULCIE_WORKINGDIR}]" if [[ "${DULCIE_MULTILINE}" -eq "1" ]]; then - PS1="${reset_color}[${DULCIE_USER}@${DULCIE_HOST}${reset_color} ${DULCIE_WORKINGDIR}]" + PS1="${reset_color}[${DULCIE_USER}@${DULCIE_HOST}${reset_color?} ${DULCIE_WORKINGDIR}]" if [[ "$(scm_prompt_info)" ]]; then SCM_THEME_PROMPT_PREFIX="${DULCIE_SCM_BACKGROUND}|${DULCIE_SCM_DIR_COLOR}" SCM_THEME_PROMPT_SUFFIX="|${normal}" @@ -90,7 +91,7 @@ dulcie_prompt() { else SCM_THEME_PROMPT_PREFIX=" ${DULCIE_SCM_BACKGROUND}|${DULCIE_SCM_DIR_COLOR}" SCM_THEME_PROMPT_SUFFIX="|${normal}" - PS1="${reset_color}[${DULCIE_USER}@${DULCIE_HOST}$(scm_prompt_info)${reset_color} ${DULCIE_WORKINGDIR}]" + PS1="${reset_color?}[${DULCIE_USER}@${DULCIE_HOST}$(scm_prompt_info)${reset_color?} ${DULCIE_WORKINGDIR}]" fi PS1="${PS1}${DULCIE_PROMPTCHAR} " } diff --git a/themes/duru/duru.theme.bash b/themes/duru/duru.theme.bash index a22bcf5f14..3aa98c125b 100644 --- a/themes/duru/duru.theme.bash +++ b/themes/duru/duru.theme.bash @@ -1,23 +1,25 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. -SCM_THEME_PROMPT_PREFIX="${cyan} on ${green}" +SCM_THEME_PROMPT_PREFIX="${cyan?} on ${green?}" SCM_THEME_PROMPT_SUFFIX="" -SCM_THEME_PROMPT_DIRTY=" ${red}with changes" +SCM_THEME_PROMPT_DIRTY=" ${red?}with changes" SCM_THEME_PROMPT_CLEAN="" venv() { - if [ ! -z "$VIRTUAL_ENV" ]; then + if [ -n "$VIRTUAL_ENV" ]; then local env=$VIRTUAL_ENV - echo "${gray} in ${orange}${env##*/} " + echo "${gray?} in ${orange?}${env##*/} " fi } last_two_dirs() { - pwd | rev | awk -F / '{print $1,$2}' | rev | sed s_\ _/_ | sed "s|$(sed 's,\/,,' <<< $HOME)|~|g" + # shellcheck disable=SC2001 + pwd | rev | awk -F / '{print $1,$2}' | rev | sed s_\ _/_ | sed "s|$(sed 's,\/,,' <<< "$HOME")|~|g" } prompt() { - PS1="${yellow}# ${reset_color}$(last_two_dirs)$(scm_prompt_info)${reset_color}$(venv)${reset_color} ${cyan}\n> ${reset_color}" + PS1="${yellow?}# ${reset_color?}$(last_two_dirs)$(scm_prompt_info)${reset_color?}$(venv)${reset_color?} ${cyan?}\n> ${reset_color?}" } safe_append_prompt_command prompt diff --git a/themes/emperor/emperor.theme.bash b/themes/emperor/emperor.theme.bash index 2f02eca78a..da145fcd6f 100644 --- a/themes/emperor/emperor.theme.bash +++ b/themes/emperor/emperor.theme.bash @@ -1,29 +1,30 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. -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="|" function get_hour_color { - hour_color=$red + hour_color=${red?} min=$(date +%M) if [ "$min" -lt "15" ]; then - hour_color=$white + hour_color=${white?} elif [ "$min" -lt "30" ]; then - hour_color=$green + hour_color=${green?} elif [ "$min" -lt "45" ]; then - hour_color=$yellow + hour_color=${yellow?} else - hour_color=$red + hour_color=${red?} fi echo "$hour_color" } @@ -34,7 +35,7 @@ __emperor_clock() { } function prompt_command() { - PS1="\n$(__emperor_clock)${purple}\h ${reset_color}in ${prompt_color}\w\n${bold_cyan}$(scm_char)${green}$(scm_prompt_info) ${green}→${reset_color} " + PS1="\n$(__emperor_clock)${purple?}\h ${reset_color?}in ${prompt_color?}\w\n${bold_cyan?}$(scm_char)${green?}$(scm_prompt_info) ${green?}→${reset_color?} " } THEME_CLOCK_FORMAT=${THEME_CLOCK_FORMAT:-"%H "} diff --git a/themes/envy/envy.theme.bash b/themes/envy/envy.theme.bash index ae28c1f622..acb0136fb9 100644 --- a/themes/envy/envy.theme.bash +++ b/themes/envy/envy.theme.bash @@ -1,19 +1,21 @@ -#!/usr/bin/env bash -SCM_THEME_PROMPT_DIRTY=" ${red}✗" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. + +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?}|" -VIRTUALENV_THEME_PROMPT_PREFIX="${green}ⓔ " +VIRTUALENV_THEME_PROMPT_PREFIX="${green?}ⓔ " VIRTUALENV_THEME_PROMPT_SUFFIX="" function prompt_command() { - PS1="\n$(virtualenv_prompt)${yellow}$(ruby_version_prompt) ${purple}\h ${reset_color}in ${green}\w\n${bold_cyan}$(scm_char)${green}$(scm_prompt_info) ${green}→${reset_color} " + PS1="\n$(virtualenv_prompt)${yellow?}$(ruby_version_prompt) ${purple?}\h ${reset_color?}in ${green?}\w\n${bold_cyan?}$(scm_char)${green?}$(scm_prompt_info) ${green?}→${reset_color?} " } safe_append_prompt_command prompt_command diff --git a/themes/font/font.theme.bash b/themes/font/font.theme.bash index 5af5e0e013..bf010b7352 100644 --- a/themes/font/font.theme.bash +++ b/themes/font/font.theme.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # # One line prompt showing the following configurable information # for git: @@ -22,20 +23,20 @@ # SCM_NONE_CHAR='' -SCM_THEME_PROMPT_DIRTY=" ${red}✗" +SCM_THEME_PROMPT_DIRTY=" ${red?}✗" SCM_THEME_PROMPT_CLEAN="" -SCM_THEME_PROMPT_PREFIX="${green}|" -SCM_THEME_PROMPT_SUFFIX="${green}|" +SCM_THEME_PROMPT_PREFIX="${green?}|" +SCM_THEME_PROMPT_SUFFIX="${green?}|" SCM_GIT_SHOW_MINIMAL_INFO=true CLOCK_THEME_PROMPT_PREFIX='' CLOCK_THEME_PROMPT_SUFFIX=' ' THEME_SHOW_CLOCK=false -THEME_CLOCK_COLOR=${THEME_CLOCK_COLOR:-"$bold_blue"} +THEME_CLOCK_COLOR=${THEME_CLOCK_COLOR:-"${bold_blue?}"} THEME_CLOCK_FORMAT=${THEME_CLOCK_FORMAT:-"%I:%M:%S"} THEME_SHOW_USER_HOST=true -USER_HOST_THEME_PROMPT_PREFIX="${bold_black}" +USER_HOST_THEME_PROMPT_PREFIX="${bold_black?}" USER_HOST_THEME_PROMPT_SUFFIX=" " VIRTUALENV_THEME_PROMPT_PREFIX='(' @@ -45,20 +46,20 @@ function prompt_command() { # This needs to be first to save last command return code local RC="$?" - hostname="${bold_black}\u@\h" - virtualenv="${white}$(virtualenv_prompt)" + hostname="${bold_black?}\u@\h" + virtualenv="${white?}$(virtualenv_prompt)" # Set return status color if [[ ${RC} == 0 ]]; then - ret_status="${bold_green}" + ret_status="${bold_green?}" else - ret_status="${bold_red}" + ret_status="${bold_red?}" fi # Append new history lines to history file history -a - PS1="$(clock_prompt)${virtualenv}$(user_host_prompt)${bold_cyan}\W $(scm_prompt_char_info)${ret_status}→ ${normal}" + PS1="$(clock_prompt)${virtualenv}$(user_host_prompt)${bold_cyan?}\W $(scm_prompt_char_info)${ret_status}→ ${normal?}" } safe_append_prompt_command prompt_command diff --git a/themes/gallifrey/gallifrey.theme.bash b/themes/gallifrey/gallifrey.theme.bash index cbffc78c46..2a529bede3 100644 --- a/themes/gallifrey/gallifrey.theme.bash +++ b/themes/gallifrey/gallifrey.theme.bash @@ -1,12 +1,14 @@ -# scm theming -SCM_THEME_PROMPT_PREFIX="${yellow}(" -SCM_THEME_PROMPT_SUFFIX=")${normal}" +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. + +SCM_THEME_PROMPT_PREFIX="${yellow?}(" +SCM_THEME_PROMPT_SUFFIX=")${normal?}" SCM_THEME_PROMPT_DIRTY="*" SCM_THEME_PROMPT_CLEAN="" -SCM_GIT_CHAR="${green}±${normal}" -SCM_SVN_CHAR="${bold_cyan}⑆${normal}" -SCM_HG_CHAR="${bold_red}☿${normal}" +SCM_GIT_CHAR="${green?}±${normal?}" +SCM_SVN_CHAR="${bold_cyan?}⑆${normal?}" +SCM_HG_CHAR="${bold_red?}☿${normal?}" ### TODO: openSUSE has already colors enabled, check if those differs from stock # LS colors, made with http://geoff.greer.fm/lscolors/ @@ -16,10 +18,10 @@ SCM_HG_CHAR="${bold_red}☿${normal}" gallifrey_prompt() { SCM_PROMPT_FORMAT='%s%s' - ps_host="${green}\h${normal}" - ps_user_mark="${bold}\$${normal}" - ps_root_mark="${normal}§" - ps_path="${normal}\w" + ps_host="${green?}\h${normal?}" + ps_user_mark="${bold?}\$${normal?}" + ps_root_mark="${normal?}§" + ps_path="${normal?}\w" # make it work case $(id -u) in diff --git a/themes/hawaii50/hawaii50.theme.bash b/themes/hawaii50/hawaii50.theme.bash index 6cba1553fd..25ad6a6a13 100644 --- a/themes/hawaii50/hawaii50.theme.bash +++ b/themes/hawaii50/hawaii50.theme.bash @@ -1,4 +1,5 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. # # This theme was obviously inspired a lot by # @@ -42,22 +43,22 @@ VIRTUAL_PROMPT_ENABLED=1 # COLORS ====================================================================== ORANGE='\[\e[0;33m\]' -DEFAULT_COLOR="${white}" +DEFAULT_COLOR="${white?}" -USER_COLOR="${purple}" -SUPERUSER_COLOR="${red}" +USER_COLOR="${purple?}" +SUPERUSER_COLOR="${red?}" MACHINE_COLOR=$ORANGE IP_COLOR=$ORANGE -DIRECTORY_COLOR="${green}" +DIRECTORY_COLOR="${green?}" -VE_COLOR="${cyan}" -RVM_COLOR="${cyan}" +VE_COLOR="${cyan?}" +RVM_COLOR="${cyan?}" -REF_COLOR="${purple}" +REF_COLOR="${purple?}" # SCM prompts -SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${normal}" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" +SCM_THEME_PROMPT_DIRTY=" ${bold_red?}✗${normal?}" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓${normal?}" SCM_THEME_PROMPT_PREFIX=' on ' SCM_THEME_PROMPT_SUFFIX='' @@ -85,7 +86,7 @@ IP_SEPARATOR=', ' function get_ip_info { myip=$(curl -s checkip.dyndns.org | grep -Eo '[0-9\.]+') - echo -e "$(ips | sed -e :a -e '$!N;s/\n/${IP_SEPARATOR}/;ta' | sed -e 's/127\.0\.0\.1\${IP_SEPARATOR}//g'), ${myip}" + echo -e "$(ips | sed -e :a -e "\$!N;s/\\n/${IP_SEPARATOR}/;ta" | sed -e "s/127\\.0\\.0\\.1\\${IP_SEPARATOR}//g"), ${myip}" } # Displays ip prompt @@ -97,9 +98,10 @@ function ip_prompt_info() { # Displays virtual info prompt (virtualenv/rvm) function virtual_prompt_info() { - local virtual_env_info=$(virtualenv_prompt) - local rvm_info=$(ruby_version_prompt) - local virtual_prompt="" + local virtual_env_info rvm_info virtual_prompt + virtual_env_info=$(virtualenv_prompt) + rvm_info=$(ruby_version_prompt) + virtual_prompt="" local prefix=${VIRTUAL_THEME_PROMPT_PREFIX} local suffix=${VIRTUAL_THEME_PROMPT_SUFFIX} @@ -119,7 +121,10 @@ function virtual_prompt_info() { # Parse git info function git_prompt_info() { - if [[ -n $(git status -s 2> /dev/null | grep -v ^# | grep -v "working directory clean") ]]; then + local dirty + dirty=$(git status --porcelain 2> /dev/null | tail -n 1) + + if [[ -n $dirty ]]; then state=${GIT_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY} else state=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} @@ -170,7 +175,7 @@ function limited_pwd() { # Replace $HOME with ~ if possible RELATIVE_PWD=${PWD/#$HOME/\~} - local offset=$((${#RELATIVE_PWD} - $MAX_PWD_LENGTH)) + local offset=$((${#RELATIVE_PWD} - MAX_PWD_LENGTH)) if [ $offset -gt "0" ]; then local truncated_symbol="..." @@ -187,9 +192,9 @@ function prompt() { [ $UID -eq "0" ] && UC=$SUPERUSER_COLOR if [[ $VIRTUAL_PROMPT_ENABLED == 1 ]]; then - PS1="$(scm_char) ${UC}\u ${DEFAULT_COLOR}at ${MACHINE_COLOR}\h$(ip_prompt_info) ${DEFAULT_COLOR}in ${DIRECTORY_COLOR}$(limited_pwd)${DEFAULT_COLOR}$(virtual_prompt_info)$(scm_prompt_info)${reset_color} \$ " + PS1="$(scm_char) ${UC}\u ${DEFAULT_COLOR}at ${MACHINE_COLOR}\h$(ip_prompt_info) ${DEFAULT_COLOR}in ${DIRECTORY_COLOR}$(limited_pwd)${DEFAULT_COLOR}$(virtual_prompt_info)$(scm_prompt_info)${reset_color?} \$ " else - PS1="$(scm_char) ${UC}\u ${DEFAULT_COLOR}at ${MACHINE_COLOR}\h$(ip_prompt_info) ${DEFAULT_COLOR}in ${DIRECTORY_COLOR}$(limited_pwd)${DEFAULT_COLOR}$(scm_prompt_info)${reset_color} \$ " + PS1="$(scm_char) ${UC}\u ${DEFAULT_COLOR}at ${MACHINE_COLOR}\h$(ip_prompt_info) ${DEFAULT_COLOR}in ${DIRECTORY_COLOR}$(limited_pwd)${DEFAULT_COLOR}$(scm_prompt_info)${reset_color?} \$ " fi PS2='> ' PS4='+ ' diff --git a/themes/iterate/iterate.theme.bash b/themes/iterate/iterate.theme.bash index 139d28c05c..009accb1cb 100644 --- a/themes/iterate/iterate.theme.bash +++ b/themes/iterate/iterate.theme.bash @@ -1,19 +1,21 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. + SCM_GIT_CHAR="± " SCM_HG_CHAR="☿ " SCM_SVN_CHAR="⑆ " SCM_NONE_CHAR="" -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_GIT_AHEAD_CHAR="${green}+" -SCM_GIT_BEHIND_CHAR="${red}-" +SCM_THEME_PROMPT_SUFFIX="${green?}| " +SCM_GIT_AHEAD_CHAR="${green?}+" +SCM_GIT_BEHIND_CHAR="${red?}-" -GIT_THEME_PROMPT_DIRTY=" ${bold_red}✗" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓" -GIT_THEME_PROMPT_PREFIX="${cyan}|" -GIT_THEME_PROMPT_SUFFIX="${cyan}| " +GIT_THEME_PROMPT_DIRTY=" ${bold_red?}✗" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +GIT_THEME_PROMPT_PREFIX="${cyan?}|" +GIT_THEME_PROMPT_SUFFIX="${cyan?}| " RVM_THEME_PROMPT_PREFIX="|" RVM_THEME_PROMPT_SUFFIX="| " @@ -42,8 +44,9 @@ function git_prompt_info { LAST_PROMPT="" function prompt_command() { - local new_PS1="${bold_cyan}$(scm_char)${yellow}$(ruby_version_prompt)${green}\w $(scm_prompt_info)" - local new_prompt=$(PS1="$new_PS1" "$BASH" --norc -i < /dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}') + local new_PS1 new_prompt + new_PS1="${bold_cyan?}$(scm_char)${yellow?}$(ruby_version_prompt)${green?}\w $(scm_prompt_info)" + new_prompt=$(PS1="$new_PS1" "$BASH" --norc -i < /dev/null 2>&1 | sed -n "\${s/^\(.*\)exit\$/\1/p;}") if [ "$LAST_PROMPT" = "$new_prompt" ]; then new_PS1="" @@ -52,8 +55,8 @@ function prompt_command() { fi local wrap_char="" - [[ $COLUMNS && ${#new_PS1} > $(($COLUMNS / 1)) ]] && wrap_char="\n" - PS1="${new_PS1}${green}${wrap_char}→${reset_color} " + [[ $COLUMNS && ${#new_PS1} -gt COLUMNS ]] && wrap_char="\n" + PS1="${new_PS1}${green?}${wrap_char}→${reset_color?} " } safe_append_prompt_command prompt_command diff --git a/themes/kitsune/kitsune.theme.bash b/themes/kitsune/kitsune.theme.bash index 3f767ddf42..268d6e5012 100644 --- a/themes/kitsune/kitsune.theme.bash +++ b/themes/kitsune/kitsune.theme.bash @@ -1,3 +1,6 @@ +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. + # This is combination of works from two different people which I combined for my requirement. # Original PS1 was from reddit user /u/Allevil669 which I found in thread: https://www.reddit.com/r/linux/comments/1z33lj/linux_users_whats_your_favourite_bash_prompt/ # I used that PS1 to the bash-it theme 'morris', and customized it to my liking. All credits to /u/Allevil669 and morris. @@ -16,21 +19,22 @@ case $TERM in TITLEBAR="" ;; esac +# shellcheck disable=SC2181 if [ "$?" == "0" ]; then - SC="${green}^_^" + SC="${green?}^_^" else - SC="${red}T_T" + SC="${red?}T_T" fi BC=$(battery_percentage) function prompt_command() { #PS1="${TITLEBAR}[\u@\h \W $(scm_prompt_info)]\$ " - PS1="\n${cyan}┌─${bold_white}[\u@\h]${cyan}─${bold_yellow}(\w)$(scm_prompt_info)\n${cyan}└─${bold_green}[\A]-${green}($BC%)${bold_cyan}-[${green}${bold_green}\$${bold_cyan}]${green} " + PS1="\n${cyan?}┌─${bold_white?}[\u@\h]${cyan?}─${bold_yellow?}(\w)$(scm_prompt_info)\n${cyan?}└─${bold_green?}[\A]-${green?}($BC%)${bold_cyan?}-[${green?}${bold_green?}\$${bold_cyan?}]${green?} " } # scm theming -SCM_THEME_PROMPT_DIRTY=" ${red}✗" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" -SCM_THEME_PROMPT_PREFIX="${bold_cyan}(" -SCM_THEME_PROMPT_SUFFIX="${bold_cyan})${reset_color}" +SCM_THEME_PROMPT_DIRTY=" ${red?}✗" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +SCM_THEME_PROMPT_PREFIX="${bold_cyan?}(" +SCM_THEME_PROMPT_SUFFIX="${bold_cyan?})${reset_color?}" safe_append_prompt_command prompt_command diff --git a/themes/liquidprompt/liquidprompt.theme.bash b/themes/liquidprompt/liquidprompt.theme.bash index a9eb27663f..471e710f09 100644 --- a/themes/liquidprompt/liquidprompt.theme.bash +++ b/themes/liquidprompt/liquidprompt.theme.bash @@ -1,86 +1,95 @@ -#!/usr/bin/env bash -# Wrapper to use liquidprompt with bashit +# shellcheck shell=bash +# shellcheck disable=SC2034 # expected behavior for themes +# Wrapper to use liquidprompt with _Bash It_ -targetdir="$BASH_IT/themes/liquidprompt/liquidprompt" gray="\[\e[1;90m\]" -cwd="$PWD" -if cd "$targetdir" &> /dev/null && git rev-parse --is-inside-work-tree &> /dev/null; then - true -else - git clone https://github.com/nojhan/liquidprompt.git "$targetdir" \ - && echo -e "Successfully cloned liquidprompt!\n More configuration in '$targetdir/liquid.theme'." +## Download repository if needed +__bash_it_theme_liquidprompt_path="github.com/nojhan/liquidprompt" +__bash_it_theme_liquidprompt_dir="${BASH_IT?}/vendor/${__bash_it_theme_liquidprompt_path}" +if [[ ! -d "${__bash_it_theme_liquidprompt_dir}" ]]; then + if git clone --branch stable "https://${__bash_it_theme_liquidprompt_path}" "${__bash_it_theme_liquidprompt_dir}"; then + __bash_it_theme_liquidprompt_lqprc="${XDG_CONFIG_HOME:-"$HOME/.config"}/liquidpromptrc" + __bash_it_theme_liquidprompt_tilde='~' + if [[ ! -e "${__bash_it_theme_liquidprompt_lqprc}" ]]; then + # shellcheck disable=SC2016 disable=SC1003 + sed -e 's/^LP_/#LP_/g' -e 's;#LOCAL_RCFILE=$HOME/.liquidpromptrc.local;LOCAL_RCFILE=${BASH_SOURCE[0]}.local;g' -e 's/#\[ -f "$LOCAL_RCFILE" \] && source "$LOCAL_RCFILE"/if [[ -s $LOCAL_RCFILE ]]; then\'$'\n\t''source "$LOCAL_RCFILE"\'$'\n''fi/g' < "${__bash_it_theme_liquidprompt_dir}/liquidpromptrc-dist" > "${__bash_it_theme_liquidprompt_lqprc}" + fi + echo -e "Successfully cloned liquidprompt!\n More configuration in '${__bash_it_theme_liquidprompt_lqprc//$HOME/$__bash_it_theme_liquidprompt_tilde}' (or '${__bash_it_theme_liquidprompt_lqprc//$HOME/$__bash_it_theme_liquidprompt_tilde}.local')." + fi fi -cd "$cwd" - -export LP_ENABLE_TIME=1 -export LP_HOSTNAME_ALWAYS=1 -export LP_USER_ALWAYS=1 -export LP_MARK_LOAD="📈 " -export LP_BATTERY_THRESHOLD=${LP_BATTERY_THRESHOLD:-75} -export LP_LOAD_THRESHOLD=${LP_LOAD_THRESHOLD:-60} -export LP_TEMP_THRESHOLD=${LP_TEMP_THRESHOLD:-80} - -unset _lp_legacy _lp_escape __lp_escape -source "$targetdir/liquidprompt" -prompt() { true; } -export PS2=" ┃ " -export LP_PS1_PREFIX="┌─" -export LP_PS1_POSTFIX="\n└▪ " -export LP_ENABLE_RUNTIME=0 -_lp_legacy() { - type -t _lp_escape &> /dev/null -} +## Configure theme +LP_MARK_LOAD="📈 " +: "${LP_ENABLE_TIME:=1}" +: "${LP_HOSTNAME_ALWAYS:=1}" +: "${LP_USER_ALWAYS:=1}" +: "${LP_BATTERY_THRESHOLD:=75}" +: "${LP_LOAD_THRESHOLD:=60}" +: "${LP_TEMP_THRESHOLD:=80}" -_lp_legacy && __lp_escape() { - ret="$(_lp_escape "$@")" -} +## Load theme, but don't activate +# shellcheck source-path=SCRIPTDIR/../../vendor/github.com/nojhan/liquidprompt +source "${__bash_it_theme_liquidprompt_dir}/liquidprompt" --no-activate -_lp_git_branch() { - ((LP_ENABLE_GIT)) || return +## Activate theme, without clobbering `bash-preexec` +LP_OLD_PS1="${PROMPT:-${PS1:-\$ }}" +LP_OLD_PROMPT_COMMAND="" +function prompt_on() { :; } +function prompt_off() { :; } +function prompt_OFF() { :; } +# shellcheck disable=SC2119 +TERM_PROGRAM=not_apple_terminal LP_ENABLE_RUNTIME=0 LP_ENABLE_RUNTIME_BELL=0 lp_activate +safe_append_preexec '__lp_runtime_before' +safe_append_prompt_command '__lp_set_prompt' - \git rev-parse --is-inside-work-tree > /dev/null 2>&1 || return +## Override upstream defaults +PS2=" ┃ " +LP_PS1_PREFIX="┌─" +LP_PS1_POSTFIX="\n└▪ " +LP_ENABLE_RUNTIME=0 - local commit branch ret +function _lp_git_branch() { + ((${LP_ENABLE_GIT:-0})) || return - commit="$(\git rev-parse --short -q HEAD 2> /dev/null)" + command git rev-parse --is-inside-work-tree > /dev/null 2>&1 || return + local branch # Recent versions of Git support the --short option for symbolic-ref, but # not 1.7.9 (Ubuntu 12.04) - if branch="$(\git symbolic-ref -q HEAD)"; then - __lp_escape "$commit:${branch#refs/heads/}" - lp_vcs_branch="$ret" + if branch="$(command git symbolic-ref -q HEAD)"; then + _lp_escape "$(command git rev-parse --short=5 -q HEAD 2> /dev/null):${branch#refs/heads/}" else # In detached head state, use commit instead # No escape needed - lp_vcs_branch="$commit" + command git rev-parse --short -q HEAD 2> /dev/null fi - _lp_legacy && echo $lp_vcs_branch || return 0 } -_lp_time() { - if ((LP_ENABLE_TIME)) && ((!LP_TIME_ANALOG)); then - LP_TIME="${gray}$(date +%d-%H:%M)${normal}" +function _lp_time() { + if ((LP_ENABLE_TIME)) && ((!${LP_TIME_ANALOG:-0})); then + LP_TIME="${gray?}\D{${THEME_CLOCK_FORMAT:-"%d-%H:%M"}}${normal?}" else LP_TIME="" fi } # Implementation using lm-sensors -_lp_temp_sensors() { +function _lp_temp_sensors() { local -i i for i in $(sensors -u \ | sed -n 's/^ temp[0-9][0-9]*_input: \([0-9]*\)\..*$/\1/p'); do - (($i > ${temperature:-0})) && (($i != 127)) && temperature=i + ((i > ${temperature:-0})) && ((i != 127)) && temperature=i done } # Implementation using 'acpi -t' -_lp_temp_acpi() { +function _lp_temp_acpi() { local -i i for i in $(LANG=C acpi -t \ | sed 's/.* \(-\?[0-9]*\)\.[0-9]* degrees C$/\1/p'); do - (($i > ${temperature:-0})) && (($i != 127)) && temperature=i + ((i > ${temperature:-0})) && ((i != 127)) && temperature=i done } + +unset "${!__bash_it_theme_liquidprompt_@}" diff --git a/themes/luan/luan.theme.bash b/themes/luan/luan.theme.bash index d5f0331f44..9e0f167404 100644 --- a/themes/luan/luan.theme.bash +++ b/themes/luan/luan.theme.bash @@ -1,33 +1,34 @@ -#!/usr/bin/env bash +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. -SCM_THEME_PROMPT_DIRTY=" ${red}✗" -SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" -SCM_THEME_PROMPT_PREFIX="(${yellow}" -SCM_THEME_PROMPT_SUFFIX="${normal})" +SCM_THEME_PROMPT_DIRTY=" ${red?}✗" +SCM_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +SCM_THEME_PROMPT_PREFIX="(${yellow?}" +SCM_THEME_PROMPT_SUFFIX="${normal?})" -GIT_THEME_PROMPT_DIRTY=" ${red}✗" -GIT_THEME_PROMPT_CLEAN=" ${bold_green}✓" -GIT_THEME_PROMPT_PREFIX="(${yellow}" -GIT_THEME_PROMPT_SUFFIX="${normal})" +GIT_THEME_PROMPT_DIRTY=" ${red?}✗" +GIT_THEME_PROMPT_CLEAN=" ${bold_green?}✓" +GIT_THEME_PROMPT_PREFIX="(${yellow?}" +GIT_THEME_PROMPT_SUFFIX="${normal?})" RVM_THEME_PROMPT_PREFIX="" RVM_THEME_PROMPT_SUFFIX="" function prompt_command() { dtime="$(clock_prompt)" - user_host="${green}\u@${cyan}\h${normal}" - current_dir="${bold_blue}\w${normal}" - rvm_ruby="${bold_red}$(ruby_version_prompt)${normal}" - git_branch="$(scm_prompt_info)${normal}" - prompt="${bold_green}\$${normal} " - arrow="${bold_white}▶${normal} " - prompt="${bold_green}\$${normal} " + user_host="${green?}\u@${cyan?}\h${normal?}" + current_dir="${bold_blue?}\w${normal?}" + rvm_ruby="${bold_red?}$(ruby_version_prompt)${normal?}" + git_branch="$(scm_prompt_info)${normal?}" + prompt="${bold_green?}\$${normal?} " + arrow="${bold_white?}▶${normal?} " + prompt="${bold_green?}\$${normal?} " PS1="${dtime}${user_host}:${current_dir} ${rvm_ruby} ${git_branch} $arrow $prompt" } -THEME_CLOCK_COLOR=${THEME_CLOCK_COLOR:-"$yellow"} +THEME_CLOCK_COLOR=${THEME_CLOCK_COLOR:-"${yellow?}"} THEME_CLOCK_FORMAT=${THEME_TIME_FORMAT:-"%I:%M:%S "} safe_append_prompt_command prompt_command diff --git a/themes/modern/modern.theme.bash b/themes/modern/modern.theme.bash index eadb07624f..2aecb90016 100644 --- a/themes/modern/modern.theme.bash +++ b/themes/modern/modern.theme.bash @@ -1,17 +1,16 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. -# shellcheck disable=SC2154 #TODO: fix these all. 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="${bold_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=" ${bold_green?}✓${normal?}" +SCM_GIT_CHAR="${bold_green?}±${normal?}" +SCM_SVN_CHAR="${bold_cyan?}⑆${normal?}" +SCM_HG_CHAR="${bold_red?}☿${normal?}" -case $TERM in +case "${TERM:-dumb}" in xterm*) TITLEBAR="\[\033]0;\w\007\]" ;; @@ -22,32 +21,34 @@ esac PS3=">> " -is_vim_shell() { - if [ -n "$VIMRUNTIME" ]; then - echo "[${cyan}vim shell${normal}]" +function is_vim_shell() { + if [[ -n "${VIMRUNTIME:-}" ]]; then + echo "[${cyan?}vim shell${normal?}]" fi } -detect_venv() { - python_venv="" +function detect_venv() { + local python_venv="" # Detect python venv - 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}")) " + if [[ -n "${CONDA_DEFAULT_ENV:-}" ]]; then + python_venv="(${PYTHON_VENV_CHAR}${CONDA_DEFAULT_ENV}) " + elif [[ -n "${VIRTUAL_ENV:-}" ]]; then + python_venv="(${PYTHON_VENV_CHAR}${VIRTUAL_ENV##*/}) " fi } -prompt() { - SCM_PROMPT_FORMAT='[%s][%s]' - retval=$? +function prompt() { + local retval=$? scm_prompt is_vim_shell python_venv + local SCM_PROMPT_FORMAT='[%s][%s]' + scm_prompt="$(scm_prompt)" + is_vim_shell="$(is_vim_shell)" if [[ retval -ne 0 ]]; then - PS1="${TITLEBAR}${bold_red}┌─${reset_color}$(scm_prompt)[${cyan}\u${normal}][${cyan}\w${normal}]$(is_vim_shell)\n${bold_red}└─▪${normal} " + PS1="${TITLEBAR:-}${bold_red?}┌─${reset_color?}${scm_prompt}[${cyan?}\u${normal?}][${cyan?}\w${normal?}]${is_vim_shell}\n${bold_red?}└─▪${normal?} " else - PS1="${TITLEBAR}┌─$(scm_prompt)[${cyan}\u${normal}][${cyan}\w${normal}]$(is_vim_shell)\n└─▪ " + PS1="${TITLEBAR:-}┌─${scm_prompt}[${cyan?}\u${normal?}][${cyan?}\w${normal?}]${is_vim_shell}\n└─▪ " fi detect_venv - PS1+="${python_venv}${dir_color}" + PS1+="${python_venv?}${dir_color?}" } PS2="└─▪ " diff --git a/themes/powerline-multiline/powerline-multiline.base.bash b/themes/powerline-multiline/powerline-multiline.base.bash index 8270aa5bb3..02bbf39eb8 100644 --- a/themes/powerline-multiline/powerline-multiline.base.bash +++ b/themes/powerline-multiline/powerline-multiline.base.bash @@ -1,107 +1,121 @@ -. "$BASH_IT/themes/powerline/powerline.base.bash" - -function __powerline_last_status_prompt { - [[ "$1" -ne 0 ]] && echo "$(set_color ${LAST_STATUS_THEME_PROMPT_COLOR} -) ${1} ${normal}" -} - -function __powerline_right_segment { - local OLD_IFS="${IFS}" - IFS="|" - local params=($1) - IFS="${OLD_IFS}" - local padding=0 +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. +# shellcheck source-path=SCRIPTDIR/../powerline +source "${BASH_IT?}/themes/powerline/powerline.base.bash" + +function __powerline_right_segment() { + local -a params + IFS="|" read -ra params <<< "${1}" local pad_before_segment=" " + local padding=0 if [[ "${SEGMENTS_AT_RIGHT}" -eq 0 ]]; then - if [[ "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT}" -ne 0 ]]; then + if [[ "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:-${POWERLINE_COMPACT:-0}}" -ne 0 ]]; then pad_before_segment="" fi - RIGHT_PROMPT+="$(set_color ${params[1]} -)${POWERLINE_RIGHT_END}${normal}" + RIGHT_PROMPT+="$(set_color "${params[1]:-}" -)${POWERLINE_RIGHT_LAST_SEGMENT_END_CHAR:-}${normal?}" ((padding += 1)) else - if [[ "${POWERLINE_COMPACT_BEFORE_SEPARATOR}" -ne 0 ]]; then + if [[ "${POWERLINE_COMPACT_BEFORE_SEPARATOR:-}" -ne 0 ]]; then pad_before_segment="" fi # Since the previous segment wasn't the last segment, add padding, if needed # - if [[ "${POWERLINE_COMPACT_AFTER_SEPARATOR}" -eq 0 ]]; then - RIGHT_PROMPT+="$(set_color - ${LAST_SEGMENT_COLOR}) ${normal}" + if [[ "${POWERLINE_COMPACT_AFTER_SEPARATOR:-0}" -eq 0 ]]; then + RIGHT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR?}") ${normal}" ((padding += 1)) fi - if [[ "${LAST_SEGMENT_COLOR}" -eq "${params[1]}" ]]; then - RIGHT_PROMPT+="$(set_color - ${LAST_SEGMENT_COLOR})${POWERLINE_RIGHT_SEPARATOR_SOFT}${normal}" + if [[ "${LAST_SEGMENT_COLOR}" -eq "${params[1]:-}" ]]; then + RIGHT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR?}")${POWERLINE_RIGHT_SEPARATOR_SOFT- }${normal?}" else - RIGHT_PROMPT+="$(set_color ${params[1]} ${LAST_SEGMENT_COLOR})${POWERLINE_RIGHT_SEPARATOR}${normal}" + RIGHT_PROMPT+="$(set_color "${params[1]:-}" "${LAST_SEGMENT_COLOR?}")${POWERLINE_RIGHT_SEPARATOR- }${normal?}" fi ((padding += 1)) fi - RIGHT_PROMPT+="$(set_color "${POWERLINE_PROMPT_FOREGROUND_COLOR}" ${params[1]})${pad_before_segment}${params[0]}${normal}" + RIGHT_PROMPT+="$(set_color - "${params[1]:-}")${pad_before_segment}${params[0]}${normal?}" ((padding += ${#pad_before_segment})) ((padding += ${#params[0]})) ((RIGHT_PROMPT_LENGTH += padding)) - LAST_SEGMENT_COLOR="${params[1]}" + LAST_SEGMENT_COLOR="${params[1]:-}" ((SEGMENTS_AT_RIGHT += 1)) } -function __powerline_right_first_segment_padding { - RIGHT_PROMPT+="$(set_color - ${LAST_SEGMENT_COLOR}) ${normal}" +function __powerline_right_first_segment_padding() { + RIGHT_PROMPT+="$(set_color - "${LAST_SEGMENT_COLOR?}") ${normal?}" ((RIGHT_PROMPT_LENGTH += 1)) } -function __powerline_prompt_command { +function __powerline_last_status_prompt() { + if [[ "${1}" -ne 0 ]]; then + printf '%b %s %b' "$(set_color "${LAST_STATUS_THEME_PROMPT_COLOR-"52"}" -)" "${1}" "${normal?}" + fi +} + +function __powerline_prompt_command() { local last_status="$?" ## always the first - local move_cursor_rightmost='\033[500C' + local beginning_of_line='\[\e[B\]' + local move_cursor_rightmost='\e[500C' + local info prompt_color segment prompt - LEFT_PROMPT="" - RIGHT_PROMPT="" - RIGHT_PROMPT_LENGTH=${POWERLINE_PADDING} - SEGMENTS_AT_LEFT=0 - SEGMENTS_AT_RIGHT=0 - LAST_SEGMENT_COLOR="" + local LEFT_PROMPT="" + local RIGHT_PROMPT="" + local RIGHT_PROMPT_LENGTH=${POWERLINE_PADDING:-2} + local SEGMENTS_AT_LEFT=0 + local SEGMENTS_AT_RIGHT=0 + local LAST_SEGMENT_COLOR="" _save-and-reload-history "${HISTORY_AUTOSAVE:-0}" + if [[ -n "${POWERLINE_PROMPT_DISTRO_LOGO:-}" ]]; then + LEFT_PROMPT+="$(set_color "${PROMPT_DISTRO_LOGO_COLOR?}" "${PROMPT_DISTRO_LOGO_COLORBG?}")${PROMPT_DISTRO_LOGO?}$(set_color - -)" + fi + ## left prompt ## - for segment in $POWERLINE_LEFT_PROMPT; do - local info="$(__powerline_${segment}_prompt)" - [[ -n "${info}" ]] && __powerline_left_segment "${info}" + # shellcheck disable=SC2068 # intended behavior + for segment in ${POWERLINE_LEFT_PROMPT[@]:-${POWERLINE_PROMPT[@]:-"user_info" "scm" "python_venv" "ruby node" "cwd"}}; do + info="$("__powerline_${segment}_prompt")" + if [[ -n "${info}" ]]; then + __powerline_left_segment "${info}" + fi done - if [[ -n "${LEFT_PROMPT}" ]] && [[ "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT}" -eq 0 ]]; then + if [[ -n "${LEFT_PROMPT:-}" && "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:-${POWERLINE_COMPACT:-0}}" -eq 0 ]]; then __powerline_left_last_segment_padding fi - [[ -n "${LEFT_PROMPT}" ]] && LEFT_PROMPT+="$(set_color ${LAST_SEGMENT_COLOR} -)${POWERLINE_LEFT_END}${normal}" + # By default we try to match the prompt to the adjacent segment's background color, + # but when part of the prompt exists within that segment, we instead match the foreground color. + prompt_color="$(set_color "${LAST_SEGMENT_COLOR?}" -)" + if [[ -n "${LEFT_PROMPT:-}" && -n "${POWERLINE_LEFT_LAST_SEGMENT_END_CHAR:-}" ]]; then + LEFT_PROMPT+="$(set_color "${LAST_SEGMENT_COLOR?}" -)${POWERLINE_LEFT_LAST_SEGMENT_END_CHAR}" + prompt_color="${normal?}" + fi ## right prompt ## - if [[ -n "${POWERLINE_RIGHT_PROMPT}" ]]; then + if [[ -n "${POWERLINE_RIGHT_PROMPT[*]:-}" ]]; then # LEFT_PROMPT+="${move_cursor_rightmost}" - for segment in $POWERLINE_RIGHT_PROMPT; do - local info="$(__powerline_${segment}_prompt)" + # shellcheck disable=SC2068 # intended behavior + for segment in ${POWERLINE_RIGHT_PROMPT[@]}; do + info="$("__powerline_${segment}_prompt")" [[ -n "${info}" ]] && __powerline_right_segment "${info}" done - if [[ -n "${RIGHT_PROMPT}" ]] && [[ "${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT}" -eq 0 ]]; then + if [[ -n "${RIGHT_PROMPT:-}" && "${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT:-${POWERLINE_COMPACT:-0}}" -eq 0 ]]; then __powerline_right_first_segment_padding fi - RIGHT_PAD=$(printf "%.s " $(seq 1 $RIGHT_PROMPT_LENGTH)) + RIGHT_PAD=$(printf "%.s " $(seq 1 "${RIGHT_PROMPT_LENGTH}")) LEFT_PROMPT+="${RIGHT_PAD}${move_cursor_rightmost}" LEFT_PROMPT+="\033[$((${#RIGHT_PAD} - 1))D" fi - local prompt="${PROMPT_CHAR}" - if [[ "${POWERLINE_COMPACT_PROMPT}" -eq 0 ]]; then + prompt="${prompt_color}${PROMPT_CHAR-${POWERLINE_PROMPT_CHAR-\\$}}${normal?}" + if [[ "${POWERLINE_COMPACT_PROMPT:-${POWERLINE_COMPACT:-0}}" -eq 0 ]]; then prompt+=" " fi - PS1="${LEFT_PROMPT}${RIGHT_PROMPT}\n$(__powerline_last_status_prompt ${last_status})${prompt}" - - ## cleanup ## - unset LAST_SEGMENT_COLOR \ - LEFT_PROMPT RIGHT_PROMPT RIGHT_PROMPT_LENGTH \ - SEGMENTS_AT_LEFT SEGMENTS_AT_RIGHT + PS1="${beginning_of_line}${normal?}${LEFT_PROMPT}${RIGHT_PROMPT}\n$(__powerline_last_status_prompt "${last_status}")${prompt}" } diff --git a/themes/powerline-multiline/powerline-multiline.theme.bash b/themes/powerline-multiline/powerline-multiline.theme.bash index 2bca81c146..cc6a3b44f0 100644 --- a/themes/powerline-multiline/powerline-multiline.theme.bash +++ b/themes/powerline-multiline/powerline-multiline.theme.bash @@ -1,22 +1,23 @@ -#!/usr/bin/env bash - -. "$BASH_IT/themes/powerline-multiline/powerline-multiline.base.bash" +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. +# shellcheck source-path=SCRIPTDIR/../powerline-multiline +source "${BASH_IT?}/themes/powerline-multiline/powerline-multiline.base.bash" PROMPT_CHAR=${POWERLINE_PROMPT_CHAR:="❯"} -POWERLINE_LEFT_SEPARATOR=${POWERLINE_LEFT_SEPARATOR:=""} -POWERLINE_LEFT_SEPARATOR_SOFT=${POWERLINE_LEFT_SEPARATOR_SOFT:=""} -POWERLINE_RIGHT_SEPARATOR=${POWERLINE_RIGHT_SEPARATOR:=""} -POWERLINE_RIGHT_SEPARATOR_SOFT=${POWERLINE_RIGHT_SEPARATOR_SOFT:=""} -POWERLINE_LEFT_END=${POWERLINE_LEFT_END:=""} -POWERLINE_RIGHT_END=${POWERLINE_RIGHT_END:=""} -POWERLINE_PADDING=${POWERLINE_PADDING:=2} - -POWERLINE_COMPACT=${POWERLINE_COMPACT:=0} -POWERLINE_COMPACT_BEFORE_SEPARATOR=${POWERLINE_COMPACT_BEFORE_SEPARATOR:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_AFTER_SEPARATOR=${POWERLINE_COMPACT_AFTER_SEPARATOR:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_BEFOR_FIRST_SEGMENT=${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_AFTER_LAST_SEGMENT=${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_PROMPT=${POWERLINE_COMPACT_PROMPT:=${POWERLINE_COMPACT}} +: "${POWERLINE_LEFT_SEPARATOR:=""}" +: "${POWERLINE_LEFT_SEPARATOR_SOFT:=""}" +: "${POWERLINE_RIGHT_SEPARATOR:=""}" +: "${POWERLINE_RIGHT_SEPARATOR_SOFT:=""}" +: "${POWERLINE_LEFT_LAST_SEGMENT_END_CHAR:=""}" +: "${POWERLINE_RIGHT_LAST_SEGMENT_END_CHAR:=""}" +: "${POWERLINE_PADDING:=2}" + +: "${POWERLINE_COMPACT:=0}" +: "${POWERLINE_COMPACT_BEFORE_SEPARATOR:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_AFTER_SEPARATOR:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_PROMPT:=${POWERLINE_COMPACT}}" POWERLINE_PROMPT_FOREGROUND_COLOR=${POWERLINE_PROMPT_FOREGROUND_COLOR:=-} @@ -44,13 +45,13 @@ NVM_THEME_PROMPT_SUFFIX="" NODE_THEME_PROMPT_PREFIX="" NODE_THEME_PROMPT_SUFFIX="" NODE_CHAR=${POWERLINE_NODE_CHAR:="❲n❳ "} -NODE_THEME_PROMPT_COLOR=${POWERLINE_NODE_COLOR:=22} +NODE_THEME_PROMPT_COLOR=${POWERLINE_NODE_COLOR:=28} RVM_THEME_PROMPT_PREFIX="" RVM_THEME_PROMPT_SUFFIX="" RBENV_THEME_PROMPT_PREFIX="" RBENV_THEME_PROMPT_SUFFIX="" -RUBY_THEME_PROMPT_COLOR=${POWERLINE_RUBY_COLOR:=161} +RUBY_THEME_PROMPT_COLOR=${POWERLINE_RUBY_COLOR:=1} RUBY_CHAR=${POWERLINE_RUBY_CHAR:="❲r❳ "} TERRAFORM_THEME_PROMPT_COLOR=${POWERLINE_TERRAFORM_COLOR:=161} @@ -71,12 +72,12 @@ LAST_STATUS_THEME_PROMPT_COLOR=${POWERLINE_LAST_STATUS_COLOR:=196} CLOCK_THEME_PROMPT_COLOR=${POWERLINE_CLOCK_COLOR:=240} -BATTERY_AC_CHAR=${BATTERY_AC_CHAR:="⚡"} +: "${BATTERY_AC_CHAR:="⚡"}" BATTERY_STATUS_THEME_PROMPT_GOOD_COLOR=${POWERLINE_BATTERY_GOOD_COLOR:=70} BATTERY_STATUS_THEME_PROMPT_LOW_COLOR=${POWERLINE_BATTERY_LOW_COLOR:=208} BATTERY_STATUS_THEME_PROMPT_CRITICAL_COLOR=${POWERLINE_BATTERY_CRITICAL_COLOR:=160} -THEME_CLOCK_FORMAT=${THEME_CLOCK_FORMAT:="%H:%M:%S"} +: "${THEME_CLOCK_FORMAT:="%H:%M:%S"}" IN_VIM_THEME_PROMPT_COLOR=${POWERLINE_IN_VIM_COLOR:=245} IN_VIM_THEME_PROMPT_TEXT=${POWERLINE_IN_VIM_TEXT:="vim"} @@ -103,7 +104,7 @@ GCLOUD_CHAR=${POWERLINE_GCLOUD_CHAR:="❲G❳ "} COMMAND_DURATION_PROMPT_COLOR=${POWERLINE_COMMAND_DURATION_COLOR:=129} -POWERLINE_LEFT_PROMPT=${POWERLINE_LEFT_PROMPT:="scm python_venv ruby node cwd"} -POWERLINE_RIGHT_PROMPT=${POWERLINE_RIGHT_PROMPT:="in_vim clock battery user_info"} +: "${POWERLINE_LEFT_PROMPT:="scm python_venv ruby node cwd"}" +: "${POWERLINE_RIGHT_PROMPT:="in_vim clock battery user_info"}" safe_append_prompt_command __powerline_prompt_command diff --git a/themes/powerline-naked/powerline-naked.base.bash b/themes/powerline-naked/powerline-naked.base.bash index 6e3b21667c..54ecbdca15 100644 --- a/themes/powerline-naked/powerline-naked.base.bash +++ b/themes/powerline-naked/powerline-naked.base.bash @@ -1,9 +1,11 @@ -. "$BASH_IT/themes/powerline/powerline.base.bash" +# shellcheck shell=bash +# shellcheck disable=SC2034,SC1091 # Expected behavior for themes. +source "${BASH_IT?}/themes/powerline/powerline.base.bash" function __powerline_left_segment { - local OLD_IFS="${IFS}" - IFS="|" - local params=($1) + local OLD_IFS="${IFS}" params=() + # shellcheck disable=SC2206 # not needed because we are splitting on "|" + IFS="|" params=($1) IFS="${OLD_IFS}" local separator="" local pad_before_segment=" " @@ -18,19 +20,21 @@ function __powerline_left_segment { fi # Since the previous segment wasn't the last segment, add padding, if needed # - if [[ "${POWERLINE_COMPACT_BEFORE_SEPARATOR}" -eq 0 ]]; then + if [[ "${POWERLINE_COMPACT_BEFORE_SEPARATOR:-0}" -eq 0 ]]; then LEFT_PROMPT+=" " fi LEFT_PROMPT+="${POWERLINE_LEFT_SEPARATOR}" fi - LEFT_PROMPT+="$(set_color ${params[1]} -)${pad_before_segment}${params[0]}${normal}" - LAST_SEGMENT_COLOR=${params[1]} + #change here to cahnge fg color + LEFT_PROMPT+="$(set_color "${params[1]:-}" -)${pad_before_segment}${params[0]}${normal?}" + #seperator char color == current bg + LAST_SEGMENT_COLOR="${params[1]:-}" ((SEGMENTS_AT_LEFT += 1)) _save-and-reload-history "${HISTORY_AUTOSAVE:-0}" } function __powerline_left_last_segment_padding { - LEFT_PROMPT+="$(set_color ${LAST_SEGMENT_COLOR} -) ${normal}" + LEFT_PROMPT+="$(set_color "${LAST_SEGMENT_COLOR?}" -) ${normal?}" } diff --git a/themes/powerline-naked/powerline-naked.theme.bash b/themes/powerline-naked/powerline-naked.theme.bash index 934a315079..811fa39e27 100644 --- a/themes/powerline-naked/powerline-naked.theme.bash +++ b/themes/powerline-naked/powerline-naked.theme.bash @@ -1,17 +1,18 @@ -#!/usr/bin/env bash - -. "$BASH_IT/themes/powerline-naked/powerline-naked.base.bash" +# shellcheck shell=bash +# shellcheck disable=SC2034 # Expected behavior for themes. +# shellcheck source-path=SCRIPTDIR/../powerline +source "${BASH_IT?}/themes/powerline/powerline.base.bash" PROMPT_CHAR=${POWERLINE_PROMPT_CHAR:=""} -POWERLINE_LEFT_SEPARATOR=${POWERLINE_LEFT_SEPARATOR:=""} +: "${POWERLINE_LEFT_SEPARATOR:=""}" POWERLINE_LEFT_LAST_SEGMENT_PROMPT_CHAR="" -POWERLINE_COMPACT=${POWERLINE_COMPACT:=0} -POWERLINE_COMPACT_BEFORE_SEPARATOR=${POWERLINE_COMPACT_BEFORE_SEPARATOR:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_AFTER_SEPARATOR=${POWERLINE_COMPACT_AFTER_SEPARATOR:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_BEFOR_FIRST_SEGMENT=${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_AFTER_LAST_SEGMENT=${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:=${POWERLINE_COMPACT}} -POWERLINE_COMPACT_PROMPT=${POWERLINE_COMPACT_PROMPT:=${POWERLINE_COMPACT}} +: "${POWERLINE_COMPACT:=0}" +: "${POWERLINE_COMPACT_BEFORE_SEPARATOR:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_AFTER_SEPARATOR:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_BEFORE_FIRST_SEGMENT:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_AFTER_LAST_SEGMENT:=${POWERLINE_COMPACT}}" +: "${POWERLINE_COMPACT_PROMPT:=${POWERLINE_COMPACT}}" POWERLINE_PROMPT_FOREGROUND_COLOR=${POWERLINE_PROMPT_FOREGROUND_COLOR:=-} @@ -66,12 +67,12 @@ LAST_STATUS_THEME_PROMPT_COLOR=${POWERLINE_LAST_STATUS_COLOR:=124} CLOCK_THEME_PROMPT_COLOR=${POWERLINE_CLOCK_COLOR:=240} -BATTERY_AC_CHAR=${BATTERY_AC_CHAR:="⚡"} +: "${BATTERY_AC_CHAR:="⚡"}" BATTERY_STATUS_THEME_PROMPT_GOOD_COLOR=${POWERLINE_BATTERY_GOOD_COLOR:=70} BATTERY_STATUS_THEME_PROMPT_LOW_COLOR=${POWERLINE_BATTERY_LOW_COLOR:=208} BATTERY_STATUS_THEME_PROMPT_CRITICAL_COLOR=${POWERLINE_BATTERY_CRITICAL_COLOR:=160} -THEME_CLOCK_FORMAT=${THEME_CLOCK_FORMAT:="%H:%M:%S"} +: "${THEME_CLOCK_FORMAT:="%H:%M:%S"}" IN_VIM_THEME_PROMPT_COLOR=${POWERLINE_IN_VIM_COLOR:=245} IN_VIM_THEME_PROMPT_TEXT=${POWERLINE_IN_VIM_TEXT:="vim"} @@ -96,6 +97,6 @@ COMMAND_NUMBER_THEME_PROMPT_CHAR=${POWERLINE_COMMAND_NUMBER_CHAR:="#"} GCLOUD_THEME_PROMPT_COLOR=${POWERLINE_GCLOUD_COLOR:=161} GCLOUD_CHAR=${POWERLINE_GCLOUD_CHAR:="❲G❳ "} -POWERLINE_PROMPT=${POWERLINE_PROMPT:="user_info scm python_venv ruby node cwd"} +: "${POWERLINE_PROMPT:="user_info scm python_venv ruby node cwd"}" safe_append_prompt_command __powerline_prompt_command diff --git a/themes/powerline/powerline.base.bash b/themes/powerline/powerline.base.bash index e7ae8ede7f..85ba0dce93 100644 --- a/themes/powerline/powerline.base.bash +++ b/themes/powerline/powerline.base.bash @@ -280,7 +280,7 @@ function __powerline_left_last_segment_padding() { } function __powerline_last_status_prompt() { - if [[ "${1?}" -ne 0 ]]; then + if [[ "${1:-0}" -ne 0 ]]; then printf '%s|%s' "${1}" "${LAST_STATUS_THEME_PROMPT_COLOR-"52"}" fi } diff --git a/themes/rana/rana.theme.bash b/themes/rana/rana.theme.bash index 163c600936..41b7bba446 100644 --- a/themes/rana/rana.theme.bash +++ b/themes/rana/rana.theme.bash @@ -112,13 +112,6 @@ ${D_BRANCH_COLOR}%b %r ${D_CHANGES_COLOR}%m%u ${D_DEFAULT_COLOR}" fi } -# checks if the plugin is installed before calling battery_charge -safe_battery_charge() { - if _command_exists battery_charge; then - battery_charge - fi -} - prompt_git() { local s='' local branchName='' @@ -183,7 +176,7 @@ prompt() { if [[ "$OSTYPE" == 'linux'* ]]; then PS1="${TITLEBAR} ${SAVE_CURSOR}${MOVE_CURSOR_RIGHTMOST}${MOVE_CURSOR_5_LEFT}\ -$(safe_battery_charge)${RESTORE_CURSOR}\ +$(battery_charge)${RESTORE_CURSOR}\ ${D_USER_COLOR}\u ${D_INTERMEDIATE_COLOR}\ at ${D_MACHINE_COLOR}\h ${D_INTERMEDIATE_COLOR}\ in ${D_DIR_COLOR}\w ${D_INTERMEDIATE_COLOR}\ @@ -201,7 +194,7 @@ $(prompt_git "$D_INTERMEDIATE_COLOR on $D_GIT_COLOR")\ ${LAST_COMMAND_FAILED}\ $(demula_vcprompt)\ $(is_vim_shell)\ -$(safe_battery_charge) +$(battery_charge) ${D_INTERMEDIATE_COLOR}$ ${D_DEFAULT_COLOR}" fi diff --git a/themes/robbyrussell/robbyrussell.theme.bash b/themes/robbyrussell/robbyrussell.theme.bash index 75ef54f8d2..11aa5ef673 100644 --- a/themes/robbyrussell/robbyrussell.theme.bash +++ b/themes/robbyrussell/robbyrussell.theme.bash @@ -1,5 +1,5 @@ -#!/usr/bin/env bash - +# shellcheck shell=bash +# shellcheck disable=SC2034,SC2154 SCM_THEME_PROMPT_DIRTY=" ${bold_yellow}✗" SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" SCM_THEME_PROMPT_PREFIX=" ${bold_blue}scm:(" @@ -13,13 +13,16 @@ GIT_THEME_PROMPT_SUFFIX="${bold_blue})" RVM_THEME_PROMPT_PREFIX="|" RVM_THEME_PROMPT_SUFFIX="|" +VIRTUALENV_THEME_PROMPT_PREFIX='(' +VIRTUALENV_THEME_PROMPT_SUFFIX=') ' + function git_prompt_info() { git_prompt_vars echo -e "$SCM_PREFIX${bold_red}$SCM_BRANCH$SCM_STATE$SCM_SUFFIX" } function prompt_command() { - PS1="${bold_green}➜ ${bold_cyan}\W${reset_color}$(scm_prompt_info)${normal} " + PS1="$(conda_or_venv_prompt)${bold_green}➜ ${bold_cyan}\W${reset_color}$(scm_prompt_info)${normal} " } PROMPT_COMMAND=prompt_command diff --git a/uninstall.sh b/uninstall.sh index 49a816da8c..d11a69b2b2 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,6 +1,23 @@ #!/usr/bin/env bash -if [ -z "$BASH_IT" ]; then - BASH_IT="$HOME/.bash_it" +# +# Since we're uninstalling, avoid depending on any other part of _Bash It_. +# I.e., hard-code colors (avoid `lib/colors.bash`), &c. + +: "${BASH_IT:=${HOME?}/.bash_it}" + +if [[ ! -e ~/.bashrc && ! -e ~/.bash_profile && ! -e ~/.bashrc.bak && ! -e ~/.bash_profile.bak ]]; then + echo "We can't locate your configuration files, so we can't uninstall..." + return +elif grep -F -q -- BASH_IT ~/.bashrc && grep -F -q -- BASH_IT ~/.bash_profile; then + echo "We can't figure out if Bash-it is loaded from ~/.bashrc or ~/.bash_profile..." + return +elif grep -F -q -- BASH_IT ~/.bashrc || [[ -e ~/.bashrc.bak && ! -e ~/.bashrc ]]; then + CONFIG_FILE=".bashrc" +elif grep -F -q -- BASH_IT ~/.bash_profile || [[ -e ~/.bash_profile.bak && ! -e ~/.bash_profile ]]; then + CONFIG_FILE=".bash_profile" +else + echo "Bash-it does not appear to be installed." + return fi case $OSTYPE in @@ -14,25 +31,40 @@ esac # overriding CONFIG_FILE: CONFIG_FILE="${BASH_IT_CONFIG_FILE:-"${CONFIG_FILE}"}" +# possible states: +# - both .bash* /and/ .bash*.bak, /and/ both config reference `$BASH_IT`: no solution +# - both config and bak, but only one references `$BASH_IT`: that one +# - both config, only one bak, but other references `$BASH_IT`: the other one? +# - both config, no bak, with `$BASH_IT` reference: that one +# - one config, no bak, but no `$BASH_IT` reference: wut +# - no config, with bak, with `$BASH_IT`: re-create??? +# - no config, no bak: nothing. BACKUP_FILE=$CONFIG_FILE.bak -if [ ! -e "$HOME/$BACKUP_FILE" ]; then - echo -e "\033[0;33mBackup file $HOME/$BACKUP_FILE not found.\033[0m" >&2 +if [[ ! -e "${HOME?}/$BACKUP_FILE" ]]; then + printf '\e[0;33m%s\e[0m\n' "Backup file ~/$BACKUP_FILE not found." - test -w "$HOME/$CONFIG_FILE" \ - && mv "$HOME/$CONFIG_FILE" "$HOME/$CONFIG_FILE.uninstall" \ - && echo -e "\033[0;32mMoved your $HOME/$CONFIG_FILE to $HOME/$CONFIG_FILE.uninstall.\033[0m" + test -w "${HOME?}/$CONFIG_FILE" \ + && mv "${HOME?}/$CONFIG_FILE" "${HOME?}/$CONFIG_FILE.uninstall" \ + && printf '\e[0;32m%s\e[0m\n' "Moved your ~/$CONFIG_FILE to ~/$CONFIG_FILE.uninstall." else - test -w "$HOME/$BACKUP_FILE" \ - && cp -a "$HOME/$BACKUP_FILE" "$HOME/$CONFIG_FILE" \ - && rm "$HOME/$BACKUP_FILE" \ - && echo -e "\033[0;32mYour original $CONFIG_FILE has been restored.\033[0m" + # Create a backup of the current config before restoring the old one + # Use -L to dereference symlinks (for homesick/dotfile managers) + if [[ -e "${HOME?}/$CONFIG_FILE" ]]; then + cp -L "${HOME?}/$CONFIG_FILE" "${HOME?}/$CONFIG_FILE.pre-uninstall.bak" + printf '\e[0;33m%s\e[0m\n' "Current ~/$CONFIG_FILE backed up to ~/$CONFIG_FILE.pre-uninstall.bak" + fi + + test -w "${HOME?}/$BACKUP_FILE" \ + && cp -a "${HOME?}/$BACKUP_FILE" "${HOME?}/$CONFIG_FILE" \ + && rm "${HOME?}/$BACKUP_FILE" \ + && printf '\e[0;32m%s\e[0m\n' "Your original ~/$CONFIG_FILE has been restored." + + printf '\e[0;33m%s\e[0m\n' "NOTE: If you had made changes since installing Bash-it, they are preserved in ~/$CONFIG_FILE.pre-uninstall.bak" fi -echo "" -echo -e "\033[0;32mUninstallation finished successfully! Sorry to see you go!\033[0m" -echo "" -echo "Final steps to complete the uninstallation:" -echo " -> Remove the $BASH_IT folder" -echo " -> Open a new shell/tab/terminal" +printf '\n\e[0;32m%s\e[0m\n\n' "Uninstallation finished successfully! Sorry to see you go!" +printf '%s\n' "Final steps to complete the uninstallation:" +printf '\t%s\n' "-> Remove the ${BASH_IT//${HOME?}/\~} folder" +printf '\t%s\n' "-> Open a new shell/tab/terminal" diff --git a/vendor/github.com/ohmyzsh/ohmyzsh/LICENSE.txt b/vendor/github.com/ohmyzsh/ohmyzsh/LICENSE.txt new file mode 100644 index 0000000000..becd6a7bdd --- /dev/null +++ b/vendor/github.com/ohmyzsh/ohmyzsh/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2009-2021 Robby Russell and contributors (https://github.com/ohmyzsh/ohmyzsh/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/README.md b/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/README.md new file mode 100644 index 0000000000..e53d93b0b3 --- /dev/null +++ b/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/README.md @@ -0,0 +1,241 @@ +# git plugin + +The git plugin provides many [aliases](#aliases) and a few useful [functions](#functions). + +To use it, add `git` to the plugins array in your zshrc file: + +```zsh +plugins=(... git) +``` + +## Aliases + +| Alias | Command | +|:---------------------|:---------------------------------------------------------------------------------------------------------------------------------| +| g | git | +| ga | git add | +| gaa | git add --all | +| gapa | git add --patch | +| gau | git add --update | +| gav | git add --verbose | +| gap | git apply | +| gapt | git apply --3way | +| gb | git branch | +| gba | git branch -a | +| gbd | git branch -d | +| gbda | git branch --no-color --merged \| grep -vE "^([+*]\|\s*($(git_main_branch)\|$(git_develop_branch))\s*$)" \| xargs git branch -d 2>/dev/null | +| gbD | git branch -D | +| gbl | git blame -b -w | +| gbnm | git branch --no-merged | +| gbr | git branch --remote | +| gbs | git bisect | +| gbsb | git bisect bad | +| gbsg | git bisect good | +| gbsr | git bisect reset | +| gbss | git bisect start | +| gc | git commit -v | +| gc! | git commit -v --amend | +| gcn! | git commit -v --no-edit --amend | +| gca | git commit -v -a | +| gca! | git commit -v -a --amend | +| gcan! | git commit -v -a --no-edit --amend | +| gcans! | git commit -v -a -s --no-edit --amend | +| gcam | git commit -a -m | +| gcas | git commit -a -s | +| gcasm | git commit -a -s -m | +| gcsm | git commit -s -m | +| gcb | git checkout -b | +| gcf | git config --list | +| gcl | git clone --recurse-submodules | +| gclean | git clean -id | +| gpristine | git reset --hard && git clean -dffx | +| gcm | git checkout $(git_main_branch) | +| gcd | git checkout $(git_develop_branch) | +| gcmsg | git commit -m | +| gco | git checkout | +| gcor | git checkout --recurse-submodules | +| gcount | git shortlog -sn | +| gcp | git cherry-pick | +| gcpa | git cherry-pick --abort | +| gcpc | git cherry-pick --continue | +| gcs | git commit -S | +| gd | git diff | +| gdca | git diff --cached | +| gdcw | git diff --cached --word-diff | +| gdct | git describe --tags $(git rev-list --tags --max-count=1) | +| gds | git diff --staged | +| gdt | git diff-tree --no-commit-id --name-only -r | +| gdnolock | git diff $@ ":(exclude)package-lock.json" ":(exclude)*.lock" | +| gdu | git diff @{u} | +| gdv | git diff -w $@ \| view - | +| gdw | git diff --word-diff | +| gf | git fetch | +| gfa | git fetch --all --prune | +| gfg | git ls-files \| grep | +| gfo | git fetch origin | +| gg | git gui citool | +| gga | git gui citool --amend | +| ggf | git push --force origin $(current_branch) | +| ggfl | git push --force-with-lease origin $(current_branch) | +| ggl | git pull origin $(current_branch) | +| ggp | git push origin $(current_branch) | +| ggpnp | ggl && ggp | +| ggpull | git pull origin "$(git_current_branch)" | +| ggpur | ggu | +| ggpush | git push origin "$(git_current_branch)" | +| ggsup | git branch --set-upstream-to=origin/$(git_current_branch) | +| ggu | git pull --rebase origin $(current_branch) | +| gpsup | git push --set-upstream origin $(git_current_branch) | +| ghh | git help | +| gignore | git update-index --assume-unchanged | +| gignored | git ls-files -v \| grep "^[[:lower:]]" | +| git-svn-dcommit-push | git svn dcommit && git push github $(git_main_branch):svntrunk | +| gk | gitk --all --branches | +| gke | gitk --all $(git log -g --pretty=%h) | +| gl | git pull | +| glg | git log --stat | +| glgp | git log --stat -p | +| glgg | git log --graph | +| glgga | git log --graph --decorate --all | +| glgm | git log --graph --max-count=10 | +| glo | git log --oneline --decorate | +| glol | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' | +| glols | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat | +| glod | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' | +| glods | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short | +| glola | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all | +| glog | git log --oneline --decorate --graph | +| gloga | git log --oneline --decorate --graph --all | +| glp | git log --pretty=\ | +| gm | git merge | +| gmom | git merge origin/$(git_main_branch) | +| gmtl | git mergetool --no-prompt | +| gmtlvim | git mergetool --no-prompt --tool=vimdiff | +| gmum | git merge upstream/$(git_main_branch) | +| gma | git merge --abort | +| gp | git push | +| gpd | git push --dry-run | +| gpf | git push --force-with-lease | +| gpf! | git push --force | +| gpoat | git push origin --all && git push origin --tags | +| gpr | git pull --rebase | +| gpu | git push upstream | +| gpv | git push -v | +| gr | git remote | +| gra | git remote add | +| grb | git rebase | +| grba | git rebase --abort | +| grbc | git rebase --continue | +| grbd | git rebase $(git_develop_branch) | +| grbi | git rebase -i | +| grbm | git rebase $(git_main_branch) | +| grbo | git rebase --onto | +| grbs | git rebase --skip | +| grev | git revert | +| grh | git reset | +| grhh | git reset --hard | +| groh | git reset origin/$(git_current_branch) --hard | +| grm | git rm | +| grmc | git rm --cached | +| grmv | git remote rename | +| grrm | git remote remove | +| grs | git restore | +| grset | git remote set-url | +| grss | git restore --source | +| grst | git restore --staged | +| grt | cd "$(git rev-parse --show-toplevel \|\| echo .)" | +| gru | git reset -- | +| grup | git remote update | +| grv | git remote -v | +| gsb | git status -sb | +| gsd | git svn dcommit | +| gsh | git show | +| gsi | git submodule init | +| gsps | git show --pretty=short --show-signature | +| gsr | git svn rebase | +| gss | git status -s | +| gst | git status | +| gsta | git stash push | +| gsta | git stash save | +| gstaa | git stash apply | +| gstc | git stash clear | +| gstd | git stash drop | +| gstl | git stash list | +| gstp | git stash pop | +| gsts | git stash show --text | +| gstu | git stash --include-untracked | +| gstall | git stash --all | +| gsu | git submodule update | +| gsw | git switch | +| gswc | git switch -c | +| gts | git tag -s | +| gtv | git tag \| sort -V | +| gtl | gtl(){ git tag --sort=-v:refname -n -l ${1}* }; noglob gtl | +| gunignore | git update-index --no-assume-unchanged | +| gunwip | git log -n 1 \| grep -q -c "\-\-wip\-\-" && git reset HEAD~1 | +| gup | git pull --rebase | +| gupv | git pull --rebase -v | +| gupa | git pull --rebase --autostash | +| gupav | git pull --rebase --autostash -v | +| glum | git pull upstream $(git_main_branch) | +| gwch | git whatchanged -p --abbrev-commit --pretty=medium | +| gwip | git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]" | +| gam | git am | +| gamc | git am --continue | +| gams | git am --skip | +| gama | git am --abort | +| gamscp | git am --show-current-patch | + +### Main branch preference + +Following the recent push for removing racially-charged words from our technical vocabulary, the git plugin favors using +a branch name other than `master`. In this case, we favor the shorter, neutral and descriptive term `main`. This means +that any aliases and functions that previously used `master`, will use `main` if that branch exists. We do this via the +function `git_main_branch`. + +### Deprecated aliases + +These are aliases that have been removed, renamed, or otherwise modified in a way that may, or may not, receive further support. + +| Alias | Command | Modification | +| :----- | :----------------------------------------------------- | :----------------------------------------------------- | +| gap | `git add --patch` | new alias `gapa` | +| gcl | `git config --list` | new alias `gcf` | +| gdc | `git diff --cached` | new alias `gdca` | +| gdt | `git difftool` | no replacement | +| ggpull | `git pull origin $(current_branch)` | new alias `ggl` (`ggpull` still exists for now though) | +| ggpur | `git pull --rebase origin $(current_branch)` | new alias `ggu` (`ggpur` still exists for now though) | +| ggpush | `git push origin $(current_branch)` | new alias `ggp` (`ggpush` still exists for now though) | +| gk | `gitk --all --branches` | now aliased to `gitk --all --branches` | +| glg | `git log --stat --max-count = 10` | now aliased to `git log --stat --color` | +| glgg | `git log --graph --max-count = 10` | now aliased to `git log --graph --color` | +| gwc | `git whatchanged -p --abbrev-commit --pretty = medium` | new alias `gwch` | + +## Functions + +### Current + +| Command | Description | +|:-----------------------|:---------------------------------------------------------------------------------------------------------| +| `grename ` | Rename `old` branch to `new`, including in origin remote | +| current_branch | Return the name of the current branch | +| git_current_user_name | Returns the `user.name` config value | +| git_current_user_email | Returns the `user.email` config value | +| git_main_branch | Returns the name of the main branch: `main` if it exists, `master` otherwise | +| git_develop_branch | Returns the name of the develop branch: `dev`, `devel`, `development` if they exist, `develop` otherwise | + +### Work in Progress (WIP) + +These features allow to pause a branch development and switch to another one (_"Work in Progress"_, or wip). When you want to go back to work, just unwip it. + +| Command | Description | +|:-----------------|:------------------------------------------------| +| work_in_progress | Echoes a warning if the current branch is a wip | +| gwip | Commit wip branch | +| gunwip | Uncommit wip branch | + +### Deprecated functions + +| Command | Description | Reason | +|:-----------------------|:----------------------------------------|:----------------------------------------------------------------| +| current_repository | Return the names of the current remotes | Didn't work properly. Use `git remote -v` instead (`grv` alias) | diff --git a/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/git.plugin.zsh b/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/git.plugin.zsh new file mode 100644 index 0000000000..64ac0a1e25 --- /dev/null +++ b/vendor/github.com/ohmyzsh/ohmyzsh/plugins/git/git.plugin.zsh @@ -0,0 +1,316 @@ +# +# Functions +# + +# The name of the current branch +# Back-compatibility wrapper for when this function was defined here in +# the plugin, before being pulled in to core lib/git.zsh as git_current_branch() +# to fix the core -> git plugin dependency. +function current_branch() { + git_current_branch +} + +# Pretty log messages +function _git_log_prettily(){ + if ! [ -z $1 ]; then + git log --pretty=$1 + fi +} + +# Warn if the current branch is a WIP +function work_in_progress() { + if $(git log -n 1 2>/dev/null | grep -q -c "\-\-wip\-\-"); then + echo "WIP!!" + fi +} + +# Check if main exists and use instead of master +function git_main_branch() { + command git rev-parse --git-dir &>/dev/null || return + local ref + for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk}; do + if command git show-ref -q --verify $ref; then + echo ${ref:t} + return + fi + done + echo master +} + +# Check for develop and similarly named branches +function git_develop_branch() { + command git rev-parse --git-dir &>/dev/null || return + local branch + for branch in dev devel development; do + if command git show-ref -q --verify refs/heads/$branch; then + echo $branch + return + fi + done + echo develop +} + +# +# Aliases +# (sorted alphabetically) +# + +alias g='git' + +alias ga='git add' +alias gaa='git add --all' +alias gapa='git add --patch' +alias gau='git add --update' +alias gav='git add --verbose' +alias gap='git apply' +alias gapt='git apply --3way' + +alias gb='git branch' +alias gba='git branch -a' +alias gbd='git branch -d' +alias gbda='git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch -d 2>/dev/null' +alias gbD='git branch -D' +alias gbl='git blame -b -w' +alias gbnm='git branch --no-merged' +alias gbr='git branch --remote' +alias gbs='git bisect' +alias gbsb='git bisect bad' +alias gbsg='git bisect good' +alias gbsr='git bisect reset' +alias gbss='git bisect start' + +alias gc='git commit -v' +alias gc!='git commit -v --amend' +alias gcn!='git commit -v --no-edit --amend' +alias gca='git commit -v -a' +alias gca!='git commit -v -a --amend' +alias gcan!='git commit -v -a --no-edit --amend' +alias gcans!='git commit -v -a -s --no-edit --amend' +alias gcam='git commit -a -m' +alias gcsm='git commit -s -m' +alias gcas='git commit -a -s' +alias gcasm='git commit -a -s -m' +alias gcb='git checkout -b' +alias gcf='git config --list' +alias gcl='git clone --recurse-submodules' +alias gclean='git clean -id' +alias gpristine='git reset --hard && git clean -dffx' +alias gcm='git checkout $(git_main_branch)' +alias gcd='git checkout $(git_develop_branch)' +alias gcmsg='git commit -m' +alias gco='git checkout' +alias gcor='git checkout --recurse-submodules' +alias gcount='git shortlog -sn' +alias gcp='git cherry-pick' +alias gcpa='git cherry-pick --abort' +alias gcpc='git cherry-pick --continue' +alias gcs='git commit -S' +alias gcss='git commit -S -s' +alias gcssm='git commit -S -s -m' + +alias gd='git diff' +alias gdca='git diff --cached' +alias gdcw='git diff --cached --word-diff' +alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' +alias gds='git diff --staged' +alias gdt='git diff-tree --no-commit-id --name-only -r' +alias gdu='git diff @{u}' +alias gdw='git diff --word-diff' + +function gdnolock() { + git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock" +} + +function gdv() { + git diff -w "$@" | view - +} + +alias gf='git fetch' +# --jobs= was added in git 2.8 +is-at-least 2.8 "$git_version" \ + && alias gfa='git fetch --all --prune --jobs=10' \ + || alias gfa='git fetch --all --prune' +alias gfo='git fetch origin' + +alias gfg='git ls-files | grep' + +alias gg='git gui citool' +alias gga='git gui citool --amend' + +function ggf() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git push --force origin "${b:=$1}" +} +function ggfl() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git push --force-with-lease origin "${b:=$1}" +} + +function ggl() { + if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then + git pull origin "${*}" + else + [[ "$#" == 0 ]] && local b="$(git_current_branch)" + git pull origin "${b:=$1}" + fi +} + +function ggp() { + if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then + git push origin "${*}" + else + [[ "$#" == 0 ]] && local b="$(git_current_branch)" + git push origin "${b:=$1}" + fi +} + +function ggpnp() { + if [[ "$#" == 0 ]]; then + ggl && ggp + else + ggl "${*}" && ggp "${*}" + fi +} + +function ggu() { + [[ "$#" != 1 ]] && local b="$(git_current_branch)" + git pull --rebase origin "${b:=$1}" +} + +alias ggpur='ggu' +alias ggpull='git pull origin "$(git_current_branch)"' +alias ggpush='git push origin "$(git_current_branch)"' + +alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)' +alias gpsup='git push --set-upstream origin $(git_current_branch)' + +alias ghh='git help' + +alias gignore='git update-index --assume-unchanged' +alias gignored='git ls-files -v | grep "^[[:lower:]]"' +alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk' + +alias gk='\gitk --all --branches' +alias gke='\gitk --all $(git log -g --pretty=%h)' + +alias gl='git pull' +alias glg='git log --stat' +alias glgp='git log --stat -p' +alias glgg='git log --graph' +alias glgga='git log --graph --decorate --all' +alias glgm='git log --graph --max-count=10' +alias glo='git log --oneline --decorate' +alias glol="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'" +alias glols="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat" +alias glod="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'" +alias glods="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short" +alias glola="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all" +alias glog='git log --oneline --decorate --graph' +alias gloga='git log --oneline --decorate --graph --all' +alias glp="_git_log_prettily" + +alias gm='git merge' +alias gmom='git merge origin/$(git_main_branch)' +alias gmtl='git mergetool --no-prompt' +alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' +alias gmum='git merge upstream/$(git_main_branch)' +alias gma='git merge --abort' + +alias gp='git push' +alias gpd='git push --dry-run' +alias gpf='git push --force-with-lease' +alias gpf!='git push --force' +alias gpoat='git push origin --all && git push origin --tags' +alias gpr='git pull --rebase' +alias gpu='git push upstream' +alias gpv='git push -v' + +alias gr='git remote' +alias gra='git remote add' +alias grb='git rebase' +alias grba='git rebase --abort' +alias grbc='git rebase --continue' +alias grbd='git rebase $(git_develop_branch)' +alias grbi='git rebase -i' +alias grbm='git rebase $(git_main_branch)' +alias grbo='git rebase --onto' +alias grbs='git rebase --skip' +alias grev='git revert' +alias grh='git reset' +alias grhh='git reset --hard' +alias groh='git reset origin/$(git_current_branch) --hard' +alias grm='git rm' +alias grmc='git rm --cached' +alias grmv='git remote rename' +alias grrm='git remote remove' +alias grs='git restore' +alias grset='git remote set-url' +alias grss='git restore --source' +alias grst='git restore --staged' +alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' +alias gru='git reset --' +alias grup='git remote update' +alias grv='git remote -v' + +alias gsb='git status -sb' +alias gsd='git svn dcommit' +alias gsh='git show' +alias gsi='git submodule init' +alias gsps='git show --pretty=short --show-signature' +alias gsr='git svn rebase' +alias gss='git status -s' +alias gst='git status' + +# use the default stash push on git 2.13 and newer +is-at-least 2.13 "$git_version" \ + && alias gsta='git stash push' \ + || alias gsta='git stash save' + +alias gstaa='git stash apply' +alias gstc='git stash clear' +alias gstd='git stash drop' +alias gstl='git stash list' +alias gstp='git stash pop' +alias gsts='git stash show --text' +alias gstu='gsta --include-untracked' +alias gstall='git stash --all' +alias gsu='git submodule update' +alias gsw='git switch' +alias gswc='git switch -c' + +alias gts='git tag -s' +alias gtv='git tag | sort -V' +alias gtl='gtl(){ git tag --sort=-v:refname -n -l "${1}*" }; noglob gtl' + +alias gunignore='git update-index --no-assume-unchanged' +alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1' +alias gup='git pull --rebase' +alias gupv='git pull --rebase -v' +alias gupa='git pull --rebase --autostash' +alias gupav='git pull --rebase --autostash -v' +alias glum='git pull upstream $(git_main_branch)' + +alias gwch='git whatchanged -p --abbrev-commit --pretty=medium' +alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]"' + +alias gam='git am' +alias gamc='git am --continue' +alias gams='git am --skip' +alias gama='git am --abort' +alias gamscp='git am --show-current-patch' + +function grename() { + if [[ -z "$1" || -z "$2" ]]; then + echo "Usage: $0 old_branch new_branch" + return 1 + fi + + # Rename branch locally + git branch -m "$1" "$2" + # Rename branch in origin remote + if git push origin :"$1"; then + git push --set-upstream origin "$2" + fi +} + +unset git_version