diff --git a/.editorconfig b/.editorconfig old mode 100755 new mode 100644 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index b501d941..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: Bug report -about: Create a bug report to help us improve -title: '' -labels: bug:general -assignees: '' - ---- - - - -## Expected Behavior - - -## Current Behavior - - -## Possible Solution - - -## Context - - - -## Steps to Reproduce - - -1. -2. -3. -4. - -## Your Environment - -* Bash-it version used: -* List of enabled plugins, themes and aliases (use ``bash-it show (plugins/themes/aliases)``): -* ``bash-it doctor`` output: -* Bash version: -* Operating System and version: - -## Your Bash Config File - - -```bash - # Your bash config file should be here -``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..a187422e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,85 @@ +name: 🐛 Bug report +title: "[Bug]: " +description: Create a bug report to help us improve +labels: "bug:general" +body: + - type: textarea + attributes: + label: Expected behavior + description: Tell us what should happen. + validations: + required: true + - type: textarea + attributes: + label: Current behavior + description: Tell us what happens instead of the expected behavior. + validations: + required: true + - type: textarea + attributes: + label: Possible solution + description: Tell us how it could be fixed at your glance. + validations: + required: false + - type: textarea + attributes: + label: Context + description: > + How has this issue affected you? What are you trying to accomplish? + Providing context helps us come up with a solution that is most useful in the real world. + validations: + required: false + - type: textarea + attributes: + label: Steps to reproduce + description: > + 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" + value: | + ``` + # How to get: bash-it doctor + ``` + validations: + required: false + - type: textarea + attributes: + label: Your ~/.bashrc + value: | + ```bash + # How to get: cat ~/.bashrc + ``` + validations: + required: true + - type: textarea + attributes: + label: Notes + description: > + Provide any extra details here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..f33f8a3f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Libera chat + url: https://web.libera.chat/?channel=#bash-it + about: You can ask and answer questions here diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index b1fabfba..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: feature request -assignees: '' - ---- - - - -## Expected Behavior - - -## Current Behavior - - -## Possible Solution - - -## Context - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..670aef64 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,34 @@ +name: 💡 Feature request +title: "[Feature]: " +description: Suggest an idea for this project +labels: "feature request" +body: + - type: textarea + attributes: + label: Expected behavior + description: Tell us how your feature should work. + validations: + required: true + - type: textarea + attributes: + label: Current behavior + description: Explain the difference your feature will have from current behavior. + validations: + required: true + - type: textarea + attributes: + label: Possible solution + description: Tell us how it could be fixed at your glance. + validations: + required: false + - type: textarea + attributes: + label: Context + description: > + How has this issue affected you? What are you trying to accomplish? + Providing context helps us come up with a solution that is most useful in the real world. + - type: textarea + attributes: + label: Notes + description: > + Provide any extra details here. diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/aliases/available/ag.aliases.bash b/aliases/available/ag.aliases.bash index e3157f94..7f9af7da 100644 --- a/aliases/available/ag.aliases.bash +++ b/aliases/available/ag.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'the silver searcher (ag) aliases' ## Summary for args to less: diff --git a/aliases/available/ansible.aliases.bash b/aliases/available/ansible.aliases.bash index 1c53a88e..04c5d280 100644 --- a/aliases/available/ansible.aliases.bash +++ b/aliases/available/ansible.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'ansible abbreviations' alias ans=ansible diff --git a/aliases/available/apt.aliases.bash b/aliases/available/apt.aliases.bash index b7ef274c..1d43ffac 100644 --- a/aliases/available/apt.aliases.bash +++ b/aliases/available/apt.aliases.bash @@ -6,10 +6,8 @@ cite 'about-alias' about-alias 'Apt and dpkg aliases for Ubuntu and Debian distros.' # set apt aliases -function _set_pkg_aliases() -{ - if _command_exists apt - then +function _set_pkg_aliases() { + if _command_exists apt; then alias apts='apt-cache search' alias aptshow='apt-cache show' alias aptinst='sudo apt-get install -V' diff --git a/aliases/available/atom.aliases.bash b/aliases/available/atom.aliases.bash index 8d70cffa..6868e2cc 100644 --- a/aliases/available/atom.aliases.bash +++ b/aliases/available/atom.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'Atom.io editor abbreviations' alias a='atom' diff --git a/aliases/available/bash-it.aliases.bash b/aliases/available/bash-it.aliases.bash index d2975667..1f16638b 100644 --- a/aliases/available/bash-it.aliases.bash +++ b/aliases/available/bash-it.aliases.bash @@ -1,4 +1,4 @@ -cite about-alias +# shellcheck shell=bash about-alias 'Aliases for the bash-it command (these aliases are automatically included with the "general" aliases)' # Common misspellings of bash-it diff --git a/aliases/available/bolt.aliases.bash b/aliases/available/bolt.aliases.bash index 8490f710..556dd7fe 100644 --- a/aliases/available/bolt.aliases.bash +++ b/aliases/available/bolt.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'puppet bolt aliases' # Aliases diff --git a/aliases/available/bundler.aliases.bash b/aliases/available/bundler.aliases.bash index fc20f4ff..1eb00862 100644 --- a/aliases/available/bundler.aliases.bash +++ b/aliases/available/bundler.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'ruby bundler' # Bundler Commands diff --git a/aliases/available/clipboard.aliases.bash b/aliases/available/clipboard.aliases.bash index 4c7e6f5b..2a5c3e8c 100644 --- a/aliases/available/clipboard.aliases.bash +++ b/aliases/available/clipboard.aliases.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite 'about-alias' about-alias 'xclip shortcuts' alias pbcopy="xclip -selection clipboard" diff --git a/aliases/available/composer.aliases.bash b/aliases/available/composer.aliases.bash index 5ccb2e24..85401abb 100644 --- a/aliases/available/composer.aliases.bash +++ b/aliases/available/composer.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'common composer abbreviations' # Aliases diff --git a/aliases/available/curl.aliases.bash b/aliases/available/curl.aliases.bash index a6b2b344..a270e416 100644 --- a/aliases/available/curl.aliases.bash +++ b/aliases/available/curl.aliases.bash @@ -1,23 +1,19 @@ -#!/bin/bash - -cite 'about-alias' +# shellcheck shell=bash about-alias 'Curl aliases for convenience.' # set apt aliases -function _set_pkg_aliases() -{ - if _command_exists curl - then +function _set_pkg_aliases() { + if _command_exists curl; then # follow redirects - alias cl='curl -L' - # follow redirects, download as original name - alias clo='curl -L -O' - # follow redirects, download as original name, continue - alias cloc='curl -L -C - -O' - # follow redirects, download as original name, continue, retry 5 times - alias clocr='curl -L -C - -O --retry 5' - # follow redirects, fetch banner - alias clb='curl -L -I' + alias cl='curl -L' + # follow redirects, download as original name + alias clo='curl -L -O' + # follow redirects, download as original name, continue + alias cloc='curl -L -C - -O' + # follow redirects, download as original name, continue, retry 5 times + alias clocr='curl -L -C - -O --retry 5' + # follow redirects, fetch banner + alias clb='curl -L -I' # see only response headers from a get request alias clhead='curl -D - -so /dev/null' fi diff --git a/aliases/available/dnf.aliases.bash b/aliases/available/dnf.aliases.bash index 9d9f0267..25007c23 100644 --- a/aliases/available/dnf.aliases.bash +++ b/aliases/available/dnf.aliases.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite 'about-alias' about-alias 'dnf aliases for fedora 22+ distros' alias dnfl="dnf list" # List packages diff --git a/aliases/available/docker-compose.aliases.bash b/aliases/available/docker-compose.aliases.bash index 3583be8f..a2f637c0 100644 --- a/aliases/available/docker-compose.aliases.bash +++ b/aliases/available/docker-compose.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'docker-compose abbreviations' alias dco="docker-compose" diff --git a/aliases/available/docker.aliases.bash b/aliases/available/docker.aliases.bash index 9f005aa7..1c49207f 100644 --- a/aliases/available/docker.aliases.bash +++ b/aliases/available/docker.aliases.bash @@ -1,32 +1,32 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'docker abbreviations' alias dk='docker' -alias dklc='docker ps -l' # List last Docker container -alias dklcid='docker ps -l -q' # List last Docker container ID -alias dklcip='docker inspect -f "{{.NetworkSettings.IPAddress}}" $(docker ps -l -q)' # Get IP of last Docker container -alias dkps='docker ps' # List running Docker containers -alias dkpsa='docker ps -a' # List all Docker containers -alias dki='docker images' # List Docker images -alias dkrmac='docker rm $(docker ps -a -q)' # Delete all Docker containers +alias dklc='docker ps -l' # List last Docker container +alias dklcid='docker ps -l -q' # List last Docker container ID +alias dklcip='docker inspect -f "{{.NetworkSettings.IPAddress}}" $(docker ps -l -q)' # Get IP of last Docker container +alias dkps='docker ps' # List running Docker containers +alias dkpsa='docker ps -a' # List all Docker containers +alias dki='docker images' # List Docker images +alias dkrmac='docker rm $(docker ps -a -q)' # Delete all Docker containers case $OSTYPE in - darwin*|*bsd*|*BSD*) - alias dkrmui='docker images -q -f dangling=true | xargs docker rmi' # Delete all untagged Docker images - ;; - *) - alias dkrmui='docker images -q -f dangling=true | xargs -r docker rmi' # Delete all untagged Docker images - ;; + darwin* | *bsd* | *BSD*) + alias dkrmui='docker images -q -f dangling=true | xargs docker rmi' # Delete all untagged Docker images + ;; + *) + alias dkrmui='docker images -q -f dangling=true | xargs -r docker rmi' # Delete all untagged Docker images + ;; esac -if [ ! -z "$(command ls "${BASH_IT}/enabled/"{[0-9][0-9][0-9]${BASH_IT_LOAD_PRIORITY_SEPARATOR}docker,docker}.plugin.bash 2>/dev/null | head -1)" ]; then -# Function aliases from docker plugin: - alias dkrmlc='docker-remove-most-recent-container' # Delete most recent (i.e., last) Docker container - alias dkrmall='docker-remove-stale-assets' # Delete all untagged images and exited containers - alias dkrmli='docker-remove-most-recent-image' # Delete most recent (i.e., last) Docker image - alias dkrmi='docker-remove-images' # Delete images for supplied IDs or all if no IDs are passed as arguments - alias dkideps='docker-image-dependencies' # Output a graph of image dependencies using Graphiz - alias dkre='docker-runtime-environment' # List environmental variables of the supplied image ID +if _bash-it-component-item-is-enabled plugin docker; then + # Function aliases from docker plugin: + alias dkrmlc='docker-remove-most-recent-container' # Delete most recent (i.e., last) Docker container + alias dkrmall='docker-remove-stale-assets' # Delete all untagged images and exited containers + alias dkrmli='docker-remove-most-recent-image' # Delete most recent (i.e., last) Docker image + alias dkrmi='docker-remove-images' # Delete images for supplied IDs or all if no IDs are passed as arguments + alias dkideps='docker-image-dependencies' # Output a graph of image dependencies using Graphiz + alias dkre='docker-runtime-environment' # List environmental variables of the supplied image ID fi alias dkelc='docker exec -it $(dklcid) bash --login' # Enter last container (works with Docker 1.3 and above) alias dkrmflast='docker rm -f $(dklcid)' diff --git a/aliases/available/emacs.aliases.bash b/aliases/available/emacs.aliases.bash index f8e1259b..a4e4111a 100644 --- a/aliases/available/emacs.aliases.bash +++ b/aliases/available/emacs.aliases.bash @@ -1,16 +1,16 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'emacs editor' case $OSTYPE in - linux*) - alias em='emacs' - alias en='emacs -nw' - alias e='emacsclient -n' - alias et='emacsclient -t' - alias ed='emacs --daemon' - alias E='SUDO_EDITOR=emacsclient sudo -e' - ;; - darwin*) - alias em='open -a emacs' - ;; + linux*) + alias em='emacs' + alias en='emacs -nw' + alias e='emacsclient -n' + alias et='emacsclient -t' + alias ed='emacs --daemon' + alias E='SUDO_EDITOR=emacsclient sudo -e' + ;; + darwin*) + alias em='open -a emacs' + ;; esac diff --git a/aliases/available/fuck.aliases.bash b/aliases/available/fuck.aliases.bash index 495ea851..4cfa52d8 100644 --- a/aliases/available/fuck.aliases.bash +++ b/aliases/available/fuck.aliases.bash @@ -1,9 +1,9 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'fuck/please to retry last command with sudo' # Play nicely with 'thefuck' plugin -if ! _command_exists fuck ; then - alias fuck='sudo $(fc -ln -1)' +if ! _command_exists fuck; then + alias fuck='sudo $(fc -ln -1)' fi alias please=fuck alias plz=please diff --git a/aliases/available/general.aliases.bash b/aliases/available/general.aliases.bash index 3c29928d..42930ab4 100644 --- a/aliases/available/general.aliases.bash +++ b/aliases/available/general.aliases.bash @@ -1,51 +1,45 @@ -cite about-alias +# shellcheck shell=bash about-alias 'general aliases' -if ls --color -d . &> /dev/null -then - alias ls="ls --color=auto" -elif ls -G -d . &> /dev/null -then - alias ls='ls -G' # Compact view, show colors +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 la='ls -AF' # Compact view, show hidden alias ll='ls -al' alias l='ls -a' alias l1='ls -1' alias lf='ls -F' -alias _="sudo" +alias _='sudo' # Shortcuts to edit startup files -alias vbrc="vim ~/.bashrc" -alias vbpf="vim ~/.bash_profile" +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 -if grep --color=auto "a" "${BASH_IT}/"*.md &> /dev/null -then - alias grep='grep --color=auto' +if command grep --color=auto "a" "${BASH_IT?}"/*.md &> /dev/null; then + alias grep='grep --color=auto' fi -if _command_exists gshuf -then - alias shuf=gshuf +if _command_exists gshuf; then + alias shuf=gshuf fi alias c='clear' -alias k='clear' alias cls='clear' -alias edit="$EDITOR" -alias pager="$PAGER" +alias edit='${EDITOR:-${ALTERNATE_EDITOR?}}' +alias pager='${PAGER:=less}' alias q='exit' -alias irc="${IRC_CLIENT:=irc}" +alias irc='${IRC_CLIENT:=irc}' # Language aliases alias rb='ruby' @@ -66,9 +60,8 @@ alias -- -='cd -' # Go back alias h='history' # Tree -if ! _command_exists tree -then - alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'" +if ! _command_exists tree; then + alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'" fi # Directory @@ -76,21 +69,21 @@ alias md='mkdir -p' alias rd='rmdir' # Shorten extract -alias xt="extract" +alias xt='extract' # sudo editors -alias svim="sudo vim" -alias snano="sudo nano" +alias svim='sudo ${VISUAL:-vim}' +alias snano='sudo nano' # Display whatever file is regular file or folder -catt() { - for i in "$@"; do - if [ -d "$i" ]; then - ls "$i" - else - cat "$i" - fi - done +function catt() { + for i in "$@"; do + if [[ -d "$i" ]]; then + ls "$i" + else + cat "$i" + fi + done } # The Bash-it aliases were moved to the `bash-it.aliases.bash` file. The intent of this @@ -99,5 +92,5 @@ catt() { # aliases and enable just the ones for Bash-it explicitly: # bash-it disable alias general # bash-it enable alias bash-it -# shellcheck source=./bash-it.aliases.bash +# shellcheck source-path=SCRIPTDIR source "$BASH_IT/aliases/available/bash-it.aliases.bash" diff --git a/aliases/available/git.aliases.bash b/aliases/available/git.aliases.bash index a63faa47..507037e1 100644 --- a/aliases/available/git.aliases.bash +++ b/aliases/available/git.aliases.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite 'about-alias' about-alias 'common git abbreviations' alias g='git' diff --git a/aliases/available/gitsvn.aliases.bash b/aliases/available/gitsvn.aliases.bash index feb608be..3c578445 100644 --- a/aliases/available/gitsvn.aliases.bash +++ b/aliases/available/gitsvn.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'common git-svn abbreviations' # Aliases diff --git a/aliases/available/heroku.aliases.bash b/aliases/available/heroku.aliases.bash index a749d424..4c822594 100644 --- a/aliases/available/heroku.aliases.bash +++ b/aliases/available/heroku.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'heroku task abbreviations' # heroku diff --git a/aliases/available/hg.aliases.bash b/aliases/available/hg.aliases.bash index eea819ff..d9101a03 100644 --- a/aliases/available/hg.aliases.bash +++ b/aliases/available/hg.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'mercurial abbreviations' alias hs='hg status' diff --git a/aliases/available/homebrew-cask.aliases.bash b/aliases/available/homebrew-cask.aliases.bash index 57d8161c..43d206d4 100644 --- a/aliases/available/homebrew-cask.aliases.bash +++ b/aliases/available/homebrew-cask.aliases.bash @@ -1,7 +1,5 @@ -# Some aliases for Homebrew Cask - -cite 'about-alias' -about-alias 'homebrew-cask abbreviations' +# shellcheck shell=bash +about-alias 'Some aliases for Homebrew Cask' alias bcin='brew cask install' alias bcrm='brew cask uninstall' diff --git a/aliases/available/homebrew.aliases.bash b/aliases/available/homebrew.aliases.bash index 15907518..f35a38d3 100644 --- a/aliases/available/homebrew.aliases.bash +++ b/aliases/available/homebrew.aliases.bash @@ -1,7 +1,5 @@ -# Some aliases for Homebrew - -cite 'about-alias' -about-alias 'homebrew abbreviations' +# shellcheck shell=bash +about-alias 'Some aliases for Homebrew' alias bup='brew update && brew upgrade' alias bout='brew outdated' diff --git a/aliases/available/homesick.aliases.bash b/aliases/available/homesick.aliases.bash index 548efc3b..00101eed 100644 --- a/aliases/available/homesick.aliases.bash +++ b/aliases/available/homesick.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'homesick aliases' # Aliases @@ -19,6 +19,5 @@ alias sikpsh="homesick push dotfiles" alias sikrc="homesick rc dotfiles" alias sikpth="homesick show_path dotfiles" alias sikst="homesick status dotfiles" -alias siktrk="homesick track $1 dotfiles" alias sikulnk="homesick unlink dotfiles" alias sikv="homesick version" diff --git a/aliases/available/jitsu.aliases.bash b/aliases/available/jitsu.aliases.bash index 91e96849..f056e749 100644 --- a/aliases/available/jitsu.aliases.bash +++ b/aliases/available/jitsu.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'jitsu task abbreviations' # jitsu diff --git a/aliases/available/kubectl.aliases.bash b/aliases/available/kubectl.aliases.bash index 440a9041..aaca4ca2 100644 --- a/aliases/available/kubectl.aliases.bash +++ b/aliases/available/kubectl.aliases.bash @@ -1,25 +1,20 @@ -#!/bin/bash -# -# -binaryanomaly - -cite 'about-alias' +# shellcheck shell=bash about-alias 'kubectl aliases' -function _set_pkg_aliases() -{ - if _command_exists kubectl; then - alias kc='kubectl' - alias kcgp='kubectl get pods' - alias kcgd='kubectl get deployments' - alias kcgn='kubectl get nodes' - alias kcdp='kubectl describe pod' - alias kcdd='kubectl describe deployment' - alias kcdn='kubectl describe node' - alias kcgpan='kubectl get pods --all-namespaces' - alias kcgdan='kubectl get deployments --all-namespaces' - # launches a disposable netshoot pod in the k8s cluster - alias kcnetshoot='kubectl run netshoot-$(date +%s) --rm -i --tty --image nicolaka/netshoot -- /bin/bash' - fi +function _set_pkg_aliases() { + if _command_exists kubectl; then + alias kc='kubectl' + alias kcgp='kubectl get pods' + alias kcgd='kubectl get deployments' + alias kcgn='kubectl get nodes' + alias kcdp='kubectl describe pod' + alias kcdd='kubectl describe deployment' + alias kcdn='kubectl describe node' + alias kcgpan='kubectl get pods --all-namespaces' + alias kcgdan='kubectl get deployments --all-namespaces' + # launches a disposable netshoot pod in the k8s cluster + alias kcnetshoot='kubectl run netshoot-$(date +%s) --rm -i --tty --image nicolaka/netshoot -- /bin/bash' + fi } _set_pkg_aliases diff --git a/aliases/available/laravel.aliases.bash b/aliases/available/laravel.aliases.bash index 75a51a01..50a9749f 100644 --- a/aliases/available/laravel.aliases.bash +++ b/aliases/available/laravel.aliases.bash @@ -1,9 +1,9 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'laravel artisan abbreviations' # A list of useful laravel aliases -alias laravel="${HOME}/.composer/vendor/bin/laravel" +alias laravel='${HOME?}/.composer/vendor/bin/laravel' # asset alias a:apub='php artisan asset:publish' diff --git a/aliases/available/maven.aliases.bash b/aliases/available/maven.aliases.bash index f8a44a1c..737826eb 100644 --- a/aliases/available/maven.aliases.bash +++ b/aliases/available/maven.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'maven abbreviations' alias mci='mvn clean install' diff --git a/aliases/available/msys2.aliases.bash b/aliases/available/msys2.aliases.bash index 000ea4bc..da41cc82 100644 --- a/aliases/available/msys2.aliases.bash +++ b/aliases/available/msys2.aliases.bash @@ -1,6 +1,4 @@ -#!/bin/bash - -cite 'about-alias' +# shellcheck shell=bash about-alias 'MSYS2 aliases' LS_COMMON="-hG" @@ -9,7 +7,7 @@ LS_COMMON="$LS_COMMON -I NTUSER.DAT\* -I ntuser.dat\*" # alias # setup the main ls alias if we've established common args -test -n "$LS_COMMON" && alias ls="command ls $LS_COMMON" +alias ls='command ls ${LS_COMMON:-}' alias ll="ls -l" alias la="ls -a" alias lal="ll -a" diff --git a/aliases/available/node.aliases.bash b/aliases/available/node.aliases.bash index a1408f26..a9e29743 100644 --- a/aliases/available/node.aliases.bash +++ b/aliases/available/node.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'the Node.js environment aliases' # alias to setup nodejs development environment diff --git a/aliases/available/npm.aliases.bash b/aliases/available/npm.aliases.bash index bd742d5d..27cf5c9f 100644 --- a/aliases/available/npm.aliases.bash +++ b/aliases/available/npm.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'common npm abbreviations' # Aliases diff --git a/aliases/available/osx.aliases.bash b/aliases/available/osx.aliases.bash index 5e30bc7c..0a16c06f 100644 --- a/aliases/available/osx.aliases.bash +++ b/aliases/available/osx.aliases.bash @@ -1,27 +1,28 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'osx-specific aliases' # Desktop Programs -alias fireworks="open -a '/Applications/Adobe Fireworks CS3/Adobe Fireworks CS3.app'" -alias photoshop="open -a '/Applications/Adobe Photoshop CS3/Adobe Photoshop.app'" -alias preview="open -a '$PREVIEW'" -alias xcode="open -a '/Applications/XCode.app'" -alias filemerge="open -a '/Developer/Applications/Utilities/FileMerge.app'" -alias safari="open -a safari" -alias firefox="open -a firefox" -alias chrome="open -a google\ chrome" -alias chromium="open -a chromium" -alias dashcode="open -a dashcode" +alias fireworks='open -a "/Applications/Adobe Fireworks CS3/Adobe Fireworks CS3.app"' +alias photoshop='open -a "/Applications/Adobe Photoshop CS3/Adobe Photoshop.app"' +alias preview='open -a "${PREVIEW?}"' +alias xcode='open -a "/Applications/XCode.app"' +alias filemerge='open -a "/Developer/Applications/Utilities/FileMerge.app"' +alias safari='open -a safari' +alias firefox='open -a firefox' +alias chrome='open -a "Google Chrome"' +alias chromium='open -a chromium' +alias brave='open -a "Brave Browser"' +alias dashcode='open -a dashcode' alias f='open -a Finder ' alias fh='open -a Finder .' alias textedit='open -a TextEdit' alias hex='open -a "Hex Fiend"' alias skype='open -a Skype' alias mou='open -a Mou' -alias subl='open -a Sublime\ Text' +alias subl='open -a "Sublime Text"' -if [ -s /usr/bin/firefox ] ; then - unalias firefox +if [[ -s /usr/bin/firefox ]]; then + unalias firefox fi # Requires growlnotify, which can be found in the Growl DMG under "Extras" @@ -37,19 +38,20 @@ alias whotunes='lsof -r 2 -n -P -F n -c iTunes -a -i TCP@`hostname`:3689' alias flush='dscacheutil -flushcache' # Show/hide hidden files (for Mac OS X Mavericks) -alias showhidden="defaults write com.apple.finder AppleShowAllFiles TRUE" -alias hidehidden="defaults write com.apple.finder AppleShowAllFiles FALSE" +alias showhidden='defaults write com.apple.finder AppleShowAllFiles TRUE' +alias hidehidden='defaults write com.apple.finder AppleShowAllFiles FALSE' # From http://apple.stackexchange.com/questions/110343/copy-last-command-in-terminal -alias copyLastCmd='fc -ln -1 | awk '\''{$1=$1}1'\'' ORS='\'''\'' | pbcopy' +# shellcheck disable=SC2142 # The quoting confuses `shellcheck`... +alias copyLastCmd="fc -ln -1 | awk '{\$1=\$1}1' ORS='' | pbcopy" # Use Finder's Quick Look on a file (^C or space to close) alias ql='qlmanage -p 2>/dev/null' # Mute/Unmute the system volume. Plays nice with all other volume settings. -alias mute="osascript -e 'set volume output muted true'" -alias unmute="osascript -e 'set volume output muted false'" +alias mute='osascript -e "set volume output muted true"' +alias unmute='osascript -e "set volume output muted false"' # Pin to the tail of long commands for an audible alert after long processes ## curl http://downloads.com/hugefile.zip; lmk -alias lmk="say 'Process complete.'" +alias lmk='say "Process complete."' diff --git a/aliases/available/phoenix.aliases.bash b/aliases/available/phoenix.aliases.bash index 64728a2e..08cef4f4 100644 --- a/aliases/available/phoenix.aliases.bash +++ b/aliases/available/phoenix.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'phoenix abbreviations' # Phoenix Commands diff --git a/aliases/available/puppet.aliases.bash b/aliases/available/puppet.aliases.bash index 15b69923..c92d13b1 100644 --- a/aliases/available/puppet.aliases.bash +++ b/aliases/available/puppet.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'puppet aliases' # Aliases diff --git a/aliases/available/pyrocms.aliases.bash b/aliases/available/pyrocms.aliases.bash index d19dff91..77865a23 100644 --- a/aliases/available/pyrocms.aliases.bash +++ b/aliases/available/pyrocms.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'pyrocms abbreviations' ### @@ -7,146 +7,146 @@ about-alias 'pyrocms abbreviations' ### # general -alias a:cl="php artisan clear-compiled" # Remove the compiled class file -alias a:d="php artisan down" # Put the application into maintenance mode -alias a:e="php artisan env" # Display the current framework environment -alias a:h="php artisan help" # Displays help for a command -alias a:i="php artisan install" # Install the Streams Platform. -alias a:ls="php artisan list" # Lists commands -alias a:mg="php artisan migrate" # Run the database migrations -alias a:op="php artisan optimize" # Optimize the framework for better performance (deprecated) -alias a:pr="php artisan preset" # Swap the front-end scaffolding for the application -alias a:s="php artisan serve" # Serve the application on the PHP development server -alias a:u="php artisan up" # Bring the application out of maintenance mode +alias a:cl="php artisan clear-compiled" # Remove the compiled class file +alias a:d="php artisan down" # Put the application into maintenance mode +alias a:e="php artisan env" # Display the current framework environment +alias a:h="php artisan help" # Displays help for a command +alias a:i="php artisan install" # Install the Streams Platform. +alias a:ls="php artisan list" # Lists commands +alias a:mg="php artisan migrate" # Run the database migrations +alias a:op="php artisan optimize" # Optimize the framework for better performance (deprecated) +alias a:pr="php artisan preset" # Swap the front-end scaffolding for the application +alias a:s="php artisan serve" # Serve the application on the PHP development server +alias a:u="php artisan up" # Bring the application out of maintenance mode # addon -alias a:ad:i="php artisan addon:install" # Install an addon. -alias a:ad:p="php artisan addon:publish" # Publish an the configuration and translations for an addon. -alias a:ad:r="php artisan addon:reinstall" # Reinstall an addon. -alias a:ad:u="php artisan addon:uninstall" # Uninstall an addon. +alias a:ad:i="php artisan addon:install" # Install an addon. +alias a:ad:p="php artisan addon:publish" # Publish an the configuration and translations for an addon. +alias a:ad:r="php artisan addon:reinstall" # Reinstall an addon. +alias a:ad:u="php artisan addon:uninstall" # Uninstall an addon. # app -alias a:ap:n="php artisan app:name" # Set the application namespace -alias a:ap:p="php artisan app:publish" # Publish general application override files. +alias a:ap:n="php artisan app:name" # Set the application namespace +alias a:ap:p="php artisan app:publish" # Publish general application override files. # assets -alias a:as:cl="php artisan assets:clear" # Clear compiled public assets. +alias a:as:cl="php artisan assets:clear" # Clear compiled public assets. # auth -alias a:au:clrs="php artisan auth:clear-resets" # Flush expired password reset tokens +alias a:au:clrs="php artisan auth:clear-resets" # Flush expired password reset tokens # cache -alias a:ca:cl="php artisan cache:clear" # Flush the application cache -alias a:ca:f="php artisan cache:forget" # Remove an item from the cache -alias a:ca:t="php artisan cache:table" # Create a migration for the cache database table +alias a:ca:cl="php artisan cache:clear" # Flush the application cache +alias a:ca:f="php artisan cache:forget" # Remove an item from the cache +alias a:ca:t="php artisan cache:table" # Create a migration for the cache database table # config -alias a:co:ca="php artisan config:cache" # Create a cache file for faster configuration loading -alias a:co:cl="php artisan config:clear" # Remove the configuration cache file +alias a:co:ca="php artisan config:cache" # Create a cache file for faster configuration loading +alias a:co:cl="php artisan config:clear" # Remove the configuration cache file # db -alias a:db:s="php artisan db:seed" # Seed the database with records +alias a:db:s="php artisan db:seed" # Seed the database with records # env -alias a:en:s="php artisan env:set" # Set an environmental value. +alias a:en:s="php artisan env:set" # Set an environmental value. # event -alias a:ev:g="php artisan event:generate" # Generate the missing events and listeners based on registration +alias a:ev:g="php artisan event:generate" # Generate the missing events and listeners based on registration # extension -alias a:ex:i="php artisan extension:install" # Install a extension. -alias a:ex:r="php artisan extension:reinstall" # Reinstall a extension. -alias a:ex:u="php artisan extension:uninstall" # Uninstall a extension. +alias a:ex:i="php artisan extension:install" # Install a extension. +alias a:ex:r="php artisan extension:reinstall" # Reinstall a extension. +alias a:ex:u="php artisan extension:uninstall" # Uninstall a extension. # files -alias a:fi:cl="php artisan files:clean" # Clean missing files from the files table. +alias a:fi:cl="php artisan files:clean" # Clean missing files from the files table. # key -alias a:ke:g="php artisan key:generate" # Set the application key +alias a:ke:g="php artisan key:generate" # Set the application key # make -alias a:mk:ad="php artisan make:addon" # Create a new addon. -alias a:mk:au="php artisan make:auth" # Scaffold basic login and registration views and routes -alias a:mk:cm="php artisan make:command" # Create a new Artisan command -alias a:mk:ct="php artisan make:controller" # Create a new controller class -alias a:mk:ev="php artisan make:event" # Create a new event class -alias a:mk:fa="php artisan make:factory" # Create a new model factory -alias a:mk:j="php artisan make:job" # Create a new job class -alias a:mk:li="php artisan make:listener" # Create a new event listener class -alias a:mk:ma="php artisan make:mail" # Create a new email class -alias a:mk:mw="php artisan make:middleware" # Create a new middleware class -alias a:mk:mg="php artisan make:migration" # Create a new migration file -alias a:mk:md="php artisan make:model" # Create a new Eloquent model class -alias a:mk:no="php artisan make:notification" # Create a new notification class -alias a:mk:po="php artisan make:policy" # Create a new policy class -alias a:mk:pr="php artisan make:provider" # Create a new service provider class -alias a:mk:rq="php artisan make:request" # Create a new form request class -alias a:mk:rs="php artisan make:resource" # Create a new resource -alias a:mk:rl="php artisan make:rule" # Create a new validation rule -alias a:mk:sd="php artisan make:seeder" # Create a new seeder class -alias a:mk:st="php artisan make:stream" # Make a streams entity namespace. -alias a:mk:ts="php artisan make:test" # Create a new test class +alias a:mk:ad="php artisan make:addon" # Create a new addon. +alias a:mk:au="php artisan make:auth" # Scaffold basic login and registration views and routes +alias a:mk:cm="php artisan make:command" # Create a new Artisan command +alias a:mk:ct="php artisan make:controller" # Create a new controller class +alias a:mk:ev="php artisan make:event" # Create a new event class +alias a:mk:fa="php artisan make:factory" # Create a new model factory +alias a:mk:j="php artisan make:job" # Create a new job class +alias a:mk:li="php artisan make:listener" # Create a new event listener class +alias a:mk:ma="php artisan make:mail" # Create a new email class +alias a:mk:mw="php artisan make:middleware" # Create a new middleware class +alias a:mk:mg="php artisan make:migration" # Create a new migration file +alias a:mk:md="php artisan make:model" # Create a new Eloquent model class +alias a:mk:no="php artisan make:notification" # Create a new notification class +alias a:mk:po="php artisan make:policy" # Create a new policy class +alias a:mk:pr="php artisan make:provider" # Create a new service provider class +alias a:mk:rq="php artisan make:request" # Create a new form request class +alias a:mk:rs="php artisan make:resource" # Create a new resource +alias a:mk:rl="php artisan make:rule" # Create a new validation rule +alias a:mk:sd="php artisan make:seeder" # Create a new seeder class +alias a:mk:st="php artisan make:stream" # Make a streams entity namespace. +alias a:mk:ts="php artisan make:test" # Create a new test class # migrate -alias a:mg:fr="php artisan migrate:fresh" # Drop all tables and re-run all migrations -alias a:mg:i="php artisan migrate:install" # Create the migration repository -alias a:mg:rf="php artisan migrate:refresh" # Reset and re-run all migrations -alias a:mg:rs="php artisan migrate:reset" # Rollback all database migrations -alias a:mg:rl="php artisan migrate:rollback" # Rollback the last database migration -alias a:mg:st="php artisan migrate:status" # Show the status of each migration +alias a:mg:fr="php artisan migrate:fresh" # Drop all tables and re-run all migrations +alias a:mg:i="php artisan migrate:install" # Create the migration repository +alias a:mg:rf="php artisan migrate:refresh" # Reset and re-run all migrations +alias a:mg:rs="php artisan migrate:reset" # Rollback all database migrations +alias a:mg:rl="php artisan migrate:rollback" # Rollback the last database migration +alias a:mg:st="php artisan migrate:status" # Show the status of each migration # module -alias a:mo:i="php artisan module:install" # Install a module. -alias a:mo:r="php artisan module:reinstall" # Reinstall a module. -alias a:mo:u="php artisan module:uninstall" # Uninstall a module. +alias a:mo:i="php artisan module:install" # Install a module. +alias a:mo:r="php artisan module:reinstall" # Reinstall a module. +alias a:mo:u="php artisan module:uninstall" # Uninstall a module. # notifications -alias a:no:tb="php artisan notifications:table" # Create a migration for the notifications table +alias a:no:tb="php artisan notifications:table" # Create a migration for the notifications table # package -alias a:pk:d="php artisan package:discover" # Rebuild the cached package manifest +alias a:pk:d="php artisan package:discover" # Rebuild the cached package manifest # queue -alias a:qu:fa="php artisan queue:failed" # List all of the failed queue jobs -alias a:qu:ft="php artisan queue:failed-table" # Create a migration for the failed queue jobs database table -alias a:qu:fl="php artisan queue:flush" # Flush all of the failed queue jobs -alias a:qu:fg="php artisan queue:forget" # Delete a failed queue job -alias a:qu:li="php artisan queue:listen" # Listen to a given queue -alias a:qu:rs="php artisan queue:restart" # Restart queue worker daemons after their current job -alias a:qu:rt="php artisan queue:retry" # Retry a failed queue job -alias a:qu:tb="php artisan queue:table" # Create a migration for the queue jobs database table -alias a:qu:w="php artisan queue:work" # Start processing jobs on the queue as a daemon +alias a:qu:fa="php artisan queue:failed" # List all of the failed queue jobs +alias a:qu:ft="php artisan queue:failed-table" # Create a migration for the failed queue jobs database table +alias a:qu:fl="php artisan queue:flush" # Flush all of the failed queue jobs +alias a:qu:fg="php artisan queue:forget" # Delete a failed queue job +alias a:qu:li="php artisan queue:listen" # Listen to a given queue +alias a:qu:rs="php artisan queue:restart" # Restart queue worker daemons after their current job +alias a:qu:rt="php artisan queue:retry" # Retry a failed queue job +alias a:qu:tb="php artisan queue:table" # Create a migration for the queue jobs database table +alias a:qu:w="php artisan queue:work" # Start processing jobs on the queue as a daemon # route -alias a:ro:ca="php artisan route:cache" # Create a route cache file for faster route registration -alias a:ro:cl="php artisan route:clear" # Remove the route cache file -alias a:ro:ls="php artisan route:list" # List all registered routes +alias a:ro:ca="php artisan route:cache" # Create a route cache file for faster route registration +alias a:ro:cl="php artisan route:clear" # Remove the route cache file +alias a:ro:ls="php artisan route:list" # List all registered routes # schedule -alias a:sc:r="php artisan schedule:run" # Run the scheduled commands +alias a:sc:r="php artisan schedule:run" # Run the scheduled commands # scout -alias a:su:fl="php artisan scout:flush" # Flush all of the model's records from the index -alias a:su:im="php artisan scout:import" # Import the given model into the search index +alias a:su:fl="php artisan scout:flush" # Flush all of the model's records from the index +alias a:su:im="php artisan scout:import" # Import the given model into the search index # session -alias a:se:tb="php artisan session:table" # Create a migration for the session database table +alias a:se:tb="php artisan session:table" # Create a migration for the session database table # storage -alias a:sg:l="php artisan storage:link" # Create a symbolic link from "public/storage" to "storage/app/public" +alias a:sg:l="php artisan storage:link" # Create a symbolic link from "public/storage" to "storage/app/public" # streams -alias a:st:cl="php artisan streams:cleanup" # Cleanup streams entry models. -alias a:st:co="php artisan streams:compile" # Compile streams entry models. -alias a:st:d="php artisan streams:destroy" # Destroy a namespace. -alias a:st:p="php artisan streams:publish" # Publish configuration and translations for streams. -alias a:st:r="php artisan streams:refresh" # Refresh streams generated components. +alias a:st:cl="php artisan streams:cleanup" # Cleanup streams entry models. +alias a:st:co="php artisan streams:compile" # Compile streams entry models. +alias a:st:d="php artisan streams:destroy" # Destroy a namespace. +alias a:st:p="php artisan streams:publish" # Publish configuration and translations for streams. +alias a:st:r="php artisan streams:refresh" # Refresh streams generated components. # tntsearch -alias a:tn:im="php artisan tntsearch:import" # Import the given model into the search index +alias a:tn:im="php artisan tntsearch:import" # Import the given model into the search index # vendor -alias a:ve:p="php artisan vendor:publish" # Publish any publishable assets from vendor packages +alias a:ve:p="php artisan vendor:publish" # Publish any publishable assets from vendor packages # view -alias a:vi:cl="php artisan view:clear" # Clear all compiled view files +alias a:vi:cl="php artisan view:clear" # Clear all compiled view files diff --git a/aliases/available/rails.aliases.bash b/aliases/available/rails.aliases.bash index c776660e..4de4faff 100644 --- a/aliases/available/rails.aliases.bash +++ b/aliases/available/rails.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'rails abbreviations' # Rails Commands @@ -14,9 +14,9 @@ alias rd='rails destroy' alias dbm='rake db:migrate' alias ss='script/server' -alias ts="thin start" # thin server +alias ts="thin start" # thin server alias sc='script/console' alias restartapp='touch tmp/restart.txt' -alias restart='touch tmp/restart.txt' # restart passenger +alias restart='touch tmp/restart.txt' # restart passenger alias devlog='tail -f log/development.log' alias taild='tail -f log/development.log' # tail dev log diff --git a/aliases/available/svn.aliases.bash b/aliases/available/svn.aliases.bash index 3d6d263e..4d3de464 100644 --- a/aliases/available/svn.aliases.bash +++ b/aliases/available/svn.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'common svn abbreviations' # Aliases diff --git a/aliases/available/systemd.aliases.bash b/aliases/available/systemd.aliases.bash index 19b0eae6..57351ae0 100644 --- a/aliases/available/systemd.aliases.bash +++ b/aliases/available/systemd.aliases.bash @@ -1,22 +1,22 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'systemd service' case $OSTYPE in - linux*) -# Improve aliases by bringing the common root `sc|scd` + `sre` for action + `u` for user - alias sc='systemctl' - alias scu='systemctl --user' - alias scdr='systemctl daemon-reload' - alias scdru='systemctl --user daemon-reload' - alias scr='systemctl restart' - alias scru='systemctl --user restart' - alias sce='systemctl stop' - alias sceu='systemctl --user stop' - alias scs='systemctl start' - alias scsu='systemctl --user start' -# Keeping previous aliases for a non-breaking change. - alias scue='sceu' - alias scus='scsu' - alias scur='scdru' - ;; + linux*) + # Improve aliases by bringing the common root `sc|scd` + `sre` for action + `u` for user + alias sc='systemctl' + alias scu='systemctl --user' + alias scdr='systemctl daemon-reload' + alias scdru='systemctl --user daemon-reload' + alias scr='systemctl restart' + alias scru='systemctl --user restart' + alias sce='systemctl stop' + alias sceu='systemctl --user stop' + alias scs='systemctl start' + alias scsu='systemctl --user start' + # Keeping previous aliases for a non-breaking change. + alias scue='sceu' + alias scus='scsu' + alias scur='scdru' + ;; esac diff --git a/aliases/available/terraform.aliases.bash b/aliases/available/terraform.aliases.bash index 09380868..baa9b0c7 100644 --- a/aliases/available/terraform.aliases.bash +++ b/aliases/available/terraform.aliases.bash @@ -1,7 +1,5 @@ -# Aliases for Terraform and Terragrunt - -cite 'about-alias' -about-alias 'Terraform abbreviations' +# shellcheck shell=bash +about-alias 'Aliases for Terraform and Terragrunt' alias tf='terraform' alias tfv='terraform validate' diff --git a/aliases/available/terragrunt.aliases.bash b/aliases/available/terragrunt.aliases.bash index 9395b351..94892901 100644 --- a/aliases/available/terragrunt.aliases.bash +++ b/aliases/available/terragrunt.aliases.bash @@ -1,7 +1,5 @@ -# Aliases for Terraform and Terragrunt - -cite 'about-alias' -about-alias 'Terragrunt abbreviations' +# shellcheck shell=bash +about-alias 'Aliases for Terraform and Terragrunt' alias tg='terragrunt' alias tgv='terragrunt validate' diff --git a/aliases/available/textmate.aliases.bash b/aliases/available/textmate.aliases.bash index f0f69e43..e53eed1a 100644 --- a/aliases/available/textmate.aliases.bash +++ b/aliases/available/textmate.aliases.bash @@ -1,10 +1,10 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'textmate abbreviations' case $OSTYPE in - darwin*) - # Textmate - alias e='mate . &' - alias et='mate app config db lib public script test spec config.ru Gemfile Rakefile README &' - ;; + darwin*) + # Textmate + alias e='mate . &' + alias et='mate app config db lib public script test spec config.ru Gemfile Rakefile README &' + ;; esac diff --git a/aliases/available/tmux.aliases.bash b/aliases/available/tmux.aliases.bash index 1b07f149..192db5b5 100644 --- a/aliases/available/tmux.aliases.bash +++ b/aliases/available/tmux.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'Tmux terminal multiplexer' alias txl='tmux ls' diff --git a/aliases/available/todo.txt-cli.aliases.bash b/aliases/available/todo.txt-cli.aliases.bash index 5bf35d0d..359321a4 100644 --- a/aliases/available/todo.txt-cli.aliases.bash +++ b/aliases/available/todo.txt-cli.aliases.bash @@ -1,8 +1,8 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'todo.txt-cli abbreviations' -alias tls="$TODO ls" -alias ta="$TODO a" -alias trm="$TODO rm" -alias tdo="$TODO do" -alias tpri="$TODO pri" +alias tls='"${TODO?}" ls' +alias ta='"${TODO?}" a' +alias trm='"${TODO?}" rm' +alias tdo='"${TODO?}" do' +alias tpri='"${TODO?}" pri' diff --git a/aliases/available/uuidgen.aliases.bash b/aliases/available/uuidgen.aliases.bash index aada05fb..45c36820 100644 --- a/aliases/available/uuidgen.aliases.bash +++ b/aliases/available/uuidgen.aliases.bash @@ -1,11 +1,11 @@ -cite 'uuid-alias' +# shellcheck shell=bash about-alias 'uuidgen aliases' if _command_exists uuid; then # Linux - alias uuidu="uuid | tr '[:lower:]' '[:upper:]'" - alias uuidl=uuid + alias uuidu="uuid | tr '[:lower:]' '[:upper:]'" + alias uuidl=uuid elif _command_exists uuidgen; then # macOS/BSD - alias uuidu="uuidgen" - alias uuid="uuidgen | tr '[:upper:]' '[:lower:]'" # because upper case is like YELLING - alias uuidl=uuid + alias uuidu="uuidgen" + alias uuid="uuidgen | tr '[:upper:]' '[:lower:]'" # because upper case is like YELLING + alias uuidl=uuid fi diff --git a/aliases/available/vagrant.aliases.bash b/aliases/available/vagrant.aliases.bash index d479fb2b..a949cbb3 100644 --- a/aliases/available/vagrant.aliases.bash +++ b/aliases/available/vagrant.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'vagrant aliases' # Aliases diff --git a/aliases/available/vault.aliases.bash b/aliases/available/vault.aliases.bash index d2ad8e74..4d083fb6 100644 --- a/aliases/available/vault.aliases.bash +++ b/aliases/available/vault.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'vault aliases' # Aliases diff --git a/aliases/available/vim.aliases.bash b/aliases/available/vim.aliases.bash index b426d270..f8068764 100644 --- a/aliases/available/vim.aliases.bash +++ b/aliases/available/vim.aliases.bash @@ -1,5 +1,4 @@ # shellcheck shell=bash -cite 'about-alias' about-alias 'vim abbreviations' _command_exists vim || return diff --git a/aliases/available/yarn.aliases.bash b/aliases/available/yarn.aliases.bash index af8c7adb..ed50be34 100644 --- a/aliases/available/yarn.aliases.bash +++ b/aliases/available/yarn.aliases.bash @@ -1,4 +1,4 @@ -cite 'about-alias' +# shellcheck shell=bash about-alias 'yarn package manager aliases' # Aliases diff --git a/bash_it.sh b/bash_it.sh index 03fd0bf5..ddc02b70 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -1,145 +1,110 @@ #!/usr/bin/env bash +# shellcheck source-path=SCRIPTDIR/lib source-path=SCRIPTDIR/scripts +# shellcheck disable=SC2034 +# # Initialize Bash It BASH_IT_LOG_PREFIX="core: main: " - -# Only set $BASH_IT if it's not already set -if [ -z "${BASH_IT:-}" ]; then - # Setting $BASH to maintain backwards compatibility - export BASH_IT=$BASH - BASH="$(bash -c 'echo $BASH')" - export BASH - BASH_IT_OLD_BASH_SETUP=true -fi +: "${BASH_IT:=${BASH_SOURCE%/*}}" +: "${BASH_IT_CUSTOM:=${BASH_IT}/custom}" +: "${CUSTOM_THEME_DIR:="${BASH_IT_CUSTOM}/themes"}" +: "${BASH_IT_BASHRC:=${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}}" # Load composure first, so we support function metadata -# shellcheck disable=SC1090 -source "${BASH_IT}"/vendor/github.com/erichs/composure/composure.sh - -# Declare our end-of-main finishing hook -declare -a _bash_it_library_finalize_hook - -# We need to load logging module early in order to be able to log -# shellcheck source-path=SCRIPTDIR/lib -source "${BASH_IT}/lib/log.bash" - -# We can only log it now -[ -z "${BASH_IT_OLD_BASH_SETUP:-}" ] || _log_warning "BASH_IT variable not initialized, please upgrade your bash-it version and reinstall it!" - -# For backwards compatibility, look in old BASH_THEME location -if [ -z "${BASH_IT_THEME:-}" ]; then - _log_warning "BASH_IT_THEME variable not initialized, please upgrade your bash-it version and reinstall it!" - export BASH_IT_THEME="${BASH_THEME:-}" - unset BASH_THEME -fi - +# shellcheck source-path=SCRIPTDIR/vendor/github.com/erichs/composure +source "${BASH_IT}/vendor/github.com/erichs/composure/composure.sh" # support 'plumbing' metadata cite _about _param _example _group _author _version cite about-alias about-plugin about-completion +# Declare our end-of-main finishing hook, but don't use `declare`/`typeset` +_bash_it_library_finalize_hook=() + +# We need to load logging module early in order to be able to log +source "${BASH_IT}/lib/log.bash" + # libraries, but skip appearance (themes) for now _log_debug "Loading libraries(except appearance)..." -LIB="${BASH_IT}/lib/*.bash" APPEARANCE_LIB="${BASH_IT}/lib/appearance.bash" -for _bash_it_config_file in $LIB; do - if [ "$_bash_it_config_file" != "$APPEARANCE_LIB" ]; then - filename=${_bash_it_config_file##*/} - filename=${filename%.bash} - BASH_IT_LOG_PREFIX="lib: ${filename}: " - _log_debug "Loading library file..." - # shellcheck disable=SC1090 - source "$_bash_it_config_file" - fi +for _bash_it_main_file_lib in "${BASH_IT}/lib"/*.bash; do + [[ "$_bash_it_main_file_lib" == "$APPEARANCE_LIB" ]] && continue + _bash-it-log-prefix-by-path "${_bash_it_main_file_lib}" + _log_debug "Loading library file..." + # shellcheck disable=SC1090 + source "$_bash_it_main_file_lib" + BASH_IT_LOG_PREFIX="core: main: " done -BASH_IT_LOG_PREFIX="core: main: " -# Load the global "enabled" directory -# "family" param is empty so that files get sources in glob order -# shellcheck source=./scripts/reloader.bash -source "${BASH_IT}/scripts/reloader.bash" - -# Load enabled aliases, completion, plugins -for file_type in "aliases" "plugins" "completion"; do - # shellcheck source=./scripts/reloader.bash - source "${BASH_IT}/scripts/reloader.bash" "skip" "$file_type" +# Load the global "enabled" directory, then enabled aliases, completion, plugins +# "_bash_it_main_file_type" param is empty so that files get sourced in glob order +for _bash_it_main_file_type in "" "aliases" "plugins" "completion"; do + BASH_IT_LOG_PREFIX="core: reloader: " + # shellcheck disable=SC2140 + source "${BASH_IT}/scripts/reloader.bash" ${_bash_it_main_file_type:+"skip" "$_bash_it_main_file_type"} + BASH_IT_LOG_PREFIX="core: main: " done # Load theme, if a theme was set -if [[ -n "${BASH_IT_THEME}" ]]; then - _log_debug "Loading \"${BASH_IT_THEME}\" theme..." +# shellcheck source-path=SCRIPTDIR/themes +if [[ -n "${BASH_IT_THEME:-}" ]]; then + _log_debug "Loading theme '${BASH_IT_THEME}'." BASH_IT_LOG_PREFIX="themes: githelpers: " - # shellcheck source=./themes/githelpers.theme.bash source "${BASH_IT}/themes/githelpers.theme.bash" BASH_IT_LOG_PREFIX="themes: p4helpers: " - # shellcheck source=./themes/p4helpers.theme.bash source "${BASH_IT}/themes/p4helpers.theme.bash" - BASH_IT_LOG_PREFIX="themes: command_duration: " - # shellcheck source=./themes/command_duration.theme.bash - source "${BASH_IT}/themes/command_duration.theme.bash" BASH_IT_LOG_PREFIX="themes: base: " - # shellcheck source=./themes/base.theme.bash source "${BASH_IT}/themes/base.theme.bash" BASH_IT_LOG_PREFIX="lib: appearance: " # appearance (themes) now, after all dependencies - # shellcheck source=./lib/appearance.bash + # shellcheck source=SCRIPTDIR/lib/appearance.bash source "$APPEARANCE_LIB" + BASH_IT_LOG_PREFIX="core: main: " fi -BASH_IT_LOG_PREFIX="core: main: " _log_debug "Loading custom aliases, completion, plugins..." -for file_type in "aliases" "completion" "plugins"; do - if [ -e "${BASH_IT}/${file_type}/custom.${file_type}.bash" ]; then - BASH_IT_LOG_PREFIX="${file_type}: custom: " +for _bash_it_main_file_type in "aliases" "completion" "plugins"; do + _bash_it_main_file_custom="${BASH_IT}/${_bash_it_main_file_type}/custom.${_bash_it_main_file_type}.bash" + if [[ -s "${_bash_it_main_file_custom}" ]]; then + _bash-it-log-prefix-by-path "${_bash_it_main_file_custom}" _log_debug "Loading component..." # shellcheck disable=SC1090 - source "${BASH_IT}/${file_type}/custom.${file_type}.bash" + source "${_bash_it_main_file_custom}" fi + BASH_IT_LOG_PREFIX="core: main: " done # Custom -BASH_IT_LOG_PREFIX="core: main: " _log_debug "Loading general custom files..." -CUSTOM="${BASH_IT_CUSTOM:=${BASH_IT}/custom}/*.bash ${BASH_IT_CUSTOM:=${BASH_IT}/custom}/**/*.bash" -for _bash_it_config_file in $CUSTOM; do - if [ -e "${_bash_it_config_file}" ]; then - filename=$(basename "${_bash_it_config_file}") - filename=${filename%*.bash} - # shellcheck disable=SC2034 - BASH_IT_LOG_PREFIX="custom: $filename: " +for _bash_it_main_file_custom in "${BASH_IT_CUSTOM}"/*.bash "${BASH_IT_CUSTOM}"/*/*.bash; do + if [[ -s "${_bash_it_main_file_custom}" ]]; then + _bash-it-log-prefix-by-path "${_bash_it_main_file_custom}" _log_debug "Loading custom file..." # shellcheck disable=SC1090 - source "$_bash_it_config_file" + source "$_bash_it_main_file_custom" fi + BASH_IT_LOG_PREFIX="core: main: " done -unset _bash_it_config_file if [[ -n "${PROMPT:-}" ]]; then - export PS1="\[""$PROMPT""\]" + PS1="${PROMPT}" fi # Adding Support for other OSes -PREVIEW="less" - -if [ -s /usr/bin/gloobus-preview ]; then +if _command_exists gloobus-preview; then PREVIEW="gloobus-preview" -elif [ -s /Applications/Preview.app ]; then - # shellcheck disable=SC2034 +elif [[ -d /Applications/Preview.app ]]; then PREVIEW="/Applications/Preview.app" +else + PREVIEW="less" fi # BASH_IT_RELOAD_LEGACY is set. -if ! _command_exists reload && [[ -n "${BASH_IT_RELOAD_LEGACY:-}" ]]; then - case $OSTYPE in - darwin*) - alias reload='source ~/.bash_profile' - ;; - *) - alias reload='source ~/.bashrc' - ;; - esac +if [[ -n "${BASH_IT_RELOAD_LEGACY:-}" ]] && ! _command_exists reload; then + # shellcheck disable=SC2139 + alias reload="builtin source '${BASH_IT_BASHRC?}'" fi for _bash_it_library_finalize_f in "${_bash_it_library_finalize_hook[@]:-}"; do eval "${_bash_it_library_finalize_f?}" # Use `eval` to achieve the same behavior as `$PROMPT_COMMAND`. done -unset "${!_bash_it_library_finalize_@}" +unset "${!_bash_it_library_finalize_@}" "${!_bash_it_main_file_@}" diff --git a/clean_files.txt b/clean_files.txt index 8f9c173a..de0f6c1e 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -16,6 +16,7 @@ # root directories # +aliases/ docs/ hooks/ scripts/ @@ -28,16 +29,11 @@ clean_files.txt install.sh lint_clean_files.sh -# aliases -# -aliases/available/dnf.aliases.bash -aliases/available/git.aliases.bash -aliases/available/vim.aliases.bash - # completions # completion/available/apm.completion.bash completion/available/awless.completion.bash +completion/available/awscli.completion.bash completion/available/bash-it.completion.bash completion/available/brew.completion.bash completion/available/cargo.completion.bash @@ -81,10 +77,14 @@ completion/available/vuejs.completion.bash completion/available/wpscan.completion.bash # libraries +lib/appearance.bash lib/colors.bash +lib/command_duration.bash lib/helpers.bash +lib/history.bash lib/log.bash lib/preexec.bash +lib/preview.bash lib/search.bash lib/utilities.bash @@ -137,10 +137,9 @@ plugins/available/zoxide.plugin.bash # tests # -test/plugins/alias-completion.plugin.bats +test/completion/aliases.completion.bats test/run test/test_helper.bash -test/test_helper_libs.bash # themes # @@ -158,11 +157,13 @@ themes/bobby-python themes/brainy themes/brunton themes/candy -themes/command_duration.theme.bash themes/easy themes/essential +themes/githelpers.theme.bash themes/modern themes/norbu +themes/oh-my-posh +themes/p4helpers.theme.bash themes/pete themes/powerline themes/pure diff --git a/completion/available/aliases.completion.bash b/completion/available/aliases.completion.bash new file mode 100644 index 00000000..f9cc1ed1 --- /dev/null +++ b/completion/available/aliases.completion.bash @@ -0,0 +1,112 @@ +# shellcheck shell=bash +about-plugin 'Automatic completion of aliases' +# Load after all aliases and completions to understand what needs to be completed +# BASH_IT_LOAD_PRIORITY: 800 + +# References: +# http://superuser.com/a/437508/119764 +# http://stackoverflow.com/a/1793178/1228454 + +# 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 tmp_file completion_loader alias_name line completions chars + local alias_arg_words new_completion compl_func compl_wrapper alias_defn + + # create array of function completion triggers, keeping multi-word triggers together + IFS=$'\n' read -d '' -ra completions < <(complete -p) + ((${#completions[@]} == 0)) && return 0 + + completions=("${completions[@]##complete -* * -}") # strip all but last option plus trigger(s) + completions=("${completions[@]#complete -}") # strip anything missed + completions=("${completions[@]#? * }") # strip last option and arg, leaving only trigger(s) + completions=("${completions[@]#? }") # strip anything missed + #TODO: this will fail on some completions... + + # create temporary file for wrapper functions and completions + tmp_file="$(mktemp -t "${namespace}-${RANDOM}XXXXXX")" || return 1 + + IFS=$'\n' read -r completion_loader < <(complete -p -D 2> /dev/null) + if [[ "${completion_loader#complete }" =~ '-F'[[:space:]]([[:alnum:]_]+)[[:space:]] ]]; then + completion_loader="${BASH_REMATCH[1]}" + else + completion_loader="" + fi + + # read in " '' ''" lines from defined aliases + # some aliases do have backslashes that needs to be interpreted + # shellcheck disable=SC2162 + while read line; do + line="${line#alias -- }" + line="${line#alias }" + alias_name="${line%%=*}" + alias_defn="${line#*=\'}" # alias definition + alias_defn="${alias_defn%\'}" + alias_cmd="${alias_defn%%[[:space:]]*}" # first word of alias + if [[ ${alias_defn} == ${alias_cmd} ]]; then + alias_args='' + else + alias_args="${alias_defn#*[[:space:]]}" # everything after first word + fi + + # skip aliases to pipes, boolean control structures and other command lists + chars='\|\&\;\)\(\n\<\>' + if [[ "${alias_defn}" =~ [$chars] ]]; then + continue + fi + # avoid expanding wildcards + read -ra alias_arg_words <<< "$alias_args" + + # skip alias if there is no completion function triggered by the aliased command + if ! _bash-it-array-contains-element "$alias_cmd" "${completions[@]}"; then + if [[ -n "$completion_loader" ]]; then + # force loading of completions for the aliased command + "${completion_loader:?}" "${alias_cmd}" + # 124 means completion loader was successful + [[ $? -eq 124 ]] || continue + completions+=("$alias_cmd") + else + continue + fi + 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}" + echo "function $compl_wrapper { + local compl_word=\${2?} + local prec_word=\${3?} + # check if prec_word is the alias itself. if so, replace it + # with the last word in the unaliased form, i.e., + # alias_cmd + ' ' + alias_args. + if [[ \$COMP_LINE == \"\$prec_word \$compl_word\" ]]; then + prec_word='$alias_cmd $alias_args' + prec_word=\${prec_word#* } + fi + (( COMP_CWORD += ${#alias_arg_words[@]} )) + COMP_WORDS=(\"$alias_cmd\" \"${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 + fi + + # replace completion trigger by alias + if [[ -n $new_completion ]]; then + new_completion="${new_completion% *} $alias_name" + echo "$new_completion" >> "$tmp_file" + fi + done < <(alias -p) + # shellcheck source=/dev/null + source "$tmp_file" && command rm -f "$tmp_file" +} + +_bash-it-component-completion-callback-on-init-aliases diff --git a/completion/available/awscli.completion.bash b/completion/available/awscli.completion.bash index a3041837..6b2c90ff 100644 --- a/completion/available/awscli.completion.bash +++ b/completion/available/awscli.completion.bash @@ -1,6 +1,5 @@ # shellcheck shell=bash -if _command_exists aws_completer -then +if _command_exists aws_completer; then complete -C "$(command -v aws_completer)" aws fi diff --git a/completion/available/bash-it.completion.bash b/completion/available/bash-it.completion.bash index 1f83d5c8..2259e37b 100644 --- a/completion/available/bash-it.completion.bash +++ b/completion/available/bash-it.completion.bash @@ -13,7 +13,7 @@ function _bash-it() { prev="${COMP_WORDS[COMP_CWORD - 1]}" verb="${COMP_WORDS[1]}" file_type="${COMP_WORDS[2]:-}" - candidates=('disable' 'enable' 'help' 'migrate' 'reload' 'restart' 'profile' 'doctor' 'search' 'show' 'update' 'version') + candidates=('disable' 'enable' 'help' 'migrate' 'reload' 'restart' 'preview' 'profile' 'doctor' 'search' 'show' 'update' 'version') case "${verb}" in show) candidates=('aliases' 'completions' 'plugins') @@ -59,6 +59,10 @@ function _bash-it() { _compreply_candidates ;; migrate | reload | restart | search | version) ;; + preview) + _bash-it-preview # completes itself + return 0 + ;; enable | disable) if [[ "${verb}" == "enable" ]]; then suffix="disabled" diff --git a/completion/available/knife.completion.bash b/completion/available/knife.completion.bash index 4b9950ed..c0fb6a99 100644 --- a/completion/available/knife.completion.bash +++ b/completion/available/knife.completion.bash @@ -55,12 +55,12 @@ _KAC_regen_cache() { # cached files can't have spaces in their names _KAC_get_cache_name_from_command() { - echo "${@/ /_SPACE_}" + echo "${@// /_SPACE_}" } # the reverse operation from the function above _KAC_get_command_from_cache_name() { - echo "${@/_SPACE_/ }" + echo "${@//_SPACE_/ }" } # given a command as argument, it fetches the cache for that command if it can find it diff --git a/completion/available/system.completion.bash b/completion/available/system.completion.bash index af7ea70d..bb1d14eb 100644 --- a/completion/available/system.completion.bash +++ b/completion/available/system.completion.bash @@ -14,31 +14,24 @@ else __bash_it_restore_nounset=false fi +# shellcheck disable=SC1090 disable=SC1091 if [[ -r "${BASH_COMPLETION:-}" ]]; then - # shellcheck disable=SC1090 source "${BASH_COMPLETION}" - elif [[ -r /etc/bash_completion ]]; then - # shellcheck disable=SC1091 source /etc/bash_completion - # Some distribution makes use of a profile.d script to import completion. elif [[ -r /etc/profile.d/bash_completion.sh ]]; then - # shellcheck disable=SC1091 source /etc/profile.d/bash_completion.sh - elif _bash_it_homebrew_check; then - : "${BASH_COMPLETION_COMPAT_DIR:=$BASH_IT_HOMEBREW_PREFIX/etc/bash_completion.d}" - + : "${BASH_COMPLETION_COMPAT_DIR:=${BASH_IT_HOMEBREW_PREFIX}/etc/bash_completion.d}" case "${BASH_VERSION}" in 1* | 2* | 3.0* | 3.1*) _log_warning "Cannot load completion due to version of shell. Are you using Bash 3.2+?" ;; 3.2* | 4.0* | 4.1*) # Import version 1.x of bash-completion, if installed. - BASH_COMPLETION="$BASH_IT_HOMEBREW_PREFIX/opt/bash-completion@1/etc/bash_completion" + BASH_COMPLETION="${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@1/etc/bash_completion" if [[ -r "$BASH_COMPLETION" ]]; then - # shellcheck disable=SC1090 source "$BASH_COMPLETION" else unset BASH_COMPLETION @@ -46,9 +39,8 @@ elif _bash_it_homebrew_check; then ;; 4.2* | 5* | *) # homebrew/versions/bash-completion2 (required for projects.completion.bash) is installed to this path - if [[ -r "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" ]]; then - # shellcheck disable=SC1091 - source "${BASH_IT_HOMEBREW_PREFIX}/etc/profile.d/bash_completion.sh" + if [[ -r "${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@2/etc/profile.d/bash_completion.sh" ]]; then + source "${BASH_IT_HOMEBREW_PREFIX}/opt/bash-completion@2/etc/profile.d/bash_completion.sh" fi ;; esac diff --git a/docs/themes-list/index.rst b/docs/themes-list/index.rst index 49c5a623..0275001b 100644 --- a/docs/themes-list/index.rst +++ b/docs/themes-list/index.rst @@ -346,6 +346,19 @@ NWinkler :alt: +---- + +.. _oh_my_posh_image: + +Oh-My-Posh +^^^^^^^^^^ + + +.. image:: https://bash-it.github.io/bash-it/docs/images/oh-my-posh.png + :target: https://bash-it.github.io/bash-it/docs/images/oh-my-posh.png + :alt: + + ---- Pete diff --git a/docs/themes-list/oh-my-posh.rst b/docs/themes-list/oh-my-posh.rst new file mode 100644 index 00000000..974adc0f --- /dev/null +++ b/docs/themes-list/oh-my-posh.rst @@ -0,0 +1,15 @@ +.. _oh-my-posh: + +Oh-My-Posh Theme +================ + +The oh-my-posh ״theme״ is really a plug to a whole other system +of managing your prompt. To use it please start here: +`Oh-My-Posh homepage `_ + +It is beyond the scope of bash-it to install and manage oh-my-posh, +this theme is here just to make sure your OMP setup doesn't clash +with other bash-it themes. Once installed, OMP will load a default +OMP theme (jandedobbeleer), which you can then customize or override. + +Note: Nerd Fonts are highly recommended, as most of the themes are graphic candies. diff --git a/docs/themes.rst b/docs/themes.rst index 5b796389..8cfbeb23 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -22,7 +22,7 @@ Examples: # Disable theming export BASH_IT_THEME="" -You can easily preview the themes in your own shell using ``BASH_PREVIEW=true bash-it reload``. +You can easily preview the themes in your own shell using ``bash-it preview``. If you've created your own custom prompts, we'd love it if you shared them with everyone else! Just submit a Pull Request. You can see theme screenshots on `wiki/Themes `_. diff --git a/lib/appearance.bash b/lib/appearance.bash index 6d0ef2ff..e77a1a80 100644 --- a/lib/appearance.bash +++ b/lib/appearance.bash @@ -1,19 +1,18 @@ -#!/usr/bin/env bash +# shellcheck shell=bash -# colored ls -export LSCOLORS='Gxfxcxdxdxegedabagacad' +: "${CLICOLOR:=$(tput colors)}" +export CLICOLOR -if [[ -z "$CUSTOM_THEME_DIR" ]]; then - CUSTOM_THEME_DIR="${BASH_IT_CUSTOM:=${BASH_IT}/custom}/themes" -fi +: "${CUSTOM_THEME_DIR:="${BASH_IT_CUSTOM:=${BASH_IT}/custom}/themes"}" # Load the theme -if [[ $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 +# 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/lib/command_duration.bash b/lib/command_duration.bash new file mode 100644 index 00000000..cd1d6636 --- /dev/null +++ b/lib/command_duration.bash @@ -0,0 +1,61 @@ +# shellcheck shell=bash +# +# Functions for measuring and reporting how long a command takes to run. + +: "${COMMAND_DURATION_START_SECONDS:=${EPOCHREALTIME:-$SECONDS}}" +: "${COMMAND_DURATION_ICON:=🕘}" +: "${COMMAND_DURATION_MIN_SECONDS:=1}" + +function _command_duration_pre_exec() { + COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" +} + +function _dynamic_clock_icon { + local clock_hand + # clock hand value is between 90 and 9b in hexadecimal. + # so between 144 and 155 in base 10. + printf -v clock_hand '%x' $(((${1:-${SECONDS}} % 12) + 144)) + printf -v 'COMMAND_DURATION_ICON' '%b' "\xf0\x9f\x95\x$clock_hand" +} + +function _command_duration() { + [[ -n "${BASH_IT_COMMAND_DURATION:-}" ]] || return + + local command_duration=0 command_start="${COMMAND_DURATION_START_SECONDS:-0}" + local -i minutes=0 seconds=0 deciseconds=0 + local -i command_start_seconds="${command_start%.*}" + local -i command_start_deciseconds=$((10#${command_start##*.})) + command_start_deciseconds="${command_start_deciseconds:0:1}" + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i current_time_seconds="${current_time%.*}" + local -i current_time_deciseconds="$((10#${current_time##*.}))" + current_time_deciseconds="${current_time_deciseconds:0:1}" + + if [[ "${command_start_seconds:-0}" -gt 0 ]]; then + # seconds + command_duration="$((current_time_seconds - command_start_seconds))" + + if ((current_time_deciseconds >= command_start_deciseconds)); then + deciseconds="$((current_time_deciseconds - command_start_deciseconds))" + else + ((command_duration -= 1)) + deciseconds="$((10 - (command_start_deciseconds - current_time_deciseconds)))" + fi + else + command_duration=0 + fi + + if ((command_duration > 0)); then + minutes=$((command_duration / 60)) + seconds=$((command_duration % 60)) + fi + + _dynamic_clock_icon "${command_duration}" + if ((minutes > 0)); then + printf "%s %s%dm %ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$minutes" "$seconds" + elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then + printf "%s %s%d.%01ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$seconds" "$deciseconds" + fi +} + +_bash_it_library_finalize_hook+=("safe_append_preexec '_command_duration_pre_exec'") diff --git a/lib/helpers.bash b/lib/helpers.bash index 66cdec74..c0ce2eb3 100644 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -8,16 +8,19 @@ : "${BASH_IT_LOAD_PRIORITY_COMPLETION:=350}" BASH_IT_LOAD_PRIORITY_SEPARATOR="---" -# Handle the different ways of running `sed` without generating a backup file based on OS -# - GNU sed (Linux) uses `-i` -# - BSD sed (macOS) uses `-i ''` +# Handle the different ways of running `sed` without generating a backup file based on provenance: +# - GNU sed (Linux) uses `-i''` +# - BSD sed (FreeBSD/macOS/Solaris/PlayStation) uses `-i ''` # To use this in Bash-it for inline replacements with `sed`, use the following syntax: # sed "${BASH_IT_SED_I_PARAMETERS[@]}" -e "..." file -BASH_IT_SED_I_PARAMETERS=('-i') # shellcheck disable=SC2034 # expected for this case -case "$OSTYPE" in - 'darwin'*) BASH_IT_SED_I_PARAMETERS=('-i' '') ;; -esac +if sed --version > /dev/null 2>&1; then + # GNU sed accepts "long" options + BASH_IT_SED_I_PARAMETERS=('-i') +else + # BSD sed errors on invalid option `-` + BASH_IT_SED_I_PARAMETERS=('-i' '') +fi function _command_exists() { _about 'checks for existence of a command' @@ -98,7 +101,7 @@ alias reload_plugins="$(_make_reload_alias plugin plugins)" function bash-it() { about 'Bash-it help and maintenance' - param '1: verb [one of: help | show | enable | disable | migrate | update | search | version | reload | restart | doctor ] ' + param '1: verb [one of: help | show | enable | disable | migrate | update | search | preview | version | reload | restart | doctor ] ' param '2: component type [one of: alias(es) | completion(s) | plugin(s) ] or search term(s)' param '3: specific component [optional]' example '$ bash-it show plugins' @@ -108,6 +111,8 @@ function bash-it() { example '$ bash-it migrate' example '$ bash-it update' example '$ bash-it search [-|@]term1 [-|@]term2 ... [ -e/--enable ] [ -d/--disable ] [ -r/--refresh ] [ -c/--no-color ]' + example '$ bash-it preview' + example '$ bash-it preview essential' example '$ bash-it version' example '$ bash-it reload' example '$ bash-it restart' @@ -142,6 +147,10 @@ function bash-it() { _bash-it-search "$component" "$@" return ;; + preview) + _bash-it-preview "$component" "$@" + return + ;; update) func="_bash-it-update-$component" ;; @@ -249,10 +258,10 @@ function _bash-it_update_migrate_and_restart() { _about 'Checks out the wanted version, pops directory and restart. Does not return (because of the restart!)' _param '1: Which branch to checkout to' _param '2: Which type of version we are using' - if git checkout "$1" &> /dev/null; then + if git checkout "${1?}" &> /dev/null; then echo "Bash-it successfully updated." echo "" - echo "Migrating your installation to the latest $2 version now..." + echo "Migrating your installation to the latest ${2:-} version now..." _bash-it-migrate echo "" echo "All done, enjoy!" @@ -269,7 +278,7 @@ function _bash-it-update-() { _param '1: What kind of update to do (stable|dev)' _group 'lib' - local silent word DIFF version TARGET revision status revert log_color num_of_lines description i RESP + local silent word DIFF version TARGET revision status revert log_color RESP for word in "$@"; do if [[ "${word}" == "--silent" || "${word}" == "-s" ]]; then silent=true @@ -294,7 +303,7 @@ function _bash-it-update-() { BASH_IT_DEVELOPMENT_BRANCH="master" fi # Defaults to stable update - if [[ -z "$1" || "$1" == "stable" ]]; then + if [[ -z "${1:-}" || "$1" == "stable" ]]; then version="stable" TARGET=$(git describe --tags "$(git rev-list --tags --max-count=1)" 2> /dev/null) @@ -325,15 +334,7 @@ function _bash-it-update-() { log_color="%Cred" fi - for i in $(git rev-list --merges --first-parent "${revision}"); do - num_of_lines=$(git log -1 --format=%B "$i" | awk '!/^[[:space:]]*$/ {++i} END{print i}') - if [[ "$num_of_lines" -eq 1 ]]; then - description="%s" - else - description="%b" - fi - git log --format="${log_color}%h: $description (%an)" -1 "$i" - done + git log --format="${log_color}%h: %s (%an)" "${revision}" echo "" if [[ -n "${silent}" ]]; then @@ -505,7 +506,6 @@ function _bash-it-profile-save() { case "$RESP" in [yY]) echo -e "${echo_green?}Overwriting profile '$name'...${echo_reset_color?}" - rm "$profile_path" break ;; [nN] | "") @@ -537,7 +537,7 @@ function _bash-it-profile-save() { fi done done - if [[ -z "$something_exists" ]]; then + if [[ -z "${something_exists:-}" ]]; then echo "It seems like no configuration was enabled.." echo "Make sure to double check that this is the wanted behavior." fi @@ -555,30 +555,30 @@ _bash-it-profile-load-parse-profile() { _example '$ _bash-it-profile-load-parse-profile "profile.bash_it" "dry"' local -i num=0 - local line + local line enable_func subdirectory component to_enable bad while read -r -a line; do ((++num)) # Ignore comments and empty lines [[ -z "${line[*]}" || "${line[*]}" =~ ^#.* ]] && continue - local enable_func="_enable-${line[0]}" - local subdirectory=${line[0]} - local component=${line[1]} + enable_func="_enable-${line[0]}" + subdirectory=${line[0]} + component=${line[1]} - local to_enable=("${BASH_IT}/$subdirectory/available/$component.${subdirectory%s}"*.bash) + to_enable=("${BASH_IT}/$subdirectory/available/$component.${subdirectory%s}"*.bash) # Ignore botched lines if [[ ! -e "${to_enable[0]}" ]]; then echo -e "${echo_orange?}Bad line(#$num) in profile, aborting load...${line[*]}${echo_reset_color?}" - local bad="bad line" + bad="bad line" break fi # Do not actually modify config on dry run - [[ -z $2 ]] || continue + [[ -z "${2:-}" ]] || continue # Actually enable the component $enable_func "$component" - done < "$1" + done < "${1?}" # Make sure to propagate the error - [[ -z $bad ]] + [[ -z ${bad:-} ]] } _bash-it-profile-list() { @@ -597,7 +597,7 @@ _bash-it-profile-rm() { about 'Removes a profile from the "profiles" directory' _group 'lib' - local name="$1" + local name="${1:-}" if [[ -z $name ]]; then echo -e "${echo_orange?}Please specify profile name to remove...${echo_reset_color?}" return 1 @@ -623,7 +623,7 @@ _bash-it-profile-load() { _about 'loads a configuration from the "profiles" directory' _group 'lib' - local name="$1" + local name="${1:-}" if [[ -z $name ]]; then echo -e "${echo_orange?}Please specify profile name to load, not changing configuration...${echo_reset_color?}" return 1 @@ -654,19 +654,15 @@ function _bash-it-restart() { _about 'restarts the shell in order to fully reload it' _group 'lib' - local saved_pwd="${PWD}" init_file="${BASH_IT_BASHRC:-${HOME?}/.bashrc}" - - exec "${0/-/}" --rcfile <(echo "source \"${init_file}\"; cd \"$saved_pwd\"") + exec "${0#-}" --rcfile "${BASH_IT_BASHRC:-${HOME?}/.bashrc}" } function _bash-it-reload() { - _about 'reloads a profile file' + _about 'reloads the shell initialization file' _group 'lib' - pushd "${BASH_IT?}" > /dev/null || return # shellcheck disable=SC1090 source "${BASH_IT_BASHRC:-${HOME?}/.bashrc}" - popd > /dev/null || return } function _bash-it-describe() { @@ -704,7 +700,9 @@ function _on-disable-callback() { _group 'lib' local callback="${1}_on_disable" - _command_exists "$callback" && "$callback" + if _command_exists "$callback"; then + "$callback" + fi } function _disable-all() { @@ -723,8 +721,8 @@ function _disable-plugin() { _example '$ disable-plugin rvm' _group 'lib' - _disable-thing "plugins" "plugin" "$1" - _on-disable-callback "$1" + _disable-thing "plugins" "plugin" "${1?}" + _on-disable-callback "${1?}" } function _disable-alias() { @@ -733,7 +731,7 @@ function _disable-alias() { _example '$ disable-alias git' _group 'lib' - _disable-thing "aliases" "alias" "$1" + _disable-thing "aliases" "alias" "${1?}" } function _disable-completion() { @@ -742,7 +740,7 @@ function _disable-completion() { _example '$ disable-completion git' _group 'lib' - _disable-thing "completion" "completion" "$1" + _disable-thing "completion" "completion" "${1?}" } function _disable-thing() { @@ -776,7 +774,7 @@ function _disable-thing() { # Either one will be matched by this glob for plugin in "${BASH_IT}/enabled"/[[:digit:]][[:digit:]][[:digit:]]"${BASH_IT_LOAD_PRIORITY_SEPARATOR}${file_entity}.${suffix}.bash" "${BASH_IT}/$subdirectory/enabled/"{[[:digit:]][[:digit:]][[:digit:]]"${BASH_IT_LOAD_PRIORITY_SEPARATOR}${file_entity}.${suffix}.bash","${file_entity}.${suffix}.bash"}; do if [[ -e "${plugin}" ]]; then - rm "${plugin}" + rm -f "${plugin}" plugin= break fi @@ -787,10 +785,11 @@ function _disable-thing() { fi fi - _bash-it-clean-component-cache "${file_type}" + _bash-it-component-cache-clean "${file_type}" - if [[ "$file_entity" = "all" ]]; then - printf '%s\n' "$file_entity $(_bash-it-pluralize-component "$file_type") disabled." + if [[ "$file_entity" == "all" ]]; then + _bash-it-component-pluralize "$file_type" file_type + printf '%s\n' "$file_entity ${file_type} disabled." else printf '%s\n' "$file_entity disabled." fi @@ -802,7 +801,7 @@ function _enable-plugin() { _example '$ enable-plugin rvm' _group 'lib' - _enable-thing "plugins" "plugin" "$1" "$BASH_IT_LOAD_PRIORITY_PLUGIN" + _enable-thing "plugins" "plugin" "${1?}" "$BASH_IT_LOAD_PRIORITY_PLUGIN" } function _enable-plugins() { @@ -816,7 +815,7 @@ function _enable-alias() { _example '$ enable-alias git' _group 'lib' - _enable-thing "aliases" "alias" "$1" "$BASH_IT_LOAD_PRIORITY_ALIAS" + _enable-thing "aliases" "alias" "${1?}" "$BASH_IT_LOAD_PRIORITY_ALIAS" } function _enable-aliases() { @@ -830,7 +829,7 @@ function _enable-completion() { _example '$ enable-completion git' _group 'lib' - _enable-thing "completion" "completion" "$1" "$BASH_IT_LOAD_PRIORITY_COMPLETION" + _enable-thing "completion" "completion" "${1?}" "$BASH_IT_LOAD_PRIORITY_COMPLETION" } function _enable-thing() { @@ -885,7 +884,7 @@ function _enable-thing() { ln -s "../$subdirectory/available/$to_enable" "${BASH_IT}/enabled/${use_load_priority}${BASH_IT_LOAD_PRIORITY_SEPARATOR}${to_enable}" fi - _bash-it-clean-component-cache "${file_type}" + _bash-it-component-cache-clean "${file_type}" printf '%s\n' "$file_entity enabled with priority $use_load_priority." } @@ -903,7 +902,7 @@ function _help-aliases() { _example '$ alias-help' _example '$ alias-help git' - if [[ -n "$1" ]]; then + if [[ -n "${1:-}" ]]; then case "$1" in custom) alias_path='custom.aliases.bash' @@ -1016,14 +1015,14 @@ function pathmunge() { # 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. function _bash-it-find-in-ancestor() ( - about 'searches parents of the current directory for any of the specified file names' - group 'helpers' - param '*: names of files or folders to search for' - returns '0: prints path of closest matching ancestor directory to stdout' - returns '1: no match found' - returns '2: improper usage of shell builtin' # uncommon - example '_bash-it-find-in-ancestor .git .hg' - example '_bash-it-find-in-ancestor GNUmakefile Makefile makefile' + : _about 'searches parents of the current directory for any of the specified file names' + : _group 'helpers' + : _param '*: names of files or folders to search for' + : _returns '0: prints path of closest matching ancestor directory to stdout' + : _returns '1: no match found' + : _returns '2: improper usage of shell builtin' # uncommon + : _example '_bash-it-find-in-ancestor .git .hg' + : _example '_bash-it-find-in-ancestor GNUmakefile Makefile makefile' local kin # To keep things simple, we do not search the root dir. diff --git a/lib/history.bash b/lib/history.bash new file mode 100644 index 00000000..7bdbbd5e --- /dev/null +++ b/lib/history.bash @@ -0,0 +1,49 @@ +# shellcheck shell=bash +# +# Functions for working with Bash's command history. + +function _bash-it-history-init() { + safe_append_preexec '_bash-it-history-auto-save' + safe_append_prompt_command '_bash-it-history-auto-load' +} + +function _bash-it-history-auto-save() { + case $HISTCONTROL in + *'noauto'* | *'autoload'*) + : # Do nothing, as configured. + ;; + *'auto'*) + # Append new history from this session to the $HISTFILE + history -a + ;; + *) + # Append *only* if shell option `histappend` has been enabled. + shopt -q histappend && history -a && return + ;; + esac +} + +function _bash-it-history-auto-load() { + case $HISTCONTROL in + *'noauto'*) + : # Do nothing, as configured. + ;; + *'autosave'*) + # Append new history from this session to the $HISTFILE + history -a + ;; + *'autoloadnew'*) + # Read new entries from $HISTFILE + history -n + ;; + *'auto'*) + # Blank in-memory history, then read entire $HISTFILE fresh from disk. + history -a && history -c && history -r + ;; + *) + : # Do nothing, default. + ;; + esac +} + +_bash_it_library_finalize_hook+=('_bash-it-history-init') diff --git a/lib/log.bash b/lib/log.bash index 444a6854..a8cb8080 100644 --- a/lib/log.bash +++ b/lib/log.bash @@ -45,46 +45,56 @@ function _bash-it-log-prefix-by-path() { function _has_colors() { # Check that stdout is a terminal, and that it has at least 8 colors. - [[ -t 1 && "${_bash_it_available_colors:=$(tput colors 2> /dev/null)}" -ge 8 ]] + [[ -t 1 && "${CLICOLOR:=$(tput colors 2> /dev/null)}" -ge 8 ]] } function _bash-it-log-message() { - about 'Internal function used for logging, uses BASH_IT_LOG_PREFIX as a prefix' - param '1: color of the message' - param '2: log level to print before the prefix' - param '3: message to log' - group 'log' + : _about 'Internal function used for logging, uses BASH_IT_LOG_PREFIX as a prefix' + : _param '1: color of the message' + : _param '2: log level to print before the prefix' + : _param '3: message to log' + : _group 'log' - message="$2${BASH_IT_LOG_PREFIX:-default: }$3" - _has_colors && echo -e "$1${message}${echo_normal:-}" || echo -e "${message}" + local prefix="${BASH_IT_LOG_PREFIX:-default}" + local color="${1-${echo_cyan:-}}" + local level="${2:-TRACE}" + local message="${level%: }: ${prefix%: }: ${3?}" + if _has_colors; then + printf '%b%s%b\n' "${color}" "${message}" "${echo_normal:-}" + else + printf '%s\n' "${message}" + fi } function _log_debug() { - about 'log a debug message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_INFO' - param '1: message to log' - example '$ _log_debug "Loading plugin git..."' - group 'log' + : _about 'log a debug message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_INFO' + : _param '1: message to log' + : _example '$ _log_debug "Loading plugin git..."' + : _group 'log' - [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_INFO?}" ]] || return 0 - _bash-it-log-message "${echo_green:-}" "DEBUG: " "$1" + if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_INFO?}" ]]; then + _bash-it-log-message "${echo_green:-}" "DEBUG: " "$1" + fi } function _log_warning() { - about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_WARNING' - param '1: message to log' - example '$ _log_warning "git binary not found, disabling git plugin..."' - group 'log' + : _about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_WARNING' + : _param '1: message to log' + : _example '$ _log_warning "git binary not found, disabling git plugin..."' + : _group 'log' - [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_WARNING?}" ]] || return 0 - _bash-it-log-message "${echo_yellow:-}" " WARN: " "$1" + if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_WARNING?}" ]]; then + _bash-it-log-message "${echo_yellow:-}" " WARN: " "$1" + fi } function _log_error() { - about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_ERROR' - param '1: message to log' - example '$ _log_error "Failed to load git plugin..."' - group 'log' + : _about 'log a message by echoing to the screen. needs BASH_IT_LOG_LEVEL >= BASH_IT_LOG_LEVEL_ERROR' + : _param '1: message to log' + : _example '$ _log_error "Failed to load git plugin..."' + : _group 'log' - [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_ERROR?}" ]] || return 0 - _bash-it-log-message "${echo_red:-}" "ERROR: " "$1" + if [[ "${BASH_IT_LOG_LEVEL:-0}" -ge "${BASH_IT_LOG_LEVEL_ERROR?}" ]]; then + _bash-it-log-message "${echo_red:-}" "ERROR: " "$1" + fi } diff --git a/lib/preexec.bash b/lib/preexec.bash index 17cabdf9..1dbe8899 100644 --- a/lib/preexec.bash +++ b/lib/preexec.bash @@ -4,9 +4,8 @@ # Load the `bash-preexec.sh` library, and define helper functions ## Prepare, load, fix, and install `bash-preexec.sh` -: "${PROMPT_COMMAND:=}" -# Disable immediate `$PROMPT_COMMAND` modification +# Disable `$PROMPT_COMMAND` modification for now. __bp_delay_install="delayed" # shellcheck source-path=SCRIPTDIR/../vendor/github.com/rcaloras/bash-preexec @@ -18,12 +17,12 @@ function __bp_adjust_histcontrol() { :; } # Don't fail on readonly variables function __bp_require_not_readonly() { :; } -# Disable trap DEBUG on subshells - https://github.com/Bash-it/bash-it/pull/1040 -__bp_enable_subshells= # blank -set +T +# For performance, testing, and to avoid unexpected behavior: disable DEBUG traps in subshells. +# See bash-it/bash-it#1040 and rcaloras/bash-preexec#26 +: "${__bp_enable_subshells:=}" # blank -# Modify `$PROMPT_COMMAND` now -__bp_install_after_session_init +# Modify `$PROMPT_COMMAND` in finalize hook +_bash_it_library_finalize_hook+=('__bp_install_after_session_init') ## Helper functions function __check_precmd_conflict() { @@ -38,26 +37,20 @@ function __check_preexec_conflict() { _bash-it-array-contains-element "${f}" "${preexec_functions[@]}" } -function safe_append_prompt_command { - local prompt_re f - __bp_trim_whitespace f "${1?}" +function safe_append_prompt_command() { + local prompt_re prompt_er f - if [ "${__bp_imported:-missing}" == "defined" ]; then + if [[ "${bash_preexec_imported:-${__bp_imported:-missing}}" == "defined" ]]; then # We are using bash-preexec + __bp_trim_whitespace f "${1?}" if ! __check_precmd_conflict "${f}"; then precmd_functions+=("${f}") fi else - # Set OS dependent exact match regular expression - if [[ ${OSTYPE} == darwin* ]]; then - # macOS - prompt_re="[[:<:]]${1}[[:>:]]" - else - # Linux, FreeBSD, etc. - prompt_re="\<${1}\>" - fi - - if [[ ${PROMPT_COMMAND} =~ ${prompt_re} ]]; then + # Match on word-boundaries + prompt_re='(^|[^[:alnum:]_])' + prompt_er='([^[:alnum:]_]|$)' + if [[ ${PROMPT_COMMAND} =~ ${prompt_re}"${1}"${prompt_er} ]]; then return elif [[ -z ${PROMPT_COMMAND} ]]; then PROMPT_COMMAND="${1}" @@ -67,12 +60,12 @@ function safe_append_prompt_command { fi } -function safe_append_preexec { +function safe_append_preexec() { local prompt_re f - __bp_trim_whitespace f "${1?}" - if [ "${__bp_imported:-missing}" == "defined" ]; then + if [[ "${bash_preexec_imported:-${__bp_imported:-missing}}" == "defined" ]]; then # We are using bash-preexec + __bp_trim_whitespace f "${1?}" if ! __check_preexec_conflict "${f}"; then preexec_functions+=("${f}") fi diff --git a/lib/preview.bash b/lib/preview.bash index 418839cd..46c1618a 100644 --- a/lib/preview.bash +++ b/lib/preview.bash @@ -1,19 +1,34 @@ -if [[ "${BASH_PREVIEW:-}" ]]; -then - unset BASH_PREVIEW #Prevent infinite looping - echo " +# shellcheck shell=bash +# +# Displays the prompt from each _Bash It_ theme. - Previewing Bash-it Themes +function _bash-it-preview() { + local BASH_IT_THEME BASH_IT_LOG_LEVEL + local themes IFS=$'\n' cur - " + if [[ $# -gt '0' ]]; then + themes=("$@") + else + themes=("${BASH_IT?}/themes"/*/*.theme.bash) + themes=("${themes[@]##*/}") + themes=("${themes[@]%.theme.bash}") + fi - THEMES="$BASH_IT/themes/*/*.theme.bash" - for theme in $THEMES - do - BASH_IT_THEME=${theme%.theme.bash} - BASH_IT_THEME=${BASH_IT_THEME##*/} - echo " - $BASH_IT_THEME" - echo "" | bash --init-file "${BASH_IT}/bash_it.sh" -i - done + if [[ ${COMP_CWORD:-} -gt '0' ]]; then + cur="${COMP_WORDS[COMP_CWORD]}" + read -d '' -ra COMPREPLY < <(compgen -W "all${IFS}${themes[*]}" -- "${cur}") + return + fi + printf '\n\n\t%s\n\n' "Previewing Bash-it Themes" + + # shellcheck disable=SC2034 + for BASH_IT_THEME in "${themes[@]}"; do + BASH_IT_LOG_LEVEL=0 + bash --init-file "${BASH_IT?}/bash_it.sh" -i <<< '_bash-it-flash-term "${#BASH_IT_THEME}" "${BASH_IT_THEME}"' + done +} + +if [[ -n "${BASH_PREVIEW:-}" ]]; then + _bash-it-preview "${BASH_PREVIEW}" "$@" + unset BASH_PREVIEW #Prevent infinite looping fi diff --git a/lib/search.bash b/lib/search.bash index 2da8f005..247e6294 100644 --- a/lib/search.bash +++ b/lib/search.bash @@ -70,7 +70,7 @@ function _bash-it-search() { return 0 ;; '-r' | '--refresh') - _bash-it-clean-component-cache + _bash-it-component-cache-clean ;; '-c' | '--no-color') BASH_IT_SEARCH_USE_COLOR=false @@ -266,9 +266,11 @@ function _bash-it-search-result() { shift local color_component color_enable color_disable color_off - local color_sep=':' line - + local match_color compatible_action suffix opposite_suffix + local color_sep=':' line match matched temp + local -i modified=0 enabled=0 len local -a matches=() + # Discard any empty arguments while IFS='' read -r line; do [[ -n "${line}" ]] && matches+=("$line") @@ -290,18 +292,13 @@ function _bash-it-search-result() { color_off='' fi - local match - local -i modified=0 - if [[ "${#matches[@]}" -gt 0 ]]; then printf "${color_component}%13s${color_sep}${color_off} " "${component}" for match in "${matches[@]}"; do - local -i enabled=0 + enabled=0 _bash-it-component-item-is-enabled "${component}" "${match}" && enabled=1 - local match_color compatible_action suffix opposite_suffix - if ((enabled)); then match_color="${color_enable}" suffix="${suffix_enable}" @@ -314,8 +311,8 @@ function _bash-it-search-result() { compatible_action="enable" fi - local matched="${match}${suffix}" - local -i len="${#matched}" + matched="${match}${suffix}" + len="${#matched}" printf '%b' "${match_color}${matched}" # print current state if [[ "${action}" == "${compatible_action}" ]]; then @@ -327,7 +324,7 @@ function _bash-it-search-result() { modified=1 # shellcheck disable=SC2034 # no idea if `$result` is ever used result=$("${action_func}" "${match}") - local temp="color_${compatible_action}" + temp="color_${compatible_action}" match_color="${!temp}" _bash-it-rewind "${len}" printf '%b' "${match_color}${match}${opposite_suffix}" @@ -336,7 +333,7 @@ function _bash-it-search-result() { printf '%b' "${color_off} " done - ((modified)) && _bash-it-clean-component-cache "${component}" + ((modified)) && _bash-it-component-cache-clean "${component}" printf "\n" fi } @@ -350,7 +347,7 @@ function _bash-it-flash-term() { local -i len="${1:-0}" # redundant local term="${2:-}" # as currently implemented, `$match` has already been printed to screen the first time - local delay=0.1 + local delay=0.2 local color [[ "${#term}" -gt 0 ]] && len="${#term}" diff --git a/lib/utilities.bash b/lib/utilities.bash index 63734a0f..6d5fd5d4 100644 --- a/lib/utilities.bash +++ b/lib/utilities.bash @@ -62,13 +62,13 @@ function _bash-it-array-dedup() { # Outputs a full path of the grep found on the filesystem function _bash-it-grep() { - : "${BASH_IT_GREP:=$(type -p egrep || type -p grep)}" - printf "%s" "${BASH_IT_GREP:-'/usr/bin/grep'}" + : "${BASH_IT_GREP:=$(type -P egrep || type -P grep)}" + printf "%s" "${BASH_IT_GREP:-/usr/bin/grep}" } # Runs `grep` with extended regular expressions function _bash-it-egrep() { - : "${BASH_IT_GREP:=$(type -p egrep || type -p grep)}" + : "${BASH_IT_GREP:=$(type -P egrep || type -P grep)}" "${BASH_IT_GREP:-/usr/bin/grep}" -E "$@" } @@ -91,7 +91,7 @@ function _bash-it-component-help() { function _bash-it-component-cache-file() { local _component_to_cache _file_path _result="${2:-${FUNCNAME[0]//-/_}}" _bash-it-component-pluralize "${1?${FUNCNAME[0]}: component name required}" _component_to_cache - _file_path="${XDG_CACHE_HOME:-${BASH_IT?}/tmp/cache}${XDG_CACHE_HOME:+/bash_it}/${_component_to_cache?}" + _file_path="${XDG_CACHE_HOME:-${HOME?}/.cache}/bash/${_component_to_cache?}" [[ -f "${_file_path}" ]] || mkdir -p "${_file_path%/*}" printf -v "${_result?}" '%s' "${_file_path}" } @@ -121,19 +121,17 @@ function _bash-it-component-pluralize() { printf -v "${_result?}" '%s' "${_component_to_plural}" } -function _bash-it-clean-component-cache() { - local component="$1" +function _bash-it-component-cache-clean() { + local component="${1:-}" local cache - local -a BASH_IT_COMPONENTS=(aliases plugins completions) + local -a components=('aliases' 'plugins' 'completions') if [[ -z "${component}" ]]; then - for component in "${BASH_IT_COMPONENTS[@]}"; do - _bash-it-clean-component-cache "${component}" + for component in "${components[@]}"; do + _bash-it-component-cache-clean "${component}" done else _bash-it-component-cache-file "${component}" cache - if [[ -f "${cache}" ]]; then - rm -f "${cache}" - fi + : >| "${cache:?}" fi } @@ -170,18 +168,22 @@ function _bash-it-component-list-disabled() { function _bash-it-component-item-is-enabled() { local component_type item_name each_file - if [[ -f "${1}" ]]; then + if [[ -f "${1?}" ]]; then item_name="$(_bash-it-get-component-name-from-path "${1}")" component_type="$(_bash-it-get-component-type-from-path "${1}")" else - component_type="${1}" item_name="${2}" + component_type="${1}" item_name="${2?}" fi for each_file in "${BASH_IT}/enabled"/*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}${item_name}.${component_type}"*."bash" \ "${BASH_IT}/${component_type}"*/"enabled/${item_name}.${component_type}"*."bash" \ "${BASH_IT}/${component_type}"*/"enabled"/*"${BASH_IT_LOAD_PRIORITY_SEPARATOR?}${item_name}.${component_type}"*."bash"; do - [[ -f "${each_file}" ]] && return + if [[ -f "${each_file}" ]]; then + return 0 + fi done + + return 1 } # Checks if a given item is disabled for a particular component/file-type. diff --git a/plugins/available/alias-completion.plugin.bash b/plugins/available/alias-completion.plugin.bash index eb368d93..d23779f7 100644 --- a/plugins/available/alias-completion.plugin.bash +++ b/plugins/available/alias-completion.plugin.bash @@ -1,105 +1,5 @@ # shellcheck shell=bash -# Load after the other completions to understand what needs to be completed -# BASH_IT_LOAD_PRIORITY: 365 +# stub for renamed file -cite about-plugin -about-plugin 'Automatic completion of aliases' - -# References: -# http://superuser.com/a/437508/119764 -# http://stackoverflow.com/a/1793178/1228454 - -# This needs to be a plugin so it gets executed after the completions and the aliases have been defined. -# Bash-it loads its components in the order -# 1) Aliases -# 2) Completions -# 3) Plugins -# 4) Custom scripts - -# Automatically add completion for all aliases to commands having completion functions -function alias_completion { - local namespace="alias_completion" - local tmp_file completion_loader alias_name alias_tokens line completions - local alias_arg_words new_completion compl_func compl_wrapper - - # parse function based completion definitions, where capture group 2 => function and 3 => trigger - local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' - # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments - local alias_regex="alias( -- | )([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" - - # create array of function completion triggers, keeping multi-word triggers together - eval "completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))" - ((${#completions[@]} == 0)) && return 0 - - # create temporary file for wrapper functions and completions - tmp_file="$(mktemp -t "${namespace}-${RANDOM}XXXXXX")" || return 1 - - completion_loader="$(complete -p -D 2> /dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')" - - # read in " '' ''" lines from defined aliases - # some aliases do have backslashes that needs to be interpreted - # shellcheck disable=SC2162 - while read line; do - eval "alias_tokens=($line)" 2> /dev/null || continue # some alias arg patterns cause an eval parse error - # shellcheck disable=SC2154 # see `eval` above - alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }" - - # skip aliases to pipes, boolean control structures and other command lists - # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters) - eval "alias_arg_words=($alias_args)" 2> /dev/null || continue - # avoid expanding wildcards - read -a alias_arg_words <<< "$alias_args" - - # skip alias if there is no completion function triggered by the aliased command - if ! _bash-it-array-contains-element "$alias_cmd" "${completions[@]}"; then - if [[ -n "$completion_loader" ]]; then - # force loading of completions for the aliased command - eval "$completion_loader $alias_cmd" - # 124 means completion loader was successful - [[ $? -eq 124 ]] || continue - completions+=("$alias_cmd") - else - continue - fi - 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}" - echo "function $compl_wrapper { - local compl_word=\$2 - local prec_word=\$3 - # check if prec_word is the alias itself. if so, replace it - # with the last word in the unaliased form, i.e., - # alias_cmd + ' ' + alias_args. - if [[ \$COMP_LINE == \"\$prec_word \$compl_word\" ]]; then - prec_word='$alias_cmd $alias_args' - prec_word=\${prec_word#* } - fi - (( COMP_CWORD += ${#alias_arg_words[@]} )) - COMP_WORDS=($alias_cmd $alias_args \${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 - fi - - # replace completion trigger by alias - if [[ -n $new_completion ]]; then - new_completion="${new_completion% *} $alias_name" - echo "$new_completion" >> "$tmp_file" - fi - done < <(alias -p | sed -Ene "s/$alias_regex/\2 '\3' '\4'/p") - # shellcheck source=/dev/null - source "$tmp_file" && command rm -f "$tmp_file" -} - -alias_completion +_enable-completion aliases && _disable-plugin alias-completion +source "${BASH_IT?}/completion/available/aliases.completion.bash" diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash index dc18167c..b38d7f9d 100644 --- a/plugins/available/battery.plugin.bash +++ b/plugins/available/battery.plugin.bash @@ -2,8 +2,10 @@ about-plugin 'display info about your battery charge level' function ac_adapter_connected() { + local batteries if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT)" | grep 'state' | grep -q 'charging\|fully-charged' + IFS=$'\n' read -d '' -ra batteries < <(upower -e | grep -i BAT) + upower -i "${batteries[0]:-}" | grep 'state' | grep -q 'charging\|fully-charged' elif _command_exists acpi; then acpi -a | grep -q "on-line" elif _command_exists pmset; then @@ -16,8 +18,10 @@ function ac_adapter_connected() { } function ac_adapter_disconnected() { + local batteries if _command_exists upower; then - upower -i "$(upower -e | grep -i BAT)" | grep 'state' | grep -q 'discharging' + IFS=$'\n' read -d '' -ra batteries < <(upower -e | grep -i BAT) + upower -i "${batteries[0]:-}" | grep 'state' | grep -q 'discharging' elif _command_exists acpi; then acpi -a | grep -q "off-line" elif _command_exists pmset; then @@ -33,16 +37,17 @@ function battery_percentage() { about 'displays battery charge as a percentage of full (100%)' group 'battery' - local command_output="no" + local command_output batteries if _command_exists upower; then - command_output=$(upower --show-info "$(upower --enumerate | grep -i BAT)" | grep percentage | grep -o "[0-9]\+" | head -1) + IFS=$'\n' read -d '' -ra batteries < <(upower -e | grep -i BAT) + command_output="$(upower --show-info "${batteries[0]:-}" | grep percentage | grep -o '[0-9]\+' | head -1)" elif _command_exists acpi; then command_output=$(acpi -b | awk -F, '/,/{gsub(/ /, "", $0); gsub(/%/,"", $0); print $2}') elif _command_exists pmset; then - command_output=$(pmset -g ps | sed -n 's/.*[[:blank:]]+*\(.*%\).*/\1/p' | grep -o "[0-9]\+" | head -1) + command_output=$(pmset -g ps | sed -n 's/.*[[:blank:]]+*\(.*%\).*/\1/p' | grep -o '[0-9]\+' | head -1) elif _command_exists ioreg; then - command_output=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%05.2f"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}' | grep -o "[0-9]\+" | head -1) + command_output=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%05.2f"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}' | grep -o '[0-9]\+' | head -1) elif _command_exists WMIC; then command_output=$(WMIC PATH Win32_Battery Get EstimatedChargeRemaining /Format:List | grep -o '[0-9]\+' | head -1) else diff --git a/plugins/available/blesh.plugin.bash b/plugins/available/blesh.plugin.bash index 7b1ce74e..6acd19ff 100644 --- a/plugins/available/blesh.plugin.bash +++ b/plugins/available/blesh.plugin.bash @@ -10,7 +10,7 @@ fi _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" + source "$_bash_it_ble_path" --attach=prompt 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/cmd-returned-notify.plugin.bash b/plugins/available/cmd-returned-notify.plugin.bash index d9be5e4e..88c07722 100644 --- a/plugins/available/cmd-returned-notify.plugin.bash +++ b/plugins/available/cmd-returned-notify.plugin.bash @@ -2,15 +2,15 @@ cite about-plugin about-plugin 'Alert (BEL) when process ends after a threshold of seconds' -precmd_return_notification() { - export LAST_COMMAND_DURATION=$(($(date +%s) - ${LAST_COMMAND_TIME:=$(date +%s)})) - [[ ${LAST_COMMAND_DURATION} -gt ${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5} ]] && echo -e "\a" - export LAST_COMMAND_TIME= +function precmd_return_notification() { + local command_start="${COMMAND_DURATION_START_SECONDS:=0}" + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i command_duration="$((${current_time%.*} - ${command_start%.*}))" + if [[ "${command_duration}" -gt "${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5}" ]]; then + printf '\a' + fi + return 0 } -preexec_return_notification() { - [[ -z "${LAST_COMMAND_TIME}" ]] && LAST_COMMAND_TIME=$(date +%s) -} - -precmd_functions+=(precmd_return_notification) -preexec_functions+=(preexec_return_notification) +safe_append_prompt_command 'precmd_return_notification' +safe_append_preexec '_command_duration_pre_exec' diff --git a/plugins/available/dirs.plugin.bash b/plugins/available/dirs.plugin.bash index f61680ca..34468fa0 100644 --- a/plugins/available/dirs.plugin.bash +++ b/plugins/available/dirs.plugin.bash @@ -59,7 +59,7 @@ function dirs-help() { # Add bookmarking functionality # Usage: -: "${BASH_IT_DIRS_BKS:=${XDG_STATE_HOME:-~/.local/state}/bash_it/dirs}" +: "${BASH_IT_DIRS_BKS:=${XDG_STATE_HOME:-${HOME}/.local/state}/bash_it/dirs}" if [[ -f "${BASH_IT_DIRS_BKS?}" ]]; then # shellcheck disable=SC1090 source "${BASH_IT_DIRS_BKS?}" diff --git a/plugins/available/history-eternal.plugin.bash b/plugins/available/history-eternal.plugin.bash index a18283d3..829868df 100644 --- a/plugins/available/history-eternal.plugin.bash +++ b/plugins/available/history-eternal.plugin.bash @@ -1,20 +1,22 @@ # shellcheck shell=bash about-plugin 'eternal bash history' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 +if [[ ${BASH_VERSINFO[0]} -lt 4 ]] || [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 3 ]]; then + _log_warning "Bash version 4.3 introduced the 'unlimited' history size capability." + return 1 +fi # Modify history sizes before changing location to avoid unintentionally # truncating the history file early. # "Numeric values less than zero result in every command being saved on the history list (there is no limit)" -export HISTSIZE=-1 +readonly HISTSIZE=-1 2> /dev/null || true # "Non-numeric values and numeric values less than zero inhibit truncation" -export HISTFILESIZE='unlimited' +readonly HISTFILESIZE='unlimited' 2> /dev/null || true # Use a custom history file location so history is not truncated # if the environment ever loses this "eternal" configuration. HISTDIR="${XDG_STATE_HOME:-${HOME?}/.local/state}/bash" [[ -d ${HISTDIR?} ]] || mkdir -p "${HISTDIR?}" -export HISTFILE="${HISTDIR?}/history" +readonly HISTFILE="${HISTDIR?}/history" 2> /dev/null || true diff --git a/plugins/available/history-search.plugin.bash b/plugins/available/history-search.plugin.bash index 341ce2af..96941993 100644 --- a/plugins/available/history-search.plugin.bash +++ b/plugins/available/history-search.plugin.bash @@ -1,9 +1,6 @@ # shellcheck shell=bash about-plugin 'search history using the prefix already entered' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 - # enter a few characters and press UpArrow/DownArrow # to search backwards/forwards through the history if [[ ${SHELLOPTS} =~ (vi|emacs) ]]; then diff --git a/plugins/available/history-substring-search.plugin.bash b/plugins/available/history-substring-search.plugin.bash index 586ceb50..dde32720 100644 --- a/plugins/available/history-substring-search.plugin.bash +++ b/plugins/available/history-substring-search.plugin.bash @@ -1,9 +1,6 @@ # shellcheck shell=bash about-plugin 'search history using the substring already entered' -# Load after the history plugin -# BASH_IT_LOAD_PRIORITY: 375 - # enter a few characters and press UpArrow/DownArrow # to search backwards/forwards through the history if [[ ${SHELLOPTS} =~ (vi|emacs) ]]; then diff --git a/plugins/available/history.plugin.bash b/plugins/available/history.plugin.bash index be253e4a..d9e930c3 100644 --- a/plugins/available/history.plugin.bash +++ b/plugins/available/history.plugin.bash @@ -5,14 +5,13 @@ about-plugin 'improve history handling with sane defaults' # variable when the shell exits, rather than overwriting the file. shopt -s histappend -# erase duplicates; alternative option: export HISTCONTROL=ignoredups -export HISTCONTROL=${HISTCONTROL:-ignorespace:erasedups} +# 'ignorespace': don't save command lines which begin with a space to history +# 'erasedups' (alternative 'ignoredups'): don't save duplicates to history +# 'autoshare': automatically share history between multiple running shells +: "${HISTCONTROL:=ignorespace:erasedups:autoshare}" # resize history to 100x the default (500) -export HISTSIZE=${HISTSIZE:-50000} - -# Flush history to disk after each command. -export PROMPT_COMMAND="history -a;${PROMPT_COMMAND}" +: "${HISTSIZE:=50000}" function top-history() { about 'print the name and count of the most commonly run tools' diff --git a/profiles/default.bash_it b/profiles/default.bash_it index 5e4f4631..9a55f6c7 100644 --- a/profiles/default.bash_it +++ b/profiles/default.bash_it @@ -1,10 +1,10 @@ # This is the default profile of Bash-it # plugins -plugins alias-completion plugins base # completion +completion aliases completion bash-it completion system diff --git a/test/bash_it/bash_it.bats b/test/bash_it/bash_it.bats index 13c84238..ef3cdbab 100644 --- a/test/bash_it/bash_it.bats +++ b/test/bash_it/bash_it.bats @@ -1,19 +1,11 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper - -function local_setup { - setup_test_fixture +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" +function local_setup_file() { # Copy the test fixture to the Bash-it folder - if command -v rsync &> /dev/null - then - rsync -a "$BASH_IT/test/fixtures/bash_it/" "$BASH_IT/" - else - find "$BASH_IT/test/fixtures/bash_it" \ - -mindepth 1 -maxdepth 1 \ - -exec cp -r {} "$BASH_IT/" \; - fi + cp -fRP "${BASH_IT?}/test/fixtures/bash_it"/* "${BASH_IT?}/" || true + # don't load any libraries as the tests here test the *whole* kit } @test "bash-it: verify that the test fixture is available" { diff --git a/test/plugins/alias-completion.plugin.bats b/test/completion/aliases.completion.bats similarity index 62% rename from test/plugins/alias-completion.plugin.bats rename to test/completion/aliases.completion.bats index 20d13cf2..83ae947a 100644 --- a/test/plugins/alias-completion.plugin.bats +++ b/test/completion/aliases.completion.bats @@ -1,27 +1,30 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../completion/available/capistrano.completion +function local_setup_file() { + setup_libs "helpers" + # Load something, anything... + load ../../completion/available/capistrano.completion +} @test "alias-completion: See that aliases with double quotes and brackets do not break the plugin" { alias gtest="git log --graph --pretty=format:'%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset' --abbrev-commit --date=relative" - load ../../plugins/available/alias-completion.plugin + run load "${BASH_IT?}/completion/available/aliases.completion.bash" assert_success } @test "alias-completion: See that aliases with single quotes and brackets do not break the plugin" { alias gtest='git log --graph --pretty=format:"%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset" --abbrev-commit --date=relative' - load ../../plugins/available/alias-completion.plugin + run load "${BASH_IT?}/completion/available/aliases.completion.bash" assert_success } @test "alias-completion: See that having aliased rm command does not output unnecessary output" { alias rm='rm -v' - load ../../plugins/available/alias-completion.plugin + run load "${BASH_IT?}/completion/available/aliases.completion.bash" refute_output } diff --git a/test/completion/bash-it.completion.bats b/test/completion/bash-it.completion.bats index f2336185..29d1dc94 100755 --- a/test/completion/bash-it.completion.bats +++ b/test/completion/bash-it.completion.bats @@ -1,17 +1,16 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../../lib/utilities -load ../../lib/helpers -load ../../completion/available/bash-it.completion +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup { - setup_test_fixture +function local_setup_file() { + setup_libs "helpers" + load "${BASH_IT?}/completion/available/bash-it.completion.bash" } @test "completion bash-it: ensure that the _bash-it function is available" { - type -a _bash-it &> /dev/null + run type -t _bash-it assert_success + assert_output "function" } function __check_completion () { @@ -81,32 +80,32 @@ function __check_completion () { @test "completion bash-it: show options" { run __check_completion 'bash-it ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bash-ti - show options" { run __check_completion 'bash-ti ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: shit - show options" { run __check_completion 'shit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bashit - show options" { run __check_completion 'bashit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: batshit - show options" { run __check_completion 'batshit ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: bash_it - show options" { run __check_completion 'bash_it ' - assert_line -n 0 "disable enable help migrate reload restart profile doctor search show update version" + assert_line -n 0 "disable enable help migrate reload restart preview profile doctor search show update version" } @test "completion bash-it: profile - show options" { diff --git a/test/fixtures/bash_it/profiles/test-bad-component.bash_it b/test/fixtures/bash_it/profiles/test-bad-component.bash_it index 8640265c..068c4b63 100644 --- a/test/fixtures/bash_it/profiles/test-bad-component.bash_it +++ b/test/fixtures/bash_it/profiles/test-bad-component.bash_it @@ -1,8 +1,8 @@ # plugins -plugins alias-completion plugins base # completion +completion aliases completion bash-it completion system diff --git a/test/fixtures/bash_it/profiles/test-bad-type.bash_it b/test/fixtures/bash_it/profiles/test-bad-type.bash_it index ed2d2373..102c52ea 100644 --- a/test/fixtures/bash_it/profiles/test-bad-type.bash_it +++ b/test/fixtures/bash_it/profiles/test-bad-type.bash_it @@ -1,10 +1,10 @@ # plugins -plugins alias-completion plugins base # Bad type -pluugins alias-completion +compleetion aliases # completion +completion aliases completion bash-it completion system diff --git a/test/install/install.bats b/test/install/install.bats index 262bf4f0..c9e1794c 100644 --- a/test/install/install.bats +++ b/test/install/install.bats @@ -1,19 +1,22 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -# 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 +function local_setup() { + export HOME="$BATS_TEST_TMPDIR" +} -function local_setup { - setup_test_fixture +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 } @test "install: verify that the install script exists" { @@ -25,11 +28,11 @@ function local_setup { ./install.sh --silent - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_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/250---base.plugin.bash" - assert_link_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_exist "$BASH_IT/enabled/325---system.completion.bash" } @@ -37,16 +40,16 @@ function local_setup { @test "install: verify that a backup file is created" { cd "$BASH_IT" - touch "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - echo "test file content" > "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - local md5_orig=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + touch "$HOME/$BASH_IT_CONFIG_FILE" + echo "test file content" > "$HOME/$BASH_IT_CONFIG_FILE" + local md5_orig=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') ./install.sh --silent - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" + assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE" + assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE.bak" - local md5_bak=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') + local md5_bak=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') assert_equal "$md5_orig" "$md5_bak" } @@ -70,15 +73,15 @@ function local_setup { @test "install: verify that the template is appended" { cd "$BASH_IT" - touch "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - echo "test file content" > "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" + touch "$HOME/$BASH_IT_CONFIG_FILE" + echo "test file content" > "$HOME/$BASH_IT_CONFIG_FILE" ./install.sh --silent --append-to-config - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" + assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE" + assert_file_exist "$HOME/$BASH_IT_CONFIG_FILE.bak" - run cat $BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE + run cat "$HOME/$BASH_IT_CONFIG_FILE" assert_line "test file content" assert_line "source \"\$BASH_IT\"/bash_it.sh" diff --git a/test/install/uninstall.bats b/test/install/uninstall.bats index 16bb7f7b..ab71a775 100644 --- a/test/install/uninstall.bats +++ b/test/install/uninstall.bats @@ -1,19 +1,22 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -# 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 +function local_setup() { + export HOME="$BATS_TEST_TMPDIR" +} -function local_setup { - setup_test_fixture +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 } @test "uninstall: verify that the uninstall script exists" { @@ -23,19 +26,18 @@ function local_setup { @test "uninstall: run the uninstall script with an existing backup file" { cd "$BASH_IT" - echo "test file content for backup" > "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" - echo "test file content for original file" > "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - local md5_bak=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') - - ./uninstall.sh + echo "test file content for backup" > "$HOME/$BASH_IT_CONFIG_FILE.bak" + echo "test file content for original file" > "$HOME/$BASH_IT_CONFIG_FILE" + local md5_bak=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE.bak" | awk '{print $1}') + run ./uninstall.sh assert_success - assert_file_not_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.uninstall" - assert_file_not_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" - assert_file_exist "$BASH_IT_TEST_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" - local md5_conf=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + local md5_conf=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') assert_equal "$md5_bak" "$md5_conf" } @@ -43,18 +45,17 @@ function local_setup { @test "uninstall: run the uninstall script without an existing backup file" { cd "$BASH_IT" - echo "test file content for original file" > "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" - local md5_orig=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') - - ./uninstall.sh + echo "test file content for original file" > "$HOME/$BASH_IT_CONFIG_FILE" + local md5_orig=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE" | awk '{print $1}') + run ./uninstall.sh assert_success - assert_file_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.uninstall" - assert_file_not_exist "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.bak" - assert_file_not_exist "$BASH_IT_TEST_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" - local md5_uninstall=$(md5sum "$BASH_IT_TEST_HOME/$BASH_IT_CONFIG_FILE.uninstall" | awk '{print $1}') + local md5_uninstall=$(md5sum "$HOME/$BASH_IT_CONFIG_FILE.uninstall" | awk '{print $1}') assert_equal "$md5_orig" "$md5_uninstall" } diff --git a/test/lib/composure.bats b/test/lib/composure.bats index 8198936c..01bfd967 100644 --- a/test/lib/composure.bats +++ b/test/lib/composure.bats @@ -1,6 +1,11 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" + +function local_setup_file() { + true + # don't load any libraries as the tests here test the *whole* kit +} @test "lib composure: _composure_keywords()" { run _composure_keywords diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats old mode 100755 new mode 100644 index bd339d04..38a917fe --- a/test/lib/helpers.bats +++ b/test/lib/helpers.bats @@ -1,21 +1,15 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs -load ../../plugins/available/base.plugin -load ../../lib/colors +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup { - setup_test_fixture +function local_setup_file() { + setup_libs "colors" + load "${BASH_IT?}/plugins/available/base.plugin.bash" +} +function local_setup() { # Copy the test fixture to the Bash-it folder - if command -v rsync &> /dev/null; then - rsync -a "$BASH_IT/test/fixtures/bash_it/" "$BASH_IT/" - else - find "$BASH_IT/test/fixtures/bash_it" \ - -mindepth 1 -maxdepth 1 \ - -exec cp -r {} "$BASH_IT/" \; - fi + cp -RP "$BASH_IT/test/fixtures/bash_it"/* "$BASH_IT/" } # TODO Create global __is_enabled function @@ -296,7 +290,7 @@ function local_setup { assert_link_exist "$BASH_IT/enabled/150---general.aliases.bash" assert_link_exist "$BASH_IT/enabled/250---base.plugin.bash" - assert_link_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_exist "$BASH_IT/enabled/325---system.completion.bash" } @@ -356,7 +350,7 @@ function local_setup { run _bash-it-profile-load "test" assert_link_not_exist "$BASH_IT/enabled/150---general.aliases.bash" assert_link_not_exist "$BASH_IT/enabled/250---base.plugin.bash" - assert_link_not_exist "$BASH_IT/enabled/365---alias-completion.plugin.bash" + assert_link_not_exist "$BASH_IT/enabled/800---aliases.completion.bash" assert_link_not_exist "$BASH_IT/enabled/350---bash-it.completion.bash" assert_link_not_exist "$BASH_IT/enabled/325---system.completion.bash" } @@ -384,7 +378,7 @@ function local_setup { @test "helpers: profile load corrupted profile file: bad subdirectory" { run _bash-it-profile-load "test-bad-type" - assert_line -n 1 -p "Bad line(#5) in profile, aborting load..." + assert_line -n 1 -p "Bad line(#4) in profile, aborting load..." } @test "helpers: profile rm sanity" { diff --git a/test/lib/log.bats b/test/lib/log.bats index bd118999..7d868fd6 100644 --- a/test/lib/log.bats +++ b/test/lib/log.bats @@ -1,11 +1,10 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../../lib/colors +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../lib/log -load ../../lib/helpers -load ../../plugins/available/base.plugin +function local_setup_file() { + setup_libs "log" +} @test "lib log: basic debug logging with BASH_IT_LOG_LEVEL_ALL" { BASH_IT_LOG_LEVEL=$BASH_IT_LOG_LEVEL_ALL diff --git a/test/lib/preexec.bats b/test/lib/preexec.bats index d85f952c..10dc666d 100644 --- a/test/lib/preexec.bats +++ b/test/lib/preexec.bats @@ -111,7 +111,7 @@ function local_setup { @test "lib preexec: __check_precmd_conflict()" { test_precmd_function_name="test" - load ../test_helper_libs + setup_libs "preexec" run __check_precmd_conflict "$test_precmd_function_name" assert_failure @@ -124,7 +124,7 @@ function local_setup { @test "lib preexec: __check_preexec_conflict()" { test_preexec_function_name="test" - load ../test_helper_libs + setup_libs "preexec" run __check_preexec_conflict "$test_preexec_function_name" assert_failure @@ -137,7 +137,7 @@ function local_setup { @test "lib preexec: safe_append_prompt_command()" { test_precmd_function_name="test" - load ../test_helper_libs + setup_libs "preexec" export precmd_functions=() assert_equal "${precmd_functions[*]}" "" @@ -151,7 +151,7 @@ function local_setup { @test "lib preexec: safe_append_preexec()" { test_preexec_function_name="test" - load ../test_helper_libs + setup_libs "preexec" export preexec_functions=() assert_equal "${preexec_functions[*]}" "" diff --git a/test/lib/search.bats b/test/lib/search.bats old mode 100755 new mode 100644 index 057951a0..e28922f4 --- a/test/lib/search.bats +++ b/test/lib/search.bats @@ -1,28 +1,14 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../plugins/available/base.plugin -load ../../aliases/available/git.aliases -load ../../plugins/available/ruby.plugin -load ../../plugins/available/rails.plugin -load ../../completion/available/bundler.completion -load ../../completion/available/gem.completion -load ../../completion/available/rake.completion - -load ../../lib/helpers - -function local_setup { - setup_test_fixture - - export OLD_PATH="$PATH" - export PATH="/usr/bin:/bin:/usr/sbin" +function local_setup_file() { + setup_libs "search" } -function local_teardown { - export PATH="$OLD_PATH" - unset OLD_PATH +function local_setup() { + # shellcheck disable=SC2034 + BASH_IT_SEARCH_USE_COLOR=false } @test "search: plugin base" { diff --git a/test/lib/utilities.bats b/test/lib/utilities.bats index a0968fce..78913870 100644 --- a/test/lib/utilities.bats +++ b/test/lib/utilities.bats @@ -1,10 +1,9 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup { - setup_test_fixture +function local_setup_file() { + setup_libs "helpers" } @test "_bash-it-component-item-is-enabled() - for a disabled item" { diff --git a/test/plugins/base.plugin.bats b/test/plugins/base.plugin.bats old mode 100755 new mode 100644 index 3d60986b..6022451a --- a/test/plugins/base.plugin.bats +++ b/test/plugins/base.plugin.bats @@ -1,14 +1,13 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs -load ../../plugins/available/base.plugin +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" + +function local_setup_file() { + setup_libs "helpers" + load "${BASH_IT?}/plugins/available/base.plugin.bash" +} @test 'plugins base: ips()' { - if [[ $CI ]]; then - skip 'ifconfig probably requires sudo on TravisCI' - fi - declare -r localhost='127.0.0.1' run ips assert_success @@ -23,7 +22,7 @@ load ../../plugins/available/base.plugin } @test 'plugins base: pickfrom()' { - stub_file="${BASH_IT_ROOT}/stub_file" + stub_file="${BATS_TEST_TMPDIR}/stub_file" printf "l1\nl2\nl3" > $stub_file run pickfrom $stub_file assert_success @@ -31,28 +30,30 @@ load ../../plugins/available/base.plugin } @test 'plugins base: mkcd()' { - cd "${BASH_IT_ROOT}" + cd "${BATS_TEST_TMPDIR}" declare -r dir_name="-dir_with_dash" # Make sure that the directory does not exist prior to the test - rm -rf "${BASH_IT_ROOT}/${dir_name}" + rm -rf "${BATS_TEST_TMPDIR}/${dir_name}" + + run mkcd "${dir_name}" + assert_success + assert_dir_exist "${BATS_TEST_TMPDIR}/${dir_name}" mkcd "${dir_name}" - assert_success - assert_dir_exist "${BASH_IT_ROOT}/${dir_name}" - assert_equal "${PWD}" "${BASH_IT_ROOT//\/\///}/${dir_name}" + assert_equal "${PWD}" "${BATS_TEST_TMPDIR//\/\///}/${dir_name}" } @test 'plugins base: lsgrep()' { - for i in 1 2 3; do mkdir -p "${BASH_IT_TEST_DIR}/${i}"; done - cd $BASH_IT_TEST_DIR + for i in 1 2 3; do mkdir -p "${BASH_IT}/${i}"; done + cd $BASH_IT run lsgrep 2 assert_success assert_equal $output 2 } @test 'plugins base: buf()' { - declare -r file="${BASH_IT_ROOT}/file" + declare -r file="${BATS_TEST_TMPDIR}/file" touch $file # Take one timestamp before running the `buf` function diff --git a/test/plugins/battery.plugin.bats b/test/plugins/battery.plugin.bats index eac6d021..49199ef2 100644 --- a/test/plugins/battery.plugin.bats +++ b/test/plugins/battery.plugin.bats @@ -1,9 +1,11 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../plugins/available/battery.plugin +function local_setup_file() { + setup_libs "helpers" + load "${BASH_IT?}/plugins/available/battery.plugin.bash" +} # Sets up the `_command_exists` function so that it only responds `true` if called with # the name of the function that was passed in as an argument to `setup_command_exists`. @@ -193,11 +195,24 @@ function setup_acpi { # Creates a `upower` function that simulates output like the real `upower` command. # The passed in parameter is used for the remaining battery percentage. function setup_upower { - percent="$1" + percent="$1" + BAT0="/org/freedesktop/UPower/devices/battery_BAT$RANDOM" - function upower { - printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" - } + function upower { + case $1 in + '-e'|'--enumerate') + printf '%s\n' "$BAT0" "/org/freedesktop/UPower/devices/mouse_hid_${RANDOM}_battery" + ;; + '-i'|'--show-info') + if [[ $2 == "$BAT0" ]] + then + printf "voltage: 12.191 V\n time to full: 57.3 minutes\n percentage: %s\n capacity: 84.6964" "${percent}" + else + false + fi + ;; + esac + } } @test 'plugins battery: battery-percentage with upower, 100%' { diff --git a/test/plugins/cmd-returned-notify.plugin.bats b/test/plugins/cmd-returned-notify.plugin.bats old mode 100755 new mode 100644 index 6f3cf25a..04edad95 --- a/test/plugins/cmd-returned-notify.plugin.bats +++ b/test/plugins/cmd-returned-notify.plugin.bats @@ -1,46 +1,41 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../plugins/available/cmd-returned-notify.plugin +function local_setup_file() { + setup_libs "command_duration" + load "${BASH_IT?}/plugins/available/cmd-returned-notify.plugin.bash" +} @test "plugins cmd-returned-notify: notify after elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 - export LAST_COMMAND_TIME=$(date +%s) - sleep 1 - run precmd_return_notification - assert_success - assert_output $'\a' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'\a' } @test "plugins cmd-returned-notify: do not notify before elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 - export LAST_COMMAND_TIME=$(date +%s) - sleep 1 - run precmd_return_notification - assert_success - assert_output $'' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'' } -@test "plugins cmd-returned-notify: preexec no output" { - export LAST_COMMAND_TIME= - run preexec_return_notification - assert_success - assert_output "" +@test "lib command_duration: preexec no output" { + export COMMAND_DURATION_START_SECONDS= + run _command_duration_pre_exec + assert_success + assert_output "" } - -@test "plugins cmd-returned-notify: preexec no output env set" { - export LAST_COMMAND_TIME=$(date +%s) - run preexec_return_notification - assert_failure - assert_output "" -} - -@test "plugins cmd-returned-notify: preexec set LAST_COMMAND_TIME" { - export LAST_COMMAND_TIME= - assert_equal "${LAST_COMMAND_TIME}" "" - NOW=$(date +%s) - preexec_return_notification - assert_equal "${LAST_COMMAND_TIME}" "${NOW}" +@test "lib command_duration: preexec set COMMAND_DURATION_START_SECONDS" { + export COMMAND_DURATION_START_SECONDS= + assert_equal "${COMMAND_DURATION_START_SECONDS}" "" + NOW="${EPOCHREALTIME:-$SECONDS}" + _command_duration_pre_exec + # We need to make sure to account for nanoseconds... + assert_equal "${COMMAND_DURATION_START_SECONDS%.*}" "${NOW%.*}" } diff --git a/test/plugins/go.plugin.bats b/test/plugins/go.plugin.bats index 258e4254..ebb9cd88 100644 --- a/test/plugins/go.plugin.bats +++ b/test/plugins/go.plugin.bats @@ -1,11 +1,9 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup() -{ - setup_test_fixture +function local_setup_file() { + setup_libs "helpers" } function setup_go_path() diff --git a/test/plugins/ruby.plugin.bats b/test/plugins/ruby.plugin.bats old mode 100755 new mode 100644 index b80adde7..7bfc6455 --- a/test/plugins/ruby.plugin.bats +++ b/test/plugins/ruby.plugin.bats @@ -1,24 +1,15 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup { - setup_test_fixture - - _command_exists "ruby" && mkdir -p "$(ruby -e 'print Gem.user_dir')/bin" - - export OLD_PATH="$PATH" - export PATH="/usr/bin:/bin:/usr/sbin" -} - -function local_teardown { - export PATH="$OLD_PATH" - unset OLD_PATH +function local_setup_file() { + setup_libs "helpers" } @test "plugins ruby: remove_gem is defined" { - load ../../plugins/available/ruby.plugin + run load "${BASH_IT?}/plugins/available/ruby.plugin.bash" + assert_success + load "${BASH_IT?}/plugins/available/ruby.plugin.bash" run type remove_gem assert_line -n 1 "remove_gem () " @@ -31,7 +22,9 @@ function local_teardown { mkdir -p "$(ruby -e 'print Gem.user_dir')/bin" - load ../../plugins/available/ruby.plugin + run load "${BASH_IT?}/plugins/available/ruby.plugin.bash" + assert_success + load "${BASH_IT?}/plugins/available/ruby.plugin.bash" local last_path_entry="$(tail -1 <<<"${PATH//:/$'\n'}")" [[ "${last_path_entry}" == "$(ruby -e 'print Gem.user_dir')/bin" ]] diff --git a/test/plugins/xterm.plugin.bats b/test/plugins/xterm.plugin.bats index c175d854..4cb1ffda 100644 --- a/test/plugins/xterm.plugin.bats +++ b/test/plugins/xterm.plugin.bats @@ -1,21 +1,10 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -load ../../plugins/available/xterm.plugin - -function local_setup { - setup_test_fixture - - # Copy the test fixture to the Bash-it folder - if _command_exists rsync; then - rsync -a "$BASH_IT/test/fixtures/plugin/xterm/" "$BASH_IT/" - else - find "$BASH_IT/test/fixtures/plugin/xterm" \ - -mindepth 1 -maxdepth 1 \ - -exec cp -r {} "$BASH_IT/" \; - fi +function local_setup_file() { + setup_libs "helpers" + load "${BASH_IT?}/plugins/available/xterm.plugin.bash" } @test "plugins xterm: shorten command output" { diff --git a/test/run b/test/run index 14d83950..78467366 100755 --- a/test/run +++ b/test/run @@ -2,17 +2,23 @@ test_directory="$(cd "$(dirname "$0")" && pwd)" bats_executable="${test_directory}/../test_lib/bats-core/bin/bats" +# Locate ourselves for easy reference. +export MAIN_BASH_IT_DIR="${test_directory%/*}" +export MAIN_BASH_IT_GITDIR="${MAIN_BASH_IT_DIR}/.git" + +# Make sure BATS is available: git submodule init && git submodule update -if [[ -z "${BASH_IT}" ]]; then - BASH_IT="$(cd "${test_directory}" && dirname "${PWD}")" - export BASH_IT +# Warn user that tests run from the current git HEAD +if ! git diff --quiet; then + echo "${BASH_SOURCE##*/}: your worktree is dirty; uncommitted changes will *not* be tested!" fi -if [[ -z "$1" ]]; then +# Which tests do we run? +if [[ $# -eq '0' ]]; then test_dirs=("${test_directory}"/{bash_it,completion,install,lib,plugins,themes}) else - test_dirs=("$1") + test_dirs=("$@") fi # Make sure that the `parallel` command is installed, @@ -38,8 +44,8 @@ if command -v parallel &> /dev/null \ fi )" exec "$bats_executable" "${CI:+--tap}" --jobs "${test_jobs_effective}" \ - "${test_dirs[@]}" + --no-parallelize-within-files "${test_dirs[@]}" else # Run `bats` in single-threaded mode. - exec "$bats_executable" ${CI:+--tap} "${test_dirs[@]}" + exec "$bats_executable" "${CI:+--tap}" "${test_dirs[@]}" fi diff --git a/test/test_helper.bash b/test/test_helper.bash old mode 100755 new mode 100644 index 06660979..bffb59ed --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -1,105 +1,117 @@ -#!/usr/bin/env bats -load "${BASH_IT}/vendor/github.com/erichs/composure/composure.sh" +# shellcheck shell=bash -unset BASH_IT_THEME -unset GIT_HOSTING -unset NGINX_PATH -unset IRC_CLIENT -unset TODO -unset SCM_CHECK -unset BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE - -export TEST_MAIN_DIR="${BATS_TEST_DIRNAME}/.." -export TEST_DEPS_DIR="${TEST_DEPS_DIR-${TEST_MAIN_DIR}/../test_lib}" - -# be independent of git's system configuration -export GIT_CONFIG_NOSYSTEM - -load "${TEST_DEPS_DIR}/bats-support/load.bash" -load "${TEST_DEPS_DIR}/bats-assert/load.bash" -load "${TEST_DEPS_DIR}/bats-file/load.bash" - -# support 'plumbing' metadata -cite _about _param _example _group _author _version -cite about-alias about-plugin about-completion - -local_setup() { - true +function setup_file() { + common_setup_file } -local_teardown() { - true -} +function common_setup_file() { + # export *everything* to subshells, needed to support tests + set -a -# This function sets up a local test fixture, i.e. a completely -# fresh and isolated Bash-it directory. This is done to avoid -# messing with your own Bash-it source directory. -# If you need this, call it in your .bats file's `local_setup` function. -setup_test_fixture() { - mkdir -p "$BASH_IT" - lib_directory="$(cd "$(dirname "$0")" && pwd)" - local src_topdir="$lib_directory/../../../.." + # Locate ourselves for easy reference. + TEST_MAIN_DIR="${MAIN_BASH_IT_DIR:-${BATS_TEST_DIRNAME?}/../..}/test" + TEST_DEPS_DIR="${MAIN_BASH_IT_DIR:-${TEST_MAIN_DIR}/..}/test_lib" - if command -v rsync &> /dev/null; then - # Use rsync to copy Bash-it to the temp folder - rsync -qavrKL -d --delete-excluded --exclude=.git --exclude=helper.bash --exclude=enabled "$src_topdir" "$BASH_IT" - else - rm -rf "$BASH_IT" - mkdir -p "$BASH_IT" + # Load the BATS modules we use: + load "${TEST_DEPS_DIR}/bats-support/load.bash" + load "${TEST_DEPS_DIR}/bats-assert/load.bash" + load "${TEST_DEPS_DIR}/bats-file/load.bash" - find "$src_topdir" \ - -mindepth 1 -maxdepth 1 \ - -not -name .git \ - -exec cp -r {} "$BASH_IT" \; - fi - - rm -rf "$BASH_IT"/enabled - rm -rf "$BASH_IT"/aliases/enabled - rm -rf "$BASH_IT"/completion/enabled - rm -rf "$BASH_IT"/plugins/enabled - - mkdir -p "$BASH_IT"/enabled - mkdir -p "$BASH_IT"/aliases/enabled - mkdir -p "$BASH_IT"/completion/enabled - mkdir -p "$BASH_IT"/plugins/enabled - - # Some tests use the BASH_IT_TEST_HOME variable, e.g. install/uninstall - export BASH_IT_TEST_HOME="$TEST_TEMP_DIR" -} - -setup() { - # The `temp_make` function from "bats-file" requires the tralston/bats-file fork, - # since the original ztombol/bats-file's `temp_make` does not work on macOS. - TEST_TEMP_DIR="$(temp_make --prefix 'bash-it-test-')" - export TEST_TEMP_DIR - - export BASH_IT_TEST_DIR="${TEST_TEMP_DIR}/.bash_it" - - export BASH_IT_ROOT="${BASH_IT_TEST_DIR}/root" - export BASH_IT=$BASH_IT_TEST_DIR - - mkdir -p -- "${BASH_IT_ROOT}" + # shellcheck disable=SC2034 # Clear any inherited environment: + XDG_DUMMY="" BASH_IT_DUMMY="" # avoid possible invalid reference: + unset "${!XDG_@}" "${!BASH_IT@}" # unset all BASH_IT* and XDG_* variables + unset GIT_HOSTING NGINX_PATH IRC_CLIENT TODO SCM_CHECK # Some tools, e.g. `git` use configuration files from the $HOME directory, - # which interferes with our tests. The only way to keep `git` from doing this - # seems to set HOME explicitly to a separate location. + # which interferes with our tests. The only way to keep `git` from doing + # this seems to set HOME explicitly to a separate location. # Refer to https://git-scm.com/docs/git-config#FILES. - unset XDG_CONFIG_HOME - export HOME="${TEST_TEMP_DIR}" + readonly HOME="${BATS_SUITE_TMPDIR?}" mkdir -p "${HOME}" # For `git` tests to run well, user name and email need to be set. # Refer to https://git-scm.com/docs/git-commit#_commit_information. # This goes to the test-specific config, due to the $HOME overridden above. - git config --global user.name "John Doe" - git config --global user.email "johndoe@example.com" + git config --global user.name "Bash It BATS Runner" + git config --global user.email "bats@bash.it" + git config --global advice.detachedHead false + git config --global init.defaultBranch "master" + # Locate the temporary folder, avoid double-slash. + BASH_IT="${BATS_FILE_TMPDIR//\/\///}/.bash_it" + + # This sets up a local test fixture, i.e. a completely fresh and isolated Bash-it directory. This is done to avoid messing with your own Bash-it source directory. + git --git-dir="${MAIN_BASH_IT_GITDIR?}" worktree add -d "${BASH_IT}" + + load "${BASH_IT?}/vendor/github.com/erichs/composure/composure.sh" + # support 'plumbing' metadata + cite _about _param _example _group _author _version + cite about-alias about-plugin about-completion + + # Run any local test setup + local_setup_file + set +a # not needed, but symetiric! +} + +# Load standard _Bash It_ libraries +function setup_libs() { + local lib + # Use a loop to allow convenient short-circuiting for some test files + for lib in "log" "utilities" "helpers" "search" "preexec" "colors" "command_duration"; do + load "${BASH_IT?}/lib/${lib}.bash" || return + # shellcheck disable=SC2015 # short-circuit if we've reached the requested library + [[ "${lib}" == "${1:-}" ]] && return 0 || true + done + return 0 +} + +function local_setup_file() { + true +} + +function local_setup() { + true +} + +function local_teardown() { + true +} + +function clean_test_fixture() { + rm -rf "${BASH_IT_CONFIG?}/enabled" + rm -rf "${BASH_IT_CONFIG?}/aliases/enabled" + rm -rf "${BASH_IT_CONFIG?}/completion/enabled" + rm -rf "${BASH_IT_CONFIG?}/plugins/enabled" + + rm -rf "${BASH_IT_CONFIG?}/tmp/cache" + rm -rf "${BASH_IT_CONFIG?}/profiles"/test*.bash_it +} + +function setup_test_fixture() { + mkdir -p "${BASH_IT_CONFIG?}/enabled" + mkdir -p "${BASH_IT_CONFIG?}/aliases/enabled" + mkdir -p "${BASH_IT_CONFIG?}/completion/enabled" + mkdir -p "${BASH_IT_CONFIG?}/plugins/enabled" +} + +function setup() { + # be independent of git's system configuration + export GIT_CONFIG_NOSYSTEM + # Locate the temporary folder: + BASH_IT_CONFIG="${BASH_IT?}" #"${BATS_TEST_TMPDIR//\/\///}" + export XDG_CACHE_HOME="${BATS_TEST_TMPDIR?}" + + setup_test_fixture local_setup } -teardown() { +function teardown() { + unset GIT_CONFIG_NOSYSTEM local_teardown - - rm -rf "${BASH_IT_TEST_DIR}" - temp_del "${TEST_TEMP_DIR}" + clean_test_fixture +} + +function teardown_file() { + # This only serves to clean metadata from the real git repo. + git --git-dir="${MAIN_BASH_IT_GITDIR?}" worktree remove -f "${BASH_IT?}" } diff --git a/test/test_helper_libs.bash b/test/test_helper_libs.bash deleted file mode 100644 index fac2a9eb..00000000 --- a/test/test_helper_libs.bash +++ /dev/null @@ -1,8 +0,0 @@ -# shellcheck shell=bash - -load "${BASH_IT}/lib/log.bash" -load "${BASH_IT}/lib/utilities.bash" -load "${BASH_IT}/lib/helpers.bash" -load "${BASH_IT}/lib/search.bash" -load "${BASH_IT}/lib/preexec.bash" -load "${BASH_IT}/lib/colors.bash" diff --git a/test/themes/base.theme.bats b/test/themes/base.theme.bats index 63f25133..81b08a01 100644 --- a/test/themes/base.theme.bats +++ b/test/themes/base.theme.bats @@ -1,8 +1,11 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs -load ../../themes/base.theme +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" + +function local_setup_file() { + setup_libs "colors" #"theme" + load "${BASH_IT?}/themes/base.theme.bash" +} @test 'themes base: battery_percentage should not exist' { run type -a battery_percentage &> /dev/null @@ -10,7 +13,7 @@ load ../../themes/base.theme } @test 'themes base: battery_percentage should exist if battery plugin loaded' { - load ../../plugins/available/battery.plugin + load "${BASH_IT?}/plugins/available/battery.plugin.bash" run type -a battery_percentage &> /dev/null assert_success @@ -28,12 +31,12 @@ load ../../themes/base.theme @test 'themes base: battery_char should exist if battery plugin loaded' { unset -f battery_char - load ../../plugins/available/battery.plugin + load "${BASH_IT?}/plugins/available/battery.plugin.bash" run type -t battery_percentage assert_success assert_line "function" - load ../../themes/base.theme + load "${BASH_IT?}/themes/base.theme.bash" run type -t battery_char assert_success assert_line "function" @@ -51,13 +54,13 @@ load ../../themes/base.theme run battery_charge assert_success - assert_line -n 0 "" + assert_output "" } @test 'themes base: battery_charge should exist if battery plugin loaded' { unset -f battery_charge - load ../../plugins/available/battery.plugin - load ../../themes/base.theme + load "${BASH_IT?}/plugins/available/battery.plugin.bash" + load "${BASH_IT?}/themes/base.theme.bash" run type -a battery_charge &> /dev/null assert_success diff --git a/test/themes/base.theme.git.bats b/test/themes/base.theme.git.bats index ad2c5a8d..b2bc7c5a 100644 --- a/test/themes/base.theme.git.bats +++ b/test/themes/base.theme.git.bats @@ -1,9 +1,14 @@ -#!/usr/bin/env bats +# shellcheck shell=bats +# shellcheck disable=SC2034 +# shellcheck disable=SC2016 -load ../test_helper -load ../test_helper_libs -load ../../themes/githelpers.theme -load ../../themes/base.theme +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" + +function local_setup_file() { + setup_libs "colors" #"theme" + load "${BASH_IT?}/themes/base.theme.bash" + load "${BASH_IT?}/themes/githelpers.theme.bash" +} add_commit() { local file_name="general-${RANDOM}" diff --git a/test/themes/base.theme.svn.bats b/test/themes/base.theme.svn.bats index 789d85e5..360e8636 100644 --- a/test/themes/base.theme.svn.bats +++ b/test/themes/base.theme.svn.bats @@ -1,29 +1,10 @@ -#!/usr/bin/env bats +# shellcheck shell=bats -load ../test_helper -load ../test_helper_libs +load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" -function local_setup { - setup_test_fixture - - # Copy the test fixture to the Bash-it folder - if command -v rsync &> /dev/null - then - rsync -a "$BASH_IT/test/fixtures/bash_it/" "$BASH_IT/" - else - find "$BASH_IT/test/fixtures/bash_it" \ - -mindepth 1 -maxdepth 1 \ - -exec cp -r {} "$BASH_IT/" \; - fi - - export OLD_PATH="$PATH" - - load ../../themes/base.theme -} - -function local_teardown { - export PATH="$OLD_PATH" - unset OLD_PATH +function local_setup_file() { + setup_libs "colors" #"theme" + load "${BASH_IT?}/themes/base.theme.bash" } function setup_repo { diff --git a/themes/base.theme.bash b/themes/base.theme.bash index a7e99961..92a56e5e 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -1,16 +1,20 @@ # shellcheck shell=bash # shellcheck disable=SC2034 # Expected behavior for themes. +# Colors for listing files, using default color scheme. +# To customize color scheme by theme, check out https://geoff.greer.fm/lscolors/ +export CLICOLOR LSCOLORS LS_COLORS + CLOCK_CHAR_THEME_PROMPT_PREFIX='' CLOCK_CHAR_THEME_PROMPT_SUFFIX='' CLOCK_THEME_PROMPT_PREFIX='' CLOCK_THEME_PROMPT_SUFFIX='' -THEME_PROMPT_HOST='\H' +THEME_PROMPT_HOST='\h' SCM= -SCM_CHECK=${SCM_CHECK:=true} +: "${SCM_CHECK:=true}" SCM_THEME_PROMPT_DIRTY=' ✗' SCM_THEME_PROMPT_CLEAN=' ✓' @@ -30,15 +34,15 @@ SCM_THEME_CHAR_SUFFIX='' : "${THEME_CHECK_SUDO:=false}" : "${THEME_BATTERY_PERCENTAGE_CHECK:=true}" -SCM_GIT_SHOW_DETAILS=${SCM_GIT_SHOW_DETAILS:=true} -SCM_GIT_SHOW_REMOTE_INFO=${SCM_GIT_SHOW_REMOTE_INFO:=auto} -SCM_GIT_IGNORE_UNTRACKED=${SCM_GIT_IGNORE_UNTRACKED:=false} -SCM_GIT_SHOW_CURRENT_USER=${SCM_GIT_SHOW_CURRENT_USER:=false} -SCM_GIT_SHOW_MINIMAL_INFO=${SCM_GIT_SHOW_MINIMAL_INFO:=false} -SCM_GIT_SHOW_STASH_INFO=${SCM_GIT_SHOW_STASH_INFO:=true} -SCM_GIT_SHOW_COMMIT_COUNT=${SCM_GIT_SHOW_COMMIT_COUNT:=true} -SCM_GIT_USE_GITSTATUS=${SCM_GIT_USE_GITSTATUS:=false} -SCM_GIT_GITSTATUS_RAN=${SCM_GIT_GITSTATUS_RAN:=false} +: "${SCM_GIT_SHOW_DETAILS:=true}" +: "${SCM_GIT_SHOW_REMOTE_INFO:=auto}" +: "${SCM_GIT_IGNORE_UNTRACKED:=false}" +: "${SCM_GIT_SHOW_CURRENT_USER:=false}" +: "${SCM_GIT_SHOW_MINIMAL_INFO:=false}" +: "${SCM_GIT_SHOW_STASH_INFO:=true}" +: "${SCM_GIT_SHOW_COMMIT_COUNT:=true}" +: "${SCM_GIT_USE_GITSTATUS:=false}" +: "${SCM_GIT_GITSTATUS_RAN:=false}" SCM_GIT='git' SCM_GIT_CHAR='±' @@ -73,9 +77,9 @@ NVM_THEME_PROMPT_SUFFIX='|' RVM_THEME_PROMPT_PREFIX=' |' RVM_THEME_PROMPT_SUFFIX='|' -THEME_SHOW_RUBY_PROMPT=${THEME_SHOW_RUBY_PROMPT:=true} +: "${THEME_SHOW_RUBY_PROMPT:=true}" -THEME_SHOW_USER_HOST=${THEME_SHOW_USER_HOST:=false} +: "${THEME_SHOW_USER_HOST:=false}" USER_HOST_THEME_PROMPT_PREFIX='' USER_HOST_THEME_PROMPT_SUFFIX='' @@ -88,154 +92,160 @@ RBENV_THEME_PROMPT_SUFFIX='|' RBFU_THEME_PROMPT_PREFIX=' |' RBFU_THEME_PROMPT_SUFFIX='|' -: "${GIT_EXE:=$SCM_GIT}" -: "${P4_EXE:=$SCM_P4}" -: "${HG_EXE:=$SCM_HG}" -: "${SVN_EXE:=$SCM_SVN}" +: "${GIT_EXE:=${SCM_GIT?}}" +: "${HG_EXE:=${SCM_HG?}}" +: "${SVN_EXE:=${SCM_SVN?}}" +: "${P4_EXE:=${SCM_P4?}}" function _bash_it_appearance_scm_init() { - GIT_EXE="$(type -P $SCM_GIT || true)" - P4_EXE="$(type -P $SCM_P4 || true)" - HG_EXE="$(type -P $SCM_HG || true)" - SVN_EXE="$(type -P $SCM_SVN || true)" + GIT_EXE="$(type -P "${SCM_GIT:-git}" || true)" + HG_EXE="$(type -P "${SCM_HG:-hg}" || true)" + SVN_EXE="$(type -P "${SCM_SVN:-svn}" || true)" + P4_EXE="$(type -P "${SCM_P4:-p4}" || true)" # Check for broken SVN exe that is caused by some versions of Xcode. # See https://github.com/Bash-it/bash-it/issues/1612 for more details. - if [[ -x "$SVN_EXE" && -x "${SVN_EXE%/*}/xcrun" ]]; then - if ! "$SVN_EXE" --version > /dev/null 2>&1; then + if [[ -x "${SVN_EXE-}" && -x "${SVN_EXE%/svn}/xcrun" ]]; then + if ! "${SVN_EXE}" --version > /dev/null 2>&1; then # Unset the SVN exe variable so that SVN commands are avoided. SVN_EXE="" fi fi + return 0 } _bash_it_library_finalize_hook+=('_bash_it_appearance_scm_init') -function scm { - if [[ "$SCM_CHECK" = false ]]; then - SCM=$SCM_NONE - elif [[ -f .git/HEAD ]] && [[ -x "$GIT_EXE" ]]; then - SCM=$SCM_GIT - elif [[ -d .hg ]] && [[ -x "$HG_EXE" ]]; then - SCM=$SCM_HG - elif [[ -d .svn ]] && [[ -x "$SVN_EXE" ]]; then - SCM=$SCM_SVN - elif [[ -x "$GIT_EXE" ]] && [[ -n "$(git rev-parse --is-inside-work-tree 2> /dev/null)" ]]; then - SCM=$SCM_GIT - elif [[ -x "$HG_EXE" ]] && [[ -n "$(hg root 2> /dev/null)" ]]; then - SCM=$SCM_HG - elif [[ -x "$SVN_EXE" ]] && [[ -n "$(svn info --show-item wc-root 2> /dev/null)" ]]; then - SCM=$SCM_SVN - elif [[ -x "$P4_EXE" ]] && [[ -n "$(p4 set P4CLIENT 2> /dev/null)" ]]; then - SCM=$SCM_P4 +function scm() { + if [[ "${SCM_CHECK:-true}" == "false" ]]; then + SCM="${SCM_NONE-NONE}" + elif [[ -x "${GIT_EXE-}" ]] && _bash-it-find-in-ancestor '.git' > /dev/null; then + SCM="${SCM_GIT?}" + elif [[ -x "${HG_EXE-}" ]] && _bash-it-find-in-ancestor '.hg' > /dev/null; then + SCM="${SCM_HG?}" + elif [[ -x "${SVN_EXE-}" ]] && _bash-it-find-in-ancestor '.svn' > /dev/null; then + SCM="${SCM_SVN?}" + elif [[ -x "${P4_EXE-}" && -n "$(p4 set P4CLIENT 2> /dev/null)" ]]; then + SCM="${SCM_P4?}" else - SCM=$SCM_NONE + SCM="${SCM_NONE-NONE}" fi } -scm_prompt() { - local CHAR - CHAR="$(scm_char)" - local format=${SCM_PROMPT_FORMAT:-'[%s%s]'} +function scm_prompt() { + local format="${SCM_PROMPT_FORMAT-"[%s%s]"}" + local scm_char scm_prompt_info + scm_char="$(scm_char)" + scm_prompt_info="$(scm_prompt_info)" - if [[ "${CHAR}" != "$SCM_NONE_CHAR" ]]; then + if [[ "${scm_char}" != "${SCM_NONE_CHAR:-}" ]]; then # shellcheck disable=2059 - printf "$format\n" "$CHAR" "$(scm_prompt_info)" + printf "${format}" "${scm_char}" "${scm_prompt_info}" fi } -function scm_prompt_char { - if [[ -z $SCM ]]; then scm; fi - if [[ $SCM == "$SCM_GIT" ]]; then - SCM_CHAR=$SCM_GIT_CHAR - elif [[ $SCM == "$SCM_P4" ]]; then - SCM_CHAR=$SCM_P4_CHAR - elif [[ $SCM == "$SCM_HG" ]]; then - SCM_CHAR=$SCM_HG_CHAR - elif [[ $SCM == "$SCM_SVN" ]]; then - SCM_CHAR=$SCM_SVN_CHAR - else - SCM_CHAR=$SCM_NONE_CHAR +function scm_prompt_char() { + if [[ -z "${SCM:-}" ]]; then + scm fi + + case ${SCM?} in + "${SCM_GIT?}") + SCM_CHAR="${SCM_GIT_CHAR?}" + ;; + "${SCM_HG?}") + SCM_CHAR="${SCM_HG_CHAR?}" + ;; + "${SCM_SVN?}") + SCM_CHAR="${SCM_SVN_CHAR?}" + ;; + "${SCM_P4?}") + SCM_CHAR="${SCM_P4_CHAR?}" + ;; + *) + SCM_CHAR="${SCM_NONE_CHAR:-}" + ;; + esac } -function scm_prompt_vars { +function scm_prompt_vars() { scm scm_prompt_char SCM_DIRTY=0 SCM_STATE='' - [[ $SCM == "$SCM_GIT" ]] && git_prompt_vars && return - [[ $SCM == "$SCM_P4" ]] && p4_prompt_vars && return - [[ $SCM == "$SCM_HG" ]] && hg_prompt_vars && return - [[ $SCM == "$SCM_SVN" ]] && svn_prompt_vars && return + + local prompt_vars="${SCM}_prompt_vars" + _is_function "${prompt_vars}" && "${prompt_vars}" } -function scm_prompt_info { +function scm_prompt_info() { scm scm_prompt_char scm_prompt_info_common } -function scm_prompt_char_info { +function scm_prompt_char_info() { scm_prompt_char - echo -ne "${SCM_THEME_CHAR_PREFIX}${SCM_CHAR}${SCM_THEME_CHAR_SUFFIX}" + echo -ne "${SCM_THEME_CHAR_PREFIX-}${SCM_CHAR?}${SCM_THEME_CHAR_SUFFIX-}" scm_prompt_info_common } -function scm_prompt_info_common { +function scm_prompt_info_common() { + local prompt_info SCM_DIRTY=0 SCM_STATE='' - if [[ ${SCM} == "${SCM_GIT}" ]]; then - if [[ ${SCM_GIT_SHOW_MINIMAL_INFO} == true ]]; then - # user requests minimal git status information - git_prompt_minimal_info - else - # more detailed git status - git_prompt_info - fi - return - fi - - # TODO: consider adding minimal status information for hg and svn - { [[ ${SCM} == "${SCM_P4}" ]] && p4_prompt_info && return; } || true - { [[ ${SCM} == "${SCM_HG}" ]] && hg_prompt_info && return; } || true - { [[ ${SCM} == "${SCM_SVN}" ]] && svn_prompt_info && return; } || true + case ${SCM?} in + "${SCM_GIT?}") + if [[ ${SCM_GIT_SHOW_MINIMAL_INFO:-false} == "true" ]]; then + # user requests minimal git status information + prompt_info="${SCM}_prompt_minimal_info" + else + # more detailed git status + prompt_info="${SCM}_prompt_info" + fi + ;; + *) + # TODO: consider adding minimal status information for hg and svn + prompt_info="${SCM}_prompt_info" + ;; + esac + _is_function "${prompt_info}" && "${prompt_info}" } -function terraform_workspace_prompt { +function terraform_workspace_prompt() { if _command_exists terraform; then - if [ -d .terraform ]; then - echo -e "$(terraform workspace show 2> /dev/null)" + if [[ -d .terraform ]]; then + terraform workspace show 2> /dev/null fi fi } -function active_gcloud_account_prompt { +function active_gcloud_account_prompt() { if _command_exists gcloud; then - echo -e "$(gcloud config list account --format "value(core.account)" 2> /dev/null)" + gcloud config list account --format "value(core.account)" 2> /dev/null fi } -function git_prompt_minimal_info { - SCM_STATE=${SCM_THEME_PROMPT_CLEAN} +function git_prompt_minimal_info() { + SCM_STATE="${SCM_THEME_PROMPT_CLEAN?}" _git-hide-status && return - SCM_BRANCH="${SCM_THEME_BRANCH_PREFIX}\$(_git-friendly-ref)" + SCM_BRANCH="${SCM_THEME_BRANCH_PREFIX-}\$(_git-friendly-ref)" if [[ -n "$(_git-status | tail -n1)" ]]; then SCM_DIRTY=1 - SCM_STATE=${SCM_THEME_PROMPT_DIRTY} + SCM_STATE="${SCM_THEME_PROMPT_DIRTY?}" fi # Output the git prompt - SCM_PREFIX=${SCM_THEME_PROMPT_PREFIX} - SCM_SUFFIX=${SCM_THEME_PROMPT_SUFFIX} - echo -e "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}" + SCM_PREFIX="${SCM_THEME_PROMPT_PREFIX-}" + SCM_SUFFIX="${SCM_THEME_PROMPT_SUFFIX-}" + echo -ne "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}" } -function git_prompt_vars { - if ${SCM_GIT_USE_GITSTATUS} && _command_exists gitstatus_query && gitstatus_query && [[ "${VCS_STATUS_RESULT}" == "ok-sync" ]]; then +function git_prompt_vars() { + if [[ "${SCM_GIT_USE_GITSTATUS:-false}" != "false" ]] && _command_exists gitstatus_query && gitstatus_query && [[ "${VCS_STATUS_RESULT:-}" == "ok-sync" ]]; then # we can use faster gitstatus # use this variable in githelpers and below to choose gitstatus output SCM_GIT_GITSTATUS_RAN=true @@ -251,190 +261,174 @@ function git_prompt_vars { local detached_prefix if _git-tag &> /dev/null; then - detached_prefix=${SCM_THEME_TAG_PREFIX} + detached_prefix="${SCM_THEME_TAG_PREFIX}" else - detached_prefix=${SCM_THEME_DETACHED_PREFIX} + detached_prefix="${SCM_THEME_DETACHED_PREFIX}" fi SCM_BRANCH="${detached_prefix}\$(_git-friendly-ref)" fi - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - commits_behind=${VCS_STATUS_COMMITS_BEHIND} - commits_ahead=${VCS_STATUS_COMMITS_AHEAD} + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + commits_behind="${VCS_STATUS_COMMITS_BEHIND?}" + commits_ahead="${VCS_STATUS_COMMITS_AHEAD?}" else IFS=$'\t' read -r commits_behind commits_ahead <<< "$(_git-upstream-behind-ahead)" fi if [[ "${commits_ahead}" -gt 0 ]]; then SCM_BRANCH+="${SCM_GIT_AHEAD_BEHIND_PREFIX_CHAR}${SCM_GIT_AHEAD_CHAR}" - [[ "${SCM_GIT_SHOW_COMMIT_COUNT}" = "true" ]] && SCM_BRANCH+="${commits_ahead}" + [[ "${SCM_GIT_SHOW_COMMIT_COUNT}" == "true" ]] && SCM_BRANCH+="${commits_ahead}" fi if [[ "${commits_behind}" -gt 0 ]]; then SCM_BRANCH+="${SCM_GIT_AHEAD_BEHIND_PREFIX_CHAR}${SCM_GIT_BEHIND_CHAR}" - [[ "${SCM_GIT_SHOW_COMMIT_COUNT}" = "true" ]] && SCM_BRANCH+="${commits_behind}" + [[ "${SCM_GIT_SHOW_COMMIT_COUNT}" == "true" ]] && SCM_BRANCH+="${commits_behind}" fi - if [[ "${SCM_GIT_SHOW_STASH_INFO}" = "true" ]]; then + if [[ "${SCM_GIT_SHOW_STASH_INFO}" == "true" ]]; then local stash_count if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - stash_count=${VCS_STATUS_STASHES} + stash_count="${VCS_STATUS_STASHES?}" else stash_count="$(git stash list 2> /dev/null | wc -l | tr -d ' ')" fi [[ "${stash_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_STASH_CHAR_PREFIX}${stash_count}${SCM_GIT_STASH_CHAR_SUFFIX}" fi - SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} + SCM_STATE="${GIT_THEME_PROMPT_CLEAN:-${SCM_THEME_PROMPT_CLEAN:-}}" if ! _git-hide-status; then - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - untracked_count=${VCS_STATUS_NUM_UNTRACKED} - unstaged_count=${VCS_STATUS_NUM_UNSTAGED} - staged_count=${VCS_STATUS_NUM_STAGED} + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + untracked_count="${VCS_STATUS_NUM_UNTRACKED?}" + unstaged_count="${VCS_STATUS_NUM_UNSTAGED?}" + staged_count="${VCS_STATUS_NUM_STAGED?}" else - IFS=$'\t' read -r untracked_count unstaged_count staged_count <<< "$(_git-status-counts)" + IFS=$'\t' read -r untracked_count unstaged_count staged_count < <(_git-status-counts) fi if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then SCM_DIRTY=1 - if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then + if [[ "${SCM_GIT_SHOW_DETAILS}" == "true" ]]; then [[ "${staged_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_STAGED_CHAR}${staged_count}" && SCM_DIRTY=3 [[ "${unstaged_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_UNSTAGED_CHAR}${unstaged_count}" && SCM_DIRTY=2 [[ "${untracked_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_UNTRACKED_CHAR}${untracked_count}" && SCM_DIRTY=1 fi - SCM_STATE=${GIT_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY} + SCM_STATE="${GIT_THEME_PROMPT_DIRTY:-${SCM_THEME_PROMPT_DIRTY?}}" fi fi # no if for gitstatus here, user extraction is not supported by it [[ "${SCM_GIT_SHOW_CURRENT_USER}" == "true" ]] && SCM_BRANCH+="$(git_user_info)" - SCM_PREFIX=${GIT_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX} - SCM_SUFFIX=${GIT_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX} + SCM_PREFIX="${GIT_THEME_PROMPT_PREFIX:-${SCM_THEME_PROMPT_PREFIX-}}" + SCM_SUFFIX="${GIT_THEME_PROMPT_SUFFIX:-${SCM_THEME_PROMPT_SUFFIX-}}" - SCM_CHANGE=$(_git-short-sha 2> /dev/null || echo "") + SCM_CHANGE=$(_git-short-sha 2> /dev/null || true) } -function p4_prompt_vars { +function p4_prompt_vars() { + local opened_count non_default_changes default_count \ + add_file_count edit_file_count delete_file_count + IFS=$'\t' read -r \ opened_count non_default_changes default_count \ add_file_count edit_file_count delete_file_count \ - <<< "$(_p4-opened-counts)" + < <(_p4-opened-counts) if [[ "${opened_count}" -gt 0 ]]; then SCM_DIRTY=1 - SCM_STATE=${SCM_THEME_PROMPT_DIRTY} - [[ "${opened_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_OPENED_CHAR}${opened_count}" - [[ "${non_default_changes}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_CHANGES_CHAR}${non_default_changes}" - [[ "${default_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_DEFAULT_CHAR}${default_count}" + SCM_STATE="${SCM_THEME_PROMPT_DIRTY?}" + [[ "${opened_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_OPENED_CHAR?}${opened_count}" + [[ "${non_default_changes}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_CHANGES_CHAR?}${non_default_changes}" + [[ "${default_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_P4_DEFAULT_CHAR?}${default_count}" else SCM_DIRTY=0 - SCM_STATE=${SCM_THEME_PROMPT_DIRTY} + SCM_STATE="${SCM_THEME_PROMPT_CLEAN?}" fi - SCM_PREFIX=${P4_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX} - SCM_SUFFIX=${P4_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX} + SCM_PREFIX="${P4_THEME_PROMPT_PREFIX:-${SCM_THEME_PROMPT_PREFIX-}}" + SCM_SUFFIX="${P4_THEME_PROMPT_SUFFIX:-${SCM_THEME_PROMPT_SUFFIX-}}" } -function svn_prompt_vars { - if [[ -n $(svn status | head -c1 2> /dev/null) ]]; then +function svn_prompt_vars() { + if [[ -n "$(svn status | head -c1 2> /dev/null)" ]]; then SCM_DIRTY=1 - SCM_STATE=${SVN_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY} + SCM_STATE="${SVN_THEME_PROMPT_DIRTY:-${SCM_THEME_PROMPT_DIRTY?}}" else SCM_DIRTY=0 - SCM_STATE=${SVN_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} + SCM_STATE="${SVN_THEME_PROMPT_CLEAN:-${SCM_THEME_PROMPT_CLEAN?}}" fi - SCM_PREFIX=${SVN_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX} - SCM_SUFFIX=${SVN_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX} - SCM_BRANCH=$(svn info --show-item=url 2> /dev/null | awk -F/ '{ for (i=0; i<=NF; i++) { if ($i == "branches" || $i == "tags" ) { print $(i+1); break }; if ($i == "trunk") { print $i; break } } }') || return - SCM_CHANGE=$(svn info --show-item=revision 2> /dev/null) + SCM_PREFIX="${SVN_THEME_PROMPT_PREFIX:-${SCM_THEME_PROMPT_PREFIX-}}" + SCM_SUFFIX="${SVN_THEME_PROMPT_SUFFIX:-${SCM_THEME_PROMPT_SUFFIX-}}" + SCM_BRANCH="$(svn info --show-item=url 2> /dev/null | awk -F/ '{ for (i=0; i<=NF; i++) { if ($i == "branches" || $i == "tags" ) { print $(i+1); break }; if ($i == "trunk") { print $i; break } } }')" || return + SCM_CHANGE="$(svn info --show-item=revision 2> /dev/null)" } -# this functions returns absolute location of .hg directory if one exists -# It starts in the current directory and moves its way up until it hits /. -# If we get to / then no Mercurial repository was found. -# Example: -# - lets say we cd into ~/Projects/Foo/Bar -# - .hg is located in ~/Projects/Foo/.hg -# - get_hg_root starts at ~/Projects/Foo/Bar and sees that there is no .hg directory, so then it goes into ~/Projects/Foo -function get_hg_root { - local CURRENT_DIR="${PWD}" - - while [[ "${CURRENT_DIR:-/}" != "/" ]]; do - if [[ -d "$CURRENT_DIR/.hg" ]]; then - echo "$CURRENT_DIR/.hg" - return - fi - - CURRENT_DIR="${CURRENT_DIR%/*}" - done -} - -function hg_prompt_vars { +function hg_prompt_vars() { + local hg_root bookmark if [[ -n $(hg status 2> /dev/null) ]]; then SCM_DIRTY=1 - SCM_STATE=${HG_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY} + SCM_STATE="${HG_THEME_PROMPT_DIRTY:-${SCM_THEME_PROMPT_DIRTY?}}" else SCM_DIRTY=0 - SCM_STATE=${HG_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} + SCM_STATE="${HG_THEME_PROMPT_CLEAN:-${SCM_THEME_PROMPT_CLEAN?}}" fi - SCM_PREFIX=${HG_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX} - SCM_SUFFIX=${HG_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX} + SCM_PREFIX="${HG_THEME_PROMPT_PREFIX:-${SCM_THEME_PROMPT_PREFIX-}}" + SCM_SUFFIX="${HG_THEME_PROMPT_SUFFIX:-${SCM_THEME_PROMPT_SUFFIX-}}" - HG_ROOT=$(get_hg_root) + hg_root="$(_bash-it-find-in-ancestor ".hg")/.hg" - if [ -f "$HG_ROOT/branch" ]; then + if [[ -f "$hg_root/branch" ]]; then # Mercurial holds it's current branch in .hg/branch file - SCM_BRANCH=$(< "${HG_ROOT}/branch") - local bookmark=${HG_ROOT}/bookmarks.current - [[ -f ${bookmark} ]] && SCM_BRANCH+=:$(< "${bookmark}") + SCM_BRANCH=$(< "${hg_root}/branch") + bookmark="${hg_root}/bookmarks.current" + [[ -f "${bookmark}" ]] && SCM_BRANCH+=:$(< "${bookmark}") else SCM_BRANCH=$(hg summary 2> /dev/null | grep branch: | awk '{print $2}') fi - if [ -f "$HG_ROOT/dirstate" ]; then + if [[ -f "$hg_root/dirstate" ]]; then # Mercurial holds various information about the working directory in .hg/dirstate file. More on http://mercurial.selenic.com/wiki/DirState - SCM_CHANGE=$(hexdump -vn 10 -e '1/1 "%02x"' "$HG_ROOT/dirstate" | cut -c-12) + SCM_CHANGE=$(hexdump -vn 10 -e '1/1 "%02x"' "$hg_root/dirstate" | cut -c-12) else SCM_CHANGE=$(hg summary 2> /dev/null | grep parent: | awk '{print $2}') fi } -function nvm_version_prompt { +function nvm_version_prompt() { local node if _is_function nvm; then node=$(nvm current 2> /dev/null) [[ "${node}" == "system" ]] && return - echo -e "${NVM_THEME_PROMPT_PREFIX}${node}${NVM_THEME_PROMPT_SUFFIX}" + echo -ne "${NVM_THEME_PROMPT_PREFIX-}${node}${NVM_THEME_PROMPT_SUFFIX-}" fi } -function node_version_prompt { - echo -e "$(nvm_version_prompt)" +function node_version_prompt() { + nvm_version_prompt } -function rvm_version_prompt { - if which rvm &> /dev/null; then - rvm=$(rvm-prompt) || return - if [ -n "$rvm" ]; then - echo -e "$RVM_THEME_PROMPT_PREFIX$rvm$RVM_THEME_PROMPT_SUFFIX" +function rvm_version_prompt() { + if _command_exists rvm; then + rvm="$(rvm-prompt)" || return + if [[ -n "$rvm" ]]; then + echo -ne "${RVM_THEME_PROMPT_PREFIX-}${rvm}${RVM_THEME_PROMPT_SUFFIX-}" fi fi } -function rbenv_version_prompt { - if which rbenv &> /dev/null; then +function rbenv_version_prompt() { + if _command_exists rbenv; then rbenv=$(rbenv version-name) || return rbenv commands | grep -q gemset && gemset=$(rbenv gemset active 2> /dev/null) && rbenv="$rbenv@${gemset%% *}" - if [ "$rbenv" != "system" ]; then - echo -e "$RBENV_THEME_PROMPT_PREFIX$rbenv$RBENV_THEME_PROMPT_SUFFIX" + if [[ "$rbenv" != "system" ]]; then + echo -ne "${RBENV_THEME_PROMPT_PREFIX-}${rbenv}${RBENV_THEME_PROMPT_SUFFIX-}" fi fi } -function rbfu_version_prompt { - if [[ $RBFU_RUBY_VERSION ]]; then - echo -e "${RBFU_THEME_PROMPT_PREFIX}${RBFU_RUBY_VERSION}${RBFU_THEME_PROMPT_SUFFIX}" +function rbfu_version_prompt() { + if [[ -n "${RBFU_RUBY_VERSION:-}" ]]; then + echo -ne "${RBFU_THEME_PROMPT_PREFIX-}${RBFU_RUBY_VERSION}${RBFU_THEME_PROMPT_SUFFIX-}" fi } -function chruby_version_prompt { +function chruby_version_prompt() { if _is_function chruby; then if _is_function chruby_auto; then chruby_auto @@ -445,145 +439,147 @@ function chruby_version_prompt { if ! chruby | grep -q '\*'; then ruby_version="${ruby_version} (system)" fi - echo -e "${CHRUBY_THEME_PROMPT_PREFIX}${ruby_version}${CHRUBY_THEME_PROMPT_SUFFIX}" + echo -ne "${CHRUBY_THEME_PROMPT_PREFIX-}${ruby_version}${CHRUBY_THEME_PROMPT_SUFFIX-}" fi } -function ruby_version_prompt { - if [[ "${THEME_SHOW_RUBY_PROMPT}" = "true" ]]; then - echo -e "$(rbfu_version_prompt)$(rbenv_version_prompt)$(rvm_version_prompt)$(chruby_version_prompt)" +function ruby_version_prompt() { + if [[ "${THEME_SHOW_RUBY_PROMPT:-}" == "true" ]]; then + rbfu_version_prompt + rbenv_version_prompt + rvm_version_prompt + chruby_version_prompt fi } -function k8s_context_prompt { - echo -e "$(kubectl config current-context 2> /dev/null)" +function k8s_context_prompt() { + kubectl config current-context 2> /dev/null } -function k8s_namespace_prompt { - echo -e "$(kubectl config view --minify --output 'jsonpath={..namespace}' 2> /dev/null)" +function k8s_namespace_prompt() { + kubectl config view --minify --output 'jsonpath={..namespace}' 2> /dev/null } -function virtualenv_prompt { - if [[ -n "$VIRTUAL_ENV" ]]; then - virtualenv=$(basename "$VIRTUAL_ENV") - echo -e "$VIRTUALENV_THEME_PROMPT_PREFIX$virtualenv$VIRTUALENV_THEME_PROMPT_SUFFIX" +function virtualenv_prompt() { + local virtualenv + if [[ -n "${VIRTUAL_ENV:-}" ]]; then + virtualenv="${VIRTUAL_ENV##*/}" + echo -ne "${VIRTUALENV_THEME_PROMPT_PREFIX-}${virtualenv}${VIRTUALENV_THEME_PROMPT_SUFFIX-}" fi } -function condaenv_prompt { - if [[ $CONDA_DEFAULT_ENV ]]; then - echo -e "${CONDAENV_THEME_PROMPT_PREFIX}${CONDA_DEFAULT_ENV}${CONDAENV_THEME_PROMPT_SUFFIX}" +function condaenv_prompt() { + if [[ -n "${CONDA_DEFAULT_ENV:-}" ]]; then + echo -ne "${CONDAENV_THEME_PROMPT_PREFIX-}${CONDA_DEFAULT_ENV}${CONDAENV_THEME_PROMPT_SUFFIX-}" fi } -function py_interp_prompt { - py_version=$(python --version 2>&1 | awk 'NR==1{print "py-"$2;}') || return - echo -e "${PYTHON_THEME_PROMPT_PREFIX}${py_version}${PYTHON_THEME_PROMPT_SUFFIX}" +function py_interp_prompt() { + local py_version + py_version="$(python --version 2>&1 | awk 'NR==1{print "py-"$2;}')" || return + echo -ne "${PYTHON_THEME_PROMPT_PREFIX-}${py_version}${PYTHON_THEME_PROMPT_SUFFIX-}" } -function python_version_prompt { - echo -e "$(virtualenv_prompt)$(condaenv_prompt)$(py_interp_prompt)" +function python_version_prompt() { + virtualenv_prompt + condaenv_prompt + py_interp_prompt } -function git_user_info { +function git_user_info() { + local current_user # support two or more initials, set by 'git pair' plugin - SCM_CURRENT_USER=$(git config user.initials | sed 's% %+%') + current_user="$(git config user.initials | sed 's% %+%')" # if `user.initials` weren't set, attempt to extract initials from `user.name` - [[ -z "${SCM_CURRENT_USER}" ]] && SCM_CURRENT_USER=$(printf "%s" "$(for word in $(git config user.name | PERLIO=:utf8 perl -pe '$_=lc'); do printf "%s" "${word:0:1}"; done)") - [[ -n "${SCM_CURRENT_USER}" ]] && printf "%s" "$SCM_THEME_CURRENT_USER_PREFFIX$SCM_CURRENT_USER$SCM_THEME_CURRENT_USER_SUFFIX" + [[ -z "${current_user}" ]] && current_user=$(printf "%s" "$(for word in $(git config user.name | PERLIO=:utf8 perl -pe '$_=lc'); do printf "%s" "${word:0:1}"; done)") + [[ -n "${current_user}" ]] && printf "%s" "${SCM_THEME_CURRENT_USER_PREFFIX-}${current_user}${SCM_THEME_CURRENT_USER_SUFFIX-}" } -function clock_char { - CLOCK_CHAR=${THEME_CLOCK_CHAR:-"⌚"} - CLOCK_CHAR_COLOR=${THEME_CLOCK_CHAR_COLOR:-"$normal"} - SHOW_CLOCK_CHAR=${THEME_SHOW_CLOCK_CHAR:-"true"} +function clock_char() { + local clock_char clock_char_color show_clock_char + clock_char="${THEME_CLOCK_CHAR:-⌚}" + clock_char_color="${THEME_CLOCK_CHAR_COLOR:-${normal:-}}" + show_clock_char="${THEME_SHOW_CLOCK_CHAR:-"true"}" - if [[ "${SHOW_CLOCK_CHAR}" = "true" ]]; then - echo -e "${CLOCK_CHAR_COLOR}${CLOCK_CHAR_THEME_PROMPT_PREFIX}${CLOCK_CHAR}${CLOCK_CHAR_THEME_PROMPT_SUFFIX}" + if [[ "${show_clock_char}" == "true" ]]; then + echo -ne "${clock_char_color}${CLOCK_CHAR_THEME_PROMPT_PREFIX-}${clock_char}${CLOCK_CHAR_THEME_PROMPT_SUFFIX-}" fi } -function clock_prompt { - CLOCK_COLOR=${THEME_CLOCK_COLOR:-"$normal"} - CLOCK_FORMAT=${THEME_CLOCK_FORMAT:-"%H:%M:%S"} - [ -z "$THEME_SHOW_CLOCK" ] && THEME_SHOW_CLOCK=${THEME_CLOCK_CHECK:-"true"} - SHOW_CLOCK=$THEME_SHOW_CLOCK +function clock_prompt() { + local clock_color="${THEME_CLOCK_COLOR:-${normal?}}" + local clock_format="${THEME_CLOCK_FORMAT:-"%H:%M:%S"}" + local show_clock="${THEME_SHOW_CLOCK:-${THEME_CLOCK_CHECK:-true}}" + local clock_string="\D{${clock_format}}" - if [[ "${SHOW_CLOCK}" = "true" ]]; then - CLOCK_STRING=$(date +"${CLOCK_FORMAT}") - echo -e "${CLOCK_COLOR}${CLOCK_THEME_PROMPT_PREFIX}${CLOCK_STRING}${CLOCK_THEME_PROMPT_SUFFIX}" + if [[ "${show_clock}" == "true" ]]; then + echo -ne "${clock_color}${CLOCK_THEME_PROMPT_PREFIX-}${clock_string}${CLOCK_THEME_PROMPT_SUFFIX-}" fi } -function user_host_prompt { - if [[ "${THEME_SHOW_USER_HOST}" = "true" ]]; then - echo -e "${USER_HOST_THEME_PROMPT_PREFIX}\u@\h${USER_HOST_THEME_PROMPT_SUFFIX}" +function user_host_prompt() { + if [[ "${THEME_SHOW_USER_HOST:-false}" == "true" ]]; then + echo -ne "${USER_HOST_THEME_PROMPT_PREFIX-}\u@${THEME_PROMPT_HOST:-\h}${USER_HOST_THEME_PROMPT_SUFFIX-}" fi } # backwards-compatibility -function git_prompt_info { +function git_prompt_info() { _git-hide-status && return git_prompt_vars - echo -e "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}" + echo -ne "${SCM_PREFIX?}${SCM_BRANCH?}${SCM_STATE?}${SCM_SUFFIX?}" } function p4_prompt_info() { p4_prompt_vars - echo -e "${SCM_PREFIX}${SCM_BRANCH}:${SCM_CHANGE}${SCM_STATE}${SCM_SUFFIX}" + echo -ne "${SCM_PREFIX?}${SCM_BRANCH?}:${SCM_CHANGE?}${SCM_STATE?}${SCM_SUFFIX?}" } -function svn_prompt_info { +function svn_prompt_info() { svn_prompt_vars - echo -e "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}" + echo -ne "${SCM_PREFIX?}${SCM_BRANCH?}${SCM_STATE?}${SCM_SUFFIX?}" } function hg_prompt_info() { hg_prompt_vars - echo -e "${SCM_PREFIX}${SCM_BRANCH}:${SCM_CHANGE#*:}${SCM_STATE}${SCM_SUFFIX}" + echo -ne "${SCM_PREFIX?}${SCM_BRANCH?}:${SCM_CHANGE#*:}${SCM_STATE?}${SCM_SUFFIX?}" } -function scm_char { +function scm_char() { scm_prompt_char - echo -e "${SCM_THEME_CHAR_PREFIX}${SCM_CHAR}${SCM_THEME_CHAR_SUFFIX}" + echo -ne "${SCM_THEME_CHAR_PREFIX?}${SCM_CHAR?}${SCM_THEME_CHAR_SUFFIX?}" } -function prompt_char { +function prompt_char() { scm_char } -function battery_char { - if [[ "${THEME_BATTERY_PERCENTAGE_CHECK}" = true ]]; then - echo -e "${bold_red:-}$(battery_percentage)%" +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)%" + else + false fi } if ! _command_exists battery_charge; then # if user has installed battery plugin, skip this... function battery_charge() { - # no op - echo -n + : # no op } fi -# The battery_char function depends on the presence of the battery_percentage function. -# If battery_percentage is not defined, then define battery_char as a no-op. -if ! _command_exists battery_percentage; then - function battery_char() { - # no op - echo -n - } -fi - -function aws_profile { - if [[ $AWS_DEFAULT_PROFILE ]]; then - echo -e "${AWS_DEFAULT_PROFILE}" +function aws_profile() { + if [[ -n "${AWS_DEFAULT_PROFILE:-}" ]]; then + echo -ne "${AWS_DEFAULT_PROFILE}" else - echo -e "default" + echo -ne "default" fi } function _save-and-reload-history() { - local autosave=${1:-0} - [[ $autosave -eq 1 ]] && history -a && history -c && history -r + local autosave="${1:-${HISTORY_AUTOSAVE:-0}}" + [[ ${autosave} -eq 1 ]] && local HISTCONTROL="${HISTCONTROL:-}${HISTCONTROL:+:}autoshare" + _bash-it-history-auto-save && _bash-it-history-auto-load } diff --git a/themes/command_duration.theme.bash b/themes/command_duration.theme.bash deleted file mode 100644 index cf91785c..00000000 --- a/themes/command_duration.theme.bash +++ /dev/null @@ -1,69 +0,0 @@ -# shellcheck shell=bash - -if [ -z "$BASH_IT_COMMAND_DURATION" ] || [ "$BASH_IT_COMMAND_DURATION" != true ]; then - _command_duration() { - echo -n - } - return -fi - -# Define tmp dir and file -COMMAND_DURATION_TMPDIR="${TMPDIR:-/tmp}" -COMMAND_DURATION_FILE="${COMMAND_DURATION_FILE:-$COMMAND_DURATION_TMPDIR/bashit_theme_execution_$BASHPID}" - -COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-'  '} -COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-'1'} - -trap _command_duration_delete_temp_file EXIT HUP INT TERM - -_command_duration_delete_temp_file() { - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - rm -f "$COMMAND_DURATION_FILE" - fi -} - -_command_duration_pre_exec() { - date +%s.%1N > "$COMMAND_DURATION_FILE" -} - -_command_duration() { - local command_duration command_start current_time - local minutes seconds deciseconds - local command_start_sseconds current_time_seconds command_start_deciseconds current_time_deciseconds - current_time=$(date +%s.%1N) - - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - command_start=$(< "$COMMAND_DURATION_FILE") - command_start_sseconds=${command_start%.*} - current_time_seconds=${current_time%.*} - - command_start_deciseconds=$((10#${command_start#*.})) - current_time_deciseconds=$((10#${current_time#*.})) - - # seconds - command_duration=$((current_time_seconds - command_start_sseconds)) - - if ((current_time_deciseconds >= command_start_deciseconds)); then - deciseconds=$(((current_time_deciseconds - command_start_deciseconds))) - else - ((command_duration -= 1)) - deciseconds=$((10 - ((command_start_deciseconds - current_time_deciseconds)))) - fi - command rm "$COMMAND_DURATION_FILE" - else - command_duration=0 - fi - - if ((command_duration > 0)); then - minutes=$((command_duration / 60)) - seconds=$((command_duration % 60)) - fi - - if ((minutes > 0)); then - printf "%s%s%dm %ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$minutes" "$seconds" - elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then - printf "%s%s%d.%01ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$seconds" "$deciseconds" - fi -} - -preexec_functions+=(_command_duration_pre_exec) diff --git a/themes/githelpers.theme.bash b/themes/githelpers.theme.bash index ba089392..719effec 100644 --- a/themes/githelpers.theme.bash +++ b/themes/githelpers.theme.bash @@ -1,99 +1,106 @@ -#!/usr/bin/env bash +# shellcheck shell=bash -function _git-symbolic-ref { - git symbolic-ref -q HEAD 2> /dev/null +function _git-symbolic-ref() { + git symbolic-ref -q HEAD 2> /dev/null } # When on a branch, this is often the same as _git-commit-description, # but this can be different when two branches are pointing to the # same commit. _git-branch is used to explicitly choose the checked-out # branch. -function _git-branch { - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - test -n "${VCS_STATUS_LOCAL_BRANCH}" && echo "${VCS_STATUS_LOCAL_BRANCH}" || return 1 - else - git symbolic-ref -q --short HEAD 2> /dev/null || return 1 - fi +function _git-branch() { + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + if [[ -n "${VCS_STATUS_LOCAL_BRANCH:-}" ]]; then + echo "${VCS_STATUS_LOCAL_BRANCH}" + else + return 1 + fi + else + git symbolic-ref -q --short HEAD 2> /dev/null || return 1 + fi } -function _git-tag { - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - test -n "${VCS_STATUS_TAG}" && echo "${VCS_STATUS_TAG}" - else - git describe --tags --exact-match 2> /dev/null - fi +function _git-tag() { + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + if [[ -n "${VCS_STATUS_TAG:-}" ]]; then + echo "${VCS_STATUS_TAG}" + fi + else + git describe --tags --exact-match 2> /dev/null + fi } -function _git-commit-description { - git describe --contains --all 2> /dev/null +function _git-commit-description() { + git describe --contains --all 2> /dev/null } -function _git-short-sha { - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - echo ${VCS_STATUS_COMMIT:0:7} - else - git rev-parse --short HEAD - fi +function _git-short-sha() { + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + echo "${VCS_STATUS_COMMIT:0:7}" + else + git rev-parse --short HEAD + fi } # Try the checked-out branch first to avoid collision with branches pointing to the same ref. -function _git-friendly-ref { - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - _git-branch || _git-tag || _git-short-sha # there is no tag based describe output in gitstatus - else - _git-branch || _git-tag || _git-commit-description || _git-short-sha - fi +function _git-friendly-ref() { + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + _git-branch || _git-tag || _git-short-sha # there is no tag based describe output in gitstatus + else + _git-branch || _git-tag || _git-commit-description || _git-short-sha + fi } -function _git-num-remotes { - git remote | wc -l +function _git-num-remotes() { + git remote | wc -l } -function _git-upstream { - local ref - ref="$(_git-symbolic-ref)" || return 1 - git for-each-ref --format="%(upstream:short)" "${ref}" +function _git-upstream() { + local ref + ref="$(_git-symbolic-ref)" || return 1 + git for-each-ref --format="%(upstream:short)" "${ref}" } -function _git-upstream-remote { - local upstream - upstream="$(_git-upstream)" || return 1 +function _git-upstream-remote() { + local upstream branch + upstream="$(_git-upstream)" || return 1 - local branch - branch="$(_git-upstream-branch)" || return 1 - echo "${upstream%"/${branch}"}" + branch="$(_git-upstream-branch)" || return 1 + echo "${upstream%"/${branch}"}" } -function _git-upstream-branch { - local ref - ref="$(_git-symbolic-ref)" || return 1 +function _git-upstream-branch() { + local ref + ref="$(_git-symbolic-ref)" || return 1 - # git versions < 2.13.0 do not support "strip" for upstream format - # regex replacement gives the wrong result for any remotes with slashes in the name, - # so only use when the strip format fails. - git for-each-ref --format="%(upstream:strip=3)" "${ref}" 2> /dev/null || git for-each-ref --format="%(upstream)" "${ref}" | sed -e "s/.*\/.*\/.*\///" + # git versions < 2.13.0 do not support "strip" for upstream format + # regex replacement gives the wrong result for any remotes with slashes in the name, + # so only use when the strip format fails. + git for-each-ref --format="%(upstream:strip=3)" "${ref}" 2> /dev/null || git for-each-ref --format="%(upstream)" "${ref}" | sed -e "s/.*\/.*\/.*\///" } -function _git-upstream-behind-ahead { - git rev-list --left-right --count "$(_git-upstream)...HEAD" 2> /dev/null +function _git-upstream-behind-ahead() { + git rev-list --left-right --count "$(_git-upstream)...HEAD" 2> /dev/null } -function _git-upstream-branch-gone { - [[ "$(git status -s -b | sed -e 's/.* //')" == "[gone]" ]] +function _git-upstream-branch-gone() { + [[ "$(git status -s -b | sed -e 's/.* //')" == "[gone]" ]] } -function _git-hide-status { - [[ "$(git config --get bash-it.hide-status)" == "1" ]] +function _git-hide-status() { + [[ "$(git config --get bash-it.hide-status)" == "1" ]] } -function _git-status { - local git_status_flags= - [[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && git_status_flags='-uno' || true - git status --porcelain ${git_status_flags} 2> /dev/null +function _git-status() { + local git_status_flags= + if [[ "${SCM_GIT_IGNORE_UNTRACKED:-}" == "true" ]]; then + git_status_flags='-uno' + fi + git status --porcelain "${git_status_flags:---}" 2> /dev/null } -function _git-status-counts { - _git-status | awk ' +function _git-status-counts() { + _git-status | awk ' BEGIN { untracked=0; unstaged=0; @@ -116,85 +123,51 @@ function _git-status-counts { }' } -function _git-remote-info { +function _git-remote-info() { + local same_branch_name="" branch_prefix + # prompt handling only, reimplement because patching the routine below gets ugly + if [[ "${SCM_GIT_GITSTATUS_RAN:-}" == "true" ]]; then + [[ "${VCS_STATUS_REMOTE_NAME?}" == "" ]] && return + [[ "${VCS_STATUS_LOCAL_BRANCH?}" == "${VCS_STATUS_REMOTE_BRANCH?}" ]] && same_branch_name=true + # no multiple remote support in gitstatusd + if [[ "${SCM_GIT_SHOW_REMOTE_INFO:-}" == "true" || "${SCM_GIT_SHOW_REMOTE_INFO:-}" == "auto" ]]; then + if [[ ${same_branch_name:-} != "true" ]]; then + remote_info="${VCS_STATUS_REMOTE_NAME?}/${VCS_STATUS_REMOTE_BRANCH?}" + else + remote_info="${VCS_STATUS_REMOTE_NAME?}" + fi + elif [[ ${same_branch_name:-} != "true" ]]; then + remote_info="${VCS_STATUS_REMOTE_BRANCH?}" + fi + if [[ -n "${remote_info:-}" ]]; then + # no support for gone remote branches in gitstatusd + branch_prefix="${SCM_THEME_BRANCH_TRACK_PREFIX:-}" + echo "${branch_prefix}${remote_info:-}" + fi + else + [[ "$(_git-upstream)" == "" ]] && return - # prompt handling only, reimplement because patching the routine below gets ugly - if [[ "${SCM_GIT_GITSTATUS_RAN}" == "true" ]]; then - [[ "${VCS_STATUS_REMOTE_NAME}" == "" ]] && return - [[ "${VCS_STATUS_LOCAL_BRANCH}" == "${VCS_STATUS_REMOTE_BRANCH}" ]] && local same_branch_name=true - local same_branch_name= - [[ "${VCS_STATUS_LOCAL_BRANCH}" == "${VCS_STATUS_REMOTE_BRANCH}" ]] && same_branch_name=true - # no multiple remote support in gitstatusd - if [[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "true" || "${SCM_GIT_SHOW_REMOTE_INFO}" = "auto" ]]; then - if [[ "${same_branch_name}" != "true" ]]; then - remote_info="${VCS_STATUS_REMOTE_NAME}/${VCS_STATUS_REMOTE_BRANCH}" - else - remote_info="${VCS_STATUS_REMOTE_NAME}" - fi - elif [[ ${same_branch_name} != "true" ]]; then - remote_info="${VCS_STATUS_REMOTE_BRANCH}" - fi - if [[ -n "${remote_info}" ]];then - # no support for gone remote branches in gitstatusd - local branch_prefix="${SCM_THEME_BRANCH_TRACK_PREFIX}" - echo "${branch_prefix}${remote_info}" - fi - else - [[ "$(_git-upstream)" == "" ]] && return - - [[ "$(_git-branch)" == "$(_git-upstream-branch)" ]] && local same_branch_name=true - local same_branch_name= - [[ "$(_git-branch)" == "$(_git-upstream-branch)" ]] && same_branch_name=true - if [[ ("${SCM_GIT_SHOW_REMOTE_INFO}" = "auto" && "$(_git-num-remotes)" -ge 2) || - "${SCM_GIT_SHOW_REMOTE_INFO}" = "true" ]]; then - if [[ "${same_branch_name}" != "true" ]]; then - remote_info="\$(_git-upstream)" - else - remote_info="$(_git-upstream-remote)" - fi - elif [[ ${same_branch_name} != "true" ]]; then - remote_info="\$(_git-upstream-branch)" - fi - if [[ -n "${remote_info}" ]];then - local branch_prefix - if _git-upstream-branch-gone; then - branch_prefix="${SCM_THEME_BRANCH_GONE_PREFIX}" - else - branch_prefix="${SCM_THEME_BRANCH_TRACK_PREFIX}" - fi - echo "${branch_prefix}${remote_info}" - fi - fi -} - -# Unused by bash-it, present for API compatibility -function git_status_summary { - awk ' - BEGIN { - untracked=0; - unstaged=0; - staged=0; - } - { - if (!after_first && $0 ~ /^##.+/) { - print $0 - seen_header = 1 - } else if ($0 ~ /^\?\? .+/) { - untracked += 1 - } else { - if ($0 ~ /^.[^ ] .+/) { - unstaged += 1 - } - if ($0 ~ /^[^ ]. .+/) { - staged += 1 - } - } - after_first = 1 - } - END { - if (!seen_header) { - print - } - print untracked "\t" unstaged "\t" staged - }' + [[ "$(_git-branch)" == "$(_git-upstream-branch)" ]] && same_branch_name=true + if [[ ("${SCM_GIT_SHOW_REMOTE_INFO}" == "auto" && "$(_git-num-remotes)" -ge 2) || + "${SCM_GIT_SHOW_REMOTE_INFO}" == "true" ]]; then + if [[ ${same_branch_name:-} != "true" ]]; then + # shellcheck disable=SC2016 + remote_info='$(_git-upstream)' + else + remote_info="$(_git-upstream-remote)" + fi + elif [[ ${same_branch_name:-} != "true" ]]; then + # shellcheck disable=SC2016 + remote_info='$(_git-upstream-branch)' + fi + if [[ -n "${remote_info:-}" ]]; then + local branch_prefix + if _git-upstream-branch-gone; then + branch_prefix="${SCM_THEME_BRANCH_GONE_PREFIX:-}" + else + branch_prefix="${SCM_THEME_BRANCH_TRACK_PREFIX:-}" + fi + echo "${branch_prefix}${remote_info:-}" + fi + fi } diff --git a/themes/oh-my-posh/oh-my-posh.theme.bash b/themes/oh-my-posh/oh-my-posh.theme.bash new file mode 100644 index 00000000..ba3c77f1 --- /dev/null +++ b/themes/oh-my-posh/oh-my-posh.theme.bash @@ -0,0 +1,8 @@ +# shellcheck shell=bash + +if _command_exists oh-my-posh; then + export POSH_THEME=${POSH_THEME:-https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/v$(oh-my-posh --version)/themes/jandedobbeleer.omp.json} + eval "$(oh-my-posh --init --shell bash --config "${POSH_THEME}")" +else + _log_warning "The oh-my-posh binary was not found on your PATH. Falling back to your existing PS1, please see the docs for more info." +fi diff --git a/themes/p4helpers.theme.bash b/themes/p4helpers.theme.bash index 27a777ac..30b520cc 100644 --- a/themes/p4helpers.theme.bash +++ b/themes/p4helpers.theme.bash @@ -1,18 +1,18 @@ -#!/usr/bin/env bash +# shellcheck shell=bash function _p4-opened { - timeout 2.0s p4 opened -s 2> /dev/null + timeout 2.0s p4 opened -s 2> /dev/null } function _p4-opened-counts { - # Return the following counts seperated by tabs: - # - count of opened files - # - count of pending changesets (other than defaults) - # - count of files in the default changeset - # - count of opened files in add mode - # - count of opened files in edit mode - # - count of opened files in delete mode - _p4-opened | awk ' + # Return the following counts seperated by tabs: + # - count of opened files + # - count of pending changesets (other than defaults) + # - count of files in the default changeset + # - count of opened files in add mode + # - count of opened files in edit mode + # - count of opened files in delete mode + _p4-opened | awk ' BEGIN { opened=0; type_array["edit"]=0; diff --git a/themes/pure/pure.theme.bash b/themes/pure/pure.theme.bash index ba83a232..4dd59e02 100644 --- a/themes/pure/pure.theme.bash +++ b/themes/pure/pure.theme.bash @@ -14,17 +14,12 @@ SCM_HG_CHAR="${bold_red?}☿${normal?}" VIRTUALENV_THEME_PROMPT_PREFIX="(" VIRTUALENV_THEME_PROMPT_SUFFIX=")" -### TODO: openSUSE has already colors enabled, check if those differs from stock -# LS colors, made with http://geoff.greer.fm/lscolors/ -# export LSCOLORS="Gxfxcxdxbxegedabagacad" -# export LS_COLORS='no=00:fi=00:di=01;34:ln=00;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=41;33;01:ex=00;32:*.cmd=00;32:*.exe=01;32:*.com=01;32:*.bat=01;32:*.btm=01;32:*.dll=01;32:*.tar=00;31:*.tbz=00;31:*.tgz=00;31:*.rpm=00;31:*.deb=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.lzma=00;31:*.zip=00;31:*.zoo=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.tb2=00;31:*.tz2=00;31:*.tbz2=00;31:*.avi=01;35:*.bmp=01;35:*.fli=01;35:*.gif=01;35:*.jpg=01;35:*.jpeg=01;35:*.mng=01;35:*.mov=01;35:*.mpg=01;35:*.pcx=01;35:*.pbm=01;35:*.pgm=01;35:*.png=01;35:*.ppm=01;35:*.tga=01;35:*.tif=01;35:*.xbm=01;35:*.xpm=01;35:*.dl=01;35:*.gl=01;35:*.wmv=01;35:*.aiff=00;32:*.au=00;32:*.mid=00;32:*.mp3=00;32:*.ogg=00;32:*.voc=00;32:*.wav=00;32:' - function pure_prompt() { local ps_host="${bold_blue?}\h${normal?}" local ps_user="${green?}\u${normal?}" - local ps_user_mark="${green?} $ ${normal?}" + local ps_user_mark="${green?} \$ ${normal?}" local ps_root="${red?}\u${red?}" - local ps_root_mark="${red?} # ${normal?}" + local ps_root_mark="${red?} \$ ${normal?}" local ps_path="${yellow?}\w${normal?}" local virtualenv_prompt scm_prompt virtualenv_prompt="$(virtualenv_prompt)" @@ -32,12 +27,11 @@ function pure_prompt() { # make it work case "${EUID:-$UID}" in 0) - PS1="${virtualenv_prompt}${ps_root}@${ps_host}${scm_prompt}:${ps_path}${ps_root_mark}" - ;; - *) - PS1="${virtualenv_prompt}${ps_user}@${ps_host}${scm_prompt}:${ps_path}${ps_user_mark}" + ps_user_mark="${ps_root_mark}" + ps_user="${ps_root}" ;; esac + PS1="${virtualenv_prompt}${ps_user}@${ps_host}${scm_prompt}:${ps_path}${ps_user_mark}" } safe_append_prompt_command pure_prompt diff --git a/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh b/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh index c23d0381..5f1208c3 100644 --- a/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh +++ b/vendor/github.com/rcaloras/bash-preexec/bash-preexec.sh @@ -32,11 +32,20 @@ # using: the "DEBUG" trap, and the "PROMPT_COMMAND" variable. If you override # either of these after bash-preexec has been installed it will most likely break. +# Make sure this is bash that's running and return otherwise. +if [[ -z "${BASH_VERSION:-}" ]]; then + return 1; +fi + # Avoid duplicate inclusion -if [[ "${__bp_imported:-}" == "defined" ]]; then +if [[ -n "${bash_preexec_imported:-}" ]]; then return 0 fi -__bp_imported="defined" +bash_preexec_imported="defined" + +# WARNING: This variable is no longer used and should not be relied upon. +# Use ${bash_preexec_imported} instead. +__bp_imported="${bash_preexec_imported}" # Should be available to each precmd and preexec # functions, should they want it. $? and $_ are available as $? and $_, but @@ -70,7 +79,8 @@ __bp_require_not_readonly() { # history even if it starts with a space. __bp_adjust_histcontrol() { local histcontrol - histcontrol="${HISTCONTROL//ignorespace}" + histcontrol="${HISTCONTROL:-}" + histcontrol="${histcontrol//ignorespace}" # Replace ignoreboth with ignoredups if [[ "$histcontrol" == *"ignoreboth"* ]]; then histcontrol="ignoredups:${histcontrol//ignoreboth}" @@ -85,6 +95,10 @@ __bp_adjust_histcontrol() { # and unset as soon as the trace hook is run. __bp_preexec_interactive_mode="" +# These arrays are used to add functions to be run before, or after, prompts. +declare -a precmd_functions +declare -a preexec_functions + # Trims leading and trailing whitespace from $2 and writes it to the variable # name passed as $1 __bp_trim_whitespace() { @@ -154,7 +168,7 @@ __bp_set_ret_value() { __bp_in_prompt_command() { local prompt_command_array - IFS=$'\n;' read -rd '' -a prompt_command_array <<< "$PROMPT_COMMAND" + IFS=$'\n;' read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND:-}" local trimmed_arg __bp_trim_whitespace trimmed_arg "${1:-}" @@ -292,7 +306,8 @@ __bp_install() { local existing_prompt_command # Remove setting our trap install string and sanitize the existing prompt command string - existing_prompt_command="${PROMPT_COMMAND//$__bp_install_string[;$'\n']}" # Edge case of appending to PROMPT_COMMAND + existing_prompt_command="${PROMPT_COMMAND:-}" + existing_prompt_command="${existing_prompt_command//$__bp_install_string[;$'\n']}" # Edge case of appending to PROMPT_COMMAND existing_prompt_command="${existing_prompt_command//$__bp_install_string}" __bp_sanitize_string existing_prompt_command "$existing_prompt_command" @@ -318,17 +333,12 @@ __bp_install() { # after our session has started. This allows bash-preexec to be included # at any point in our bash profile. __bp_install_after_session_init() { - # Make sure this is bash that's running this and return otherwise. - if [[ -z "${BASH_VERSION:-}" ]]; then - return 1; - fi - # bash-preexec needs to modify these variables in order to work correctly # if it can't, just stop the installation __bp_require_not_readonly PROMPT_COMMAND HISTCONTROL HISTTIMEFORMAT || return local sanitized_prompt_command - __bp_sanitize_string sanitized_prompt_command "$PROMPT_COMMAND" + __bp_sanitize_string sanitized_prompt_command "${PROMPT_COMMAND:-}" if [[ -n "$sanitized_prompt_command" ]]; then PROMPT_COMMAND=${sanitized_prompt_command}$'\n' fi;