diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml index 2a27b70fc..800761554 100644 --- a/.github/workflows/project.yml +++ b/.github/workflows/project.yml @@ -47,21 +47,25 @@ jobs: ISSUE_OR_PR_ID: ${{ github.event.issue.node_id || github.event.pull_request.node_id }} run: | item_id="$(gh api graphql -f query=' - mutation($project: ID!, $item: ID!) { - addProjectNextItem(input: {projectId: $project, contentId: $item}) { + mutation($project: ID!, $content: ID!) { + addProjectNextItem(input: {projectId: $project, contentId: $content}) { projectNextItem { id } } } - ' -f project=$PROJECT_ID -f item=$ISSUE_OR_PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')" + ' -f project=$PROJECT_ID -f content=$ISSUE_OR_PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')" echo "ITEM_ID=$item_id" >> $GITHUB_ENV - name: Classify Pull Request if: github.event_name == 'pull_request_target' run: | - gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path' | awk -F/ ' + touch plugins.list themes.list + + gh pr view ${{ github.event.pull_request.number }} \ + --repo ${{ github.repository }} \ + --json files --jq '.files.[].path' | awk -F/ ' /^plugins\// { plugins[$2] = 1 } diff --git a/lib/cli.zsh b/lib/cli.zsh index 8cf8368e6..2f3f293da 100644 --- a/lib/cli.zsh +++ b/lib/cli.zsh @@ -37,7 +37,7 @@ function _omz { elif (( CURRENT == 3 )); then case "$words[2]" in changelog) local -a refs - refs=("${(@f)$(cd "$ZSH"; command git for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}") + refs=("${(@f)$(builtin cd -q "$ZSH"; command git for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}") _describe 'command' refs ;; plugin) subcmds=( 'disable:Disable plugin(s)' @@ -61,7 +61,7 @@ function _omz { # if command is "disable", only offer already enabled plugins valid_plugins=($plugins) else - valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) + valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t)) # if command is "enable", remove already enabled plugins [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins}) fi @@ -69,11 +69,11 @@ function _omz { _describe 'plugin' valid_plugins ;; plugin::info) local -aU plugins - plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) + plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t)) _describe 'plugin' plugins ;; theme::(set|use)) local -aU themes - themes=("$ZSH"/themes/*.zsh-theme(.N:t:r) "$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) + themes=("$ZSH"/themes/*.zsh-theme(-.N:t:r) "$ZSH_CUSTOM"/**/*.zsh-theme(-.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) _describe 'theme' themes ;; esac elif (( CURRENT > 4 )); then @@ -85,7 +85,7 @@ function _omz { # if command is "disable", only offer already enabled plugins valid_plugins=($plugins) else - valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) + valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t)) # if command is "enable", remove already enabled plugins [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins}) fi @@ -176,13 +176,13 @@ function _omz::changelog { local version=${1:-HEAD} format=${3:-"--text"} if ( - cd "$ZSH" + builtin cd -q "$ZSH" ! command git show-ref --verify refs/heads/$version && \ ! command git show-ref --verify refs/tags/$version && \ ! command git rev-parse --verify "${version}^{commit}" ) &>/dev/null; then cat >&2 < must be a valid branch, tag or commit. EOF @@ -193,9 +193,9 @@ EOF } function _omz::plugin { - (( $# > 0 && $+functions[_omz::plugin::$1] )) || { + (( $# > 0 && $+functions[$0::$1] )) || { cat >&2 < [options] +Usage: ${(j: :)${(s.::.)0#_}} [options] Available commands: @@ -212,12 +212,12 @@ EOF local command="$1" shift - _omz::plugin::$command "$@" + $0::$command "$@" } function _omz::plugin::disable { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz plugin disable [...]" + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} [...]" return 1 fi @@ -307,7 +307,7 @@ multi == 1 && length(\$0) > 0 { function _omz::plugin::enable { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz plugin enable [...]" + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} [...]" return 1 fi @@ -383,7 +383,7 @@ multi == 1 && /^[^#]*\)/ { function _omz::plugin::info { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz plugin info " + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} " return 1 fi @@ -430,7 +430,7 @@ function _omz::plugin::list { function _omz::plugin::load { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz plugin load [...]" + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} [...]" return 1 fi @@ -477,9 +477,9 @@ function _omz::plugin::load { } function _omz::pr { - (( $# > 0 && $+functions[_omz::pr::$1] )) || { + (( $# > 0 && $+functions[$0::$1] )) || { cat >&2 < [options] +Usage: ${(j: :)${(s.::.)0#_}} [options] Available commands: @@ -493,7 +493,7 @@ EOF local command="$1" shift - _omz::pr::$command "$@" + $0::$command "$@" } function _omz::pr::clean { @@ -534,7 +534,7 @@ function _omz::pr::test { # Check the input if ! [[ -n "$1" && "$1" =~ ^[[:digit:]]+$ ]]; then - echo >&2 "Usage: omz pr test " + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} " return 1 fi @@ -619,9 +619,9 @@ function _omz::reload { } function _omz::theme { - (( $# > 0 && $+functions[_omz::theme::$1] )) || { + (( $# > 0 && $+functions[$0::$1] )) || { cat >&2 < [options] +Usage: ${(j: :)${(s.::.)0#_}} [options] Available commands: @@ -636,7 +636,7 @@ EOF local command="$1" shift - _omz::theme::$command "$@" + $0::$command "$@" } function _omz::theme::list { @@ -671,7 +671,7 @@ function _omz::theme::list { function _omz::theme::set { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz theme set " + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} " return 1 fi @@ -739,7 +739,7 @@ EOF function _omz::theme::use { if [[ -z "$1" ]]; then - echo >&2 "Usage: omz theme use " + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} " return 1 fi @@ -761,7 +761,7 @@ function _omz::theme::use { } function _omz::update { - local last_commit=$(cd "$ZSH"; git rev-parse HEAD) + local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD) # Run update script if [[ "$1" != --unattended ]]; then @@ -777,7 +777,7 @@ function _omz::update { command rm -rf "$ZSH/log/update.lock" # Restart the zsh session if there were changes - if [[ "$1" != --unattended && "$(cd "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then + if [[ "$1" != --unattended && "$(builtin cd -q "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then # Old zsh versions don't have ZSH_ARGZERO local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" # Check whether to run a login shell @@ -787,16 +787,17 @@ function _omz::update { function _omz::version { ( - cd "$ZSH" + builtin cd -q "$ZSH" # Get the version name: # 1) try tag-like version - # 2) try name-rev - # 3) try branch name + # 2) try branch name + # 3) try name-rev (tag~ or branch~) local version version=$(command git describe --tags HEAD 2>/dev/null) \ + || version=$(command git symbolic-ref --quiet --short HEAD 2>/dev/null) \ || version=$(command git name-rev --no-undefined --name-only --exclude="remotes/*" HEAD 2>/dev/null) \ - || version=$(command git symbolic-ref --quiet --short HEAD 2>/dev/null) + || version="" # Get short hash for the current HEAD local commit=$(command git rev-parse --short HEAD 2>/dev/null) diff --git a/plugins/aws/README.md b/plugins/aws/README.md index 24c6429dd..d6f4f4600 100644 --- a/plugins/aws/README.md +++ b/plugins/aws/README.md @@ -16,10 +16,10 @@ plugins=(... aws) Run `asp` without arguments to clear the profile. * `asp [] login`: If AWS SSO has been configured in your aws profile, it will run the `aws sso login` command following profile selection. -* `acp []`: in addition to `asp` functionality, it actually changes the profile by - assuming the role specified in the `` configuration. It supports MFA and sets - `$AWS_ACCESS_KEY_ID`, `$AWS_SECRET_ACCESS_KEY` and `$AWS_SESSION_TOKEN`, if obtained. It - requires the roles to be configured as per the +* `acp [] []`: in addition to `asp` functionality, it actually changes + the profile by assuming the role specified in the `` configuration. It supports + MFA and sets `$AWS_ACCESS_KEY_ID`, `$AWS_SECRET_ACCESS_KEY` and `$AWS_SESSION_TOKEN`, if + obtained. It requires the roles to be configured as per the [official guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html). Run `acp` without arguments to clear the profile. diff --git a/plugins/aws/aws.plugin.zsh b/plugins/aws/aws.plugin.zsh index c18bd634b..920a7139d 100644 --- a/plugins/aws/aws.plugin.zsh +++ b/plugins/aws/aws.plugin.zsh @@ -45,6 +45,7 @@ function acp() { fi local profile="$1" + local mfa_token="$2" # Get fallback credentials for if the aws command fails or no command is run local aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)" @@ -58,9 +59,10 @@ function acp() { if [[ -n "$mfa_serial" ]]; then local -a mfa_opt - local mfa_token - echo -n "Please enter your MFA token for $mfa_serial: " - read -r mfa_token + if [[ -z "$mfa_token" ]]; then + echo -n "Please enter your MFA token for $mfa_serial: " + read -r mfa_token + fi if [[ -z "$sess_duration" ]]; then echo -n "Please enter the session duration in seconds (900-43200; default: 3600, which is the default maximum for a role): " read -r sess_duration diff --git a/plugins/dotenv/dotenv.plugin.zsh b/plugins/dotenv/dotenv.plugin.zsh index 40ec5c46f..394455ae1 100644 --- a/plugins/dotenv/dotenv.plugin.zsh +++ b/plugins/dotenv/dotenv.plugin.zsh @@ -23,12 +23,12 @@ source_env() { touch "$ZSH_DOTENV_DISALLOWED_LIST" # early return if disallowed - if command grep -q "$dirpath" "$ZSH_DOTENV_DISALLOWED_LIST" &>/dev/null; then + if command grep -Fx -q "$dirpath" "$ZSH_DOTENV_DISALLOWED_LIST" &>/dev/null; then return fi # check if current directory's .env file is allowed or ask for confirmation - if ! command grep -q "$dirpath" "$ZSH_DOTENV_ALLOWED_LIST" &>/dev/null; then + if ! command grep -Fx -q "$dirpath" "$ZSH_DOTENV_ALLOWED_LIST" &>/dev/null; then # get cursor column and print new line before prompt if not at line beginning local column echo -ne "\e[6n" > /dev/tty diff --git a/plugins/fig/README.md b/plugins/fig/README.md new file mode 100644 index 000000000..3861958d6 --- /dev/null +++ b/plugins/fig/README.md @@ -0,0 +1,9 @@ +# Fig plugin + +This plugin sets up completion for [Fig](https://fig.io/). + +To use it, add `fig` to the plugins array in your zshrc file: + +```zsh +plugins=(... fig) +``` diff --git a/plugins/fig/fig.plugin.zsh b/plugins/fig/fig.plugin.zsh new file mode 100644 index 000000000..cddb6c7c0 --- /dev/null +++ b/plugins/fig/fig.plugin.zsh @@ -0,0 +1,13 @@ +if ! (( $+commands[fig] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `fig`. Otherwise, compinit will have already done that +if [[ ! -f "$ZSH_CACHE_DIR/completions/_fig" ]]; then + autoload -Uz _fig + typeset -g -A _comps + _comps[fig]=_fig +fi + +fig completion zsh >| "$ZSH_CACHE_DIR/completions/_fig" &| diff --git a/plugins/git/git.plugin.zsh b/plugins/git/git.plugin.zsh index 648fa0a33..8f7e623ec 100644 --- a/plugins/git/git.plugin.zsh +++ b/plugins/git/git.plugin.zsh @@ -24,9 +24,7 @@ compdef _git _git_log_prettily=git-log # Warn if the current branch is a WIP function work_in_progress() { - if $(git log -n 1 2>/dev/null | grep -q -c "\-\-wip\-\-"); then - echo "WIP!!" - fi + command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- "--wip--" && echo "WIP!!" } # Check if main exists and use instead of master diff --git a/plugins/helm/helm.plugin.zsh b/plugins/helm/helm.plugin.zsh index c6b91693a..cadfa551a 100644 --- a/plugins/helm/helm.plugin.zsh +++ b/plugins/helm/helm.plugin.zsh @@ -11,12 +11,12 @@ command rm -f "${ZSH_CACHE_DIR}/helm_completion" command mkdir -p "$ZSH_CACHE_DIR/completions" (( ${fpath[(Ie)"$ZSH_CACHE_DIR/completions"]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath) -# If the completion file doesn't exist yet, we need to autoload it and -# bind it to `helm`. Otherwise, compinit will have already done that. +# If the completion file does not exist, generate it and then source it +# Otherwise, source it and regenerate in the background if [[ ! -f "$ZSH_CACHE_DIR/completions/_helm" ]]; then - typeset -g -A _comps - autoload -Uz _helm - _comps[helm]=_helm + helm completion zsh >| "$ZSH_CACHE_DIR/completions/_helm" + source "$ZSH_CACHE_DIR/completions/_helm" +else + source "$ZSH_CACHE_DIR/completions/_helm" + helm completion zsh >| "$ZSH_CACHE_DIR/completions/_helm" &| fi - -helm completion zsh >| "$ZSH_CACHE_DIR/completions/_helm" &| diff --git a/plugins/kubectl/kubectl.plugin.zsh b/plugins/kubectl/kubectl.plugin.zsh index bf602bb7b..6edb59751 100644 --- a/plugins/kubectl/kubectl.plugin.zsh +++ b/plugins/kubectl/kubectl.plugin.zsh @@ -8,15 +8,15 @@ if (( $+commands[kubectl] )); then command mkdir -p "$ZSH_CACHE_DIR/completions" (( ${fpath[(Ie)"$ZSH_CACHE_DIR/completions"]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath) - # If the completion file doesn't exist yet, we need to autoload it and - # bind it to `kubectl`. Otherwise, compinit will have already done that. + # If the completion file does not exist, generate it and then source it + # Otherwise, source it and regenerate in the background if [[ ! -f "$ZSH_CACHE_DIR/completions/_kubectl" ]]; then - typeset -g -A _comps - autoload -Uz _kubectl - _comps[kubectl]=_kubectl + kubectl completion zsh >| "$ZSH_CACHE_DIR/completions/_kubectl" + source "$ZSH_CACHE_DIR/completions/_kubectl" + else + source "$ZSH_CACHE_DIR/completions/_kubectl" + kubectl completion zsh >| "$ZSH_CACHE_DIR/completions/_kubectl" &| fi - - kubectl completion zsh >! "$ZSH_CACHE_DIR/completions/_kubectl" &| fi # This command is used a LOT both below and in daily life diff --git a/plugins/mvn/mvn.plugin.zsh b/plugins/mvn/mvn.plugin.zsh index e32729aa6..1b9141f21 100644 --- a/plugins/mvn/mvn.plugin.zsh +++ b/plugins/mvn/mvn.plugin.zsh @@ -117,7 +117,7 @@ function listMavenCompletions { done # List modules - modules=($(find **/pom.xml -type f | grep -v '/target/classes/META-INF/' | grep '/pom.xml' |sed 's|\(.*\)/pom\.xml|\1|')) + modules=($(print -l **/pom.xml(-.N:h) | grep -v '/target/classes/META-INF/')) reply=( # common lifecycle diff --git a/plugins/poetry/README.md b/plugins/poetry/README.md new file mode 100644 index 000000000..51780cbed --- /dev/null +++ b/plugins/poetry/README.md @@ -0,0 +1,9 @@ +# Poetry Plugin + +This plugin automatically installs [Poetry](https://python-poetry.org/)'s completions for you, and keeps them up to date as your Poetry version changes. + +To use it, add `poetry` to the plugins array in your zshrc file: + +```zsh +plugins=(... poetry) +``` diff --git a/plugins/poetry/poetry.plugin.zsh b/plugins/poetry/poetry.plugin.zsh new file mode 100644 index 000000000..cebcb46c4 --- /dev/null +++ b/plugins/poetry/poetry.plugin.zsh @@ -0,0 +1,14 @@ +# Return immediately if poetry is not found +if (( ! $+commands[poetry] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `poetry`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_poetry" ]]; then + typeset -g -A _comps + autoload -Uz _poetry + _comps[poetry]=_poetry +fi + +poetry completions zsh >| "$ZSH_CACHE_DIR/completions/_poetry" &| diff --git a/plugins/rust/rust.plugin.zsh b/plugins/rust/rust.plugin.zsh index 465b701b0..db6ca9e74 100644 --- a/plugins/rust/rust.plugin.zsh +++ b/plugins/rust/rust.plugin.zsh @@ -27,5 +27,5 @@ fi rustup completions zsh >| "$ZSH_CACHE_DIR/completions/_rustup" &| cat >| "$ZSH_CACHE_DIR/completions/_cargo" <<'EOF' #compdef cargo -source $(rustc +${${(z)$(rustup default)}[1]} --print sysroot)/share/zsh/site-functions/_cargo +source "$(rustc +${${(z)$(rustup default)}[1]} --print sysroot)"/share/zsh/site-functions/_cargo EOF diff --git a/plugins/sudo/README.md b/plugins/sudo/README.md index 012fc5325..27cd20c18 100644 --- a/plugins/sudo/README.md +++ b/plugins/sudo/README.md @@ -24,6 +24,20 @@ By pressing the esc key twice, you will have the same command with `s $ sudo apt-get install build-essential ``` +The same happens for editing files with your default editor (defined in `$SUDO_EDITOR`, `$VISUAL` or `$EDITOR`, in that order): + +If the editor defined were `vim`: + +```console +$ vim /etc/hosts +``` + +By pressing the esc key twice, you will have the same command with `sudo -e` instead of the editor, that would open that editor with root privileges: + +```console +$ sudo -e /etc/hosts +``` + ### Previous executed commands Say you want to delete a system file and denied: @@ -44,6 +58,8 @@ Password: $ ``` +The same happens for file editing, as told before. + ## Key binding By default, the `sudo` plugin uses EscEsc as the trigger. diff --git a/plugins/sudo/sudo.plugin.zsh b/plugins/sudo/sudo.plugin.zsh index e02f88a87..2a0b3bfc4 100644 --- a/plugins/sudo/sudo.plugin.zsh +++ b/plugins/sudo/sudo.plugin.zsh @@ -2,7 +2,7 @@ # Description # ----------- # -# sudo or sudoedit will be inserted before the command +# sudo or sudo -e (replacement for sudoedit) will be inserted before the command # # ------------------------------------------------------------------------------ # Authors @@ -11,14 +11,19 @@ # * Dongweiming # * Subhaditya Nath # * Marc Cornellà +# * Carlo Sala # # ------------------------------------------------------------------------------ __sudo-replace-buffer() { local old=$1 new=$2 space=${2:+ } - if [[ ${#LBUFFER} -le ${#old} ]]; then - RBUFFER="${space}${BUFFER#$old }" - LBUFFER="${new}" + + # if the cursor is positioned in the $old part of the text, make + # the substitution and leave the cursor after the $new text + if [[ $CURSOR -le ${#old} ]]; then + BUFFER="${new}${space}${BUFFER#$old }" + CURSOR=${#new} + # otherwise just replace $old with $new in the text before the cursor else LBUFFER="${new}${space}${LBUFFER#$old }" fi @@ -35,14 +40,21 @@ sudo-command-line() { LBUFFER="${LBUFFER:1}" fi - # If $EDITOR is not set, just toggle the sudo prefix on and off - if [[ -z "$EDITOR" ]]; then - case "$BUFFER" in - sudoedit\ *) __sudo-replace-buffer "sudoedit" "" ;; - sudo\ *) __sudo-replace-buffer "sudo" "" ;; - *) LBUFFER="sudo $LBUFFER" ;; - esac - else + { + # If $SUDO_EDITOR or $VISUAL are defined, then use that as $EDITOR + # Else use the default $EDITOR + local EDITOR=${SUDO_EDITOR:-${VISUAL:-$EDITOR}} + + # If $EDITOR is not set, just toggle the sudo prefix on and off + if [[ -z "$EDITOR" ]]; then + case "$BUFFER" in + sudo\ -e\ *) __sudo-replace-buffer "sudo -e" "" ;; + sudo\ *) __sudo-replace-buffer "sudo" "" ;; + *) LBUFFER="sudo $LBUFFER" ;; + esac + return + fi + # Check if the typed command is really an alias to $EDITOR # Get the first part of the typed command @@ -67,24 +79,25 @@ sudo-command-line() { if [[ "$realcmd" = (\$EDITOR|$editorcmd|${editorcmd:c}) \ || "${realcmd:c}" = ($editorcmd|${editorcmd:c}) ]] \ || builtin which -a "$realcmd" | command grep -Fx -q "$editorcmd"; then - editorcmd="$cmd" # replace $editorcmd with the typed command so it matches below + __sudo-replace-buffer "$cmd" "sudo -e" + return fi # Check for editor commands in the typed command and replace accordingly case "$BUFFER" in - $editorcmd\ *) __sudo-replace-buffer "$editorcmd" "sudoedit" ;; - \$EDITOR\ *) __sudo-replace-buffer '$EDITOR' "sudoedit" ;; - sudoedit\ *) __sudo-replace-buffer "sudoedit" "$EDITOR" ;; + $editorcmd\ *) __sudo-replace-buffer "$editorcmd" "sudo -e" ;; + \$EDITOR\ *) __sudo-replace-buffer '$EDITOR' "sudo -e" ;; + sudo\ -e\ *) __sudo-replace-buffer "sudo -e" "$EDITOR" ;; sudo\ *) __sudo-replace-buffer "sudo" "" ;; *) LBUFFER="sudo $LBUFFER" ;; esac - fi + } always { + # Preserve beginning space + LBUFFER="${WHITESPACE}${LBUFFER}" - # Preserve beginning space - LBUFFER="${WHITESPACE}${LBUFFER}" - - # Redisplay edit buffer (compatibility with zsh-syntax-highlighting) - zle redisplay + # Redisplay edit buffer (compatibility with zsh-syntax-highlighting) + zle redisplay + } } zle -N sudo-command-line diff --git a/plugins/svn/svn.plugin.zsh b/plugins/svn/svn.plugin.zsh index 9c3b50d16..22b07b4ec 100644 --- a/plugins/svn/svn.plugin.zsh +++ b/plugins/svn/svn.plugin.zsh @@ -55,7 +55,7 @@ svn_get_branch_name() { } svn_get_rev_nr() { - sed -n 's/Revision:\ //p' "${1:-$(LANG= svn info 2>/dev/null)}" + sed -n 's/Revision:\ //p' <<<"${1:-$(LANG= svn info 2>/dev/null)}" } svn_dirty() { @@ -67,10 +67,10 @@ svn_dirty_choose() { root=$(sed -n 's/^Working Copy Root Path: //p' <<< "${1:-$(LANG= svn info 2>/dev/null)}") if LANG= svn status "$root" 2>/dev/null | command grep -Eq '^\s*[ACDIM!?L]'; then # Grep exits with 0 when "One or more lines were selected", return "dirty". - echo $1 + echo $2 else # Otherwise, no lines were found, or an error occurred. Return clean. - echo $2 + echo $3 fi } diff --git a/plugins/tmux/README.md b/plugins/tmux/README.md index 551814a39..bc192a40c 100644 --- a/plugins/tmux/README.md +++ b/plugins/tmux/README.md @@ -15,20 +15,21 @@ The plugin also supports the following: ## Aliases -| Alias | Command | Description | -| ------ | -----------------------|---------------------------------------------------------- | -| `ta` | tmux attach -t | Attach new tmux session to already running named session | -| `tad` | tmux attach -d -t | Detach named tmux session | -| `ts` | tmux new-session -s | Create a new named tmux session | -| `tl` | tmux list-sessions | Displays a list of running tmux sessions | -| `tksv` | tmux kill-server | Terminate all running tmux sessions | -| `tkss` | tmux kill-session -t | Terminate named running tmux session | -| `tmux` | `_zsh_tmux_plugin_run` | Start a new tmux session | +| Alias | Command | Description | +| ---------- | ---------------------- | -------------------------------------------------------- | +| `ta` | tmux attach -t | Attach new tmux session to already running named session | +| `tad` | tmux attach -d -t | Detach named tmux session | +| `ts` | tmux new-session -s | Create a new named tmux session | +| `tl` | tmux list-sessions | Displays a list of running tmux sessions | +| `tksv` | tmux kill-server | Terminate all running tmux sessions | +| `tkss` | tmux kill-session -t | Terminate named running tmux session | +| `tmux` | `_zsh_tmux_plugin_run` | Start a new tmux session | +| `tmuxconf` | `$EDITOR ~/.tmux.conf` | Open .tmux.conf file with an editor | ## Configuration Variables | Variable | Description | -|-------------------------------------|-------------------------------------------------------------------------------| +| ----------------------------------- | ----------------------------------------------------------------------------- | | `ZSH_TMUX_AUTOSTART` | Automatically starts tmux (default: `false`) | | `ZSH_TMUX_AUTOSTART_ONCE` | Autostart only if tmux hasn't been started previously (default: `true`) | | `ZSH_TMUX_AUTOCONNECT` | Automatically connect to a previous session if it exits (default: `true`) | diff --git a/plugins/tmux/tmux.plugin.zsh b/plugins/tmux/tmux.plugin.zsh index 5474c3522..9d333257e 100644 --- a/plugins/tmux/tmux.plugin.zsh +++ b/plugins/tmux/tmux.plugin.zsh @@ -11,6 +11,7 @@ alias ts='tmux new-session -s' alias tl='tmux list-sessions' alias tksv='tmux kill-server' alias tkss='tmux kill-session -t' +alias tmuxconf='$EDITOR ~/.tmux.conf' # CONFIGURATION VARIABLES # Automatically start tmux diff --git a/plugins/vi-mode/README.md b/plugins/vi-mode/README.md index a1d6bc6b0..476666bf6 100644 --- a/plugins/vi-mode/README.md +++ b/plugins/vi-mode/README.md @@ -30,10 +30,10 @@ plugins=(... vi-mode) ``` - `MODE_INDICATOR`: controls the string displayed when the shell is in normal mode. - See [Mode indicator](#mode-indicator) for details. + See [Mode indicators](#mode-indicators) for details. - `INSERT_MODE_INDICATOR`: controls the string displayed when the shell is in insert mode. - See [Mode indicator](#mode-indicator) for details. + See [Mode indicators](#mode-indicators) for details. ## Mode indicators diff --git a/plugins/yarn/_yarn b/plugins/yarn/_yarn index 9db02602e..1237ba672 100644 --- a/plugins/yarn/_yarn +++ b/plugins/yarn/_yarn @@ -116,7 +116,7 @@ _yarn_commands_scripts() { fi if [[ -n $packageJson ]]; then - scripts=($(cat "$packageJson" | perl -0777 -MJSON::PP -n -E '%r=decode_json($_); say for sort keys %{$r->{scripts}}')) + scripts=($(cat "$packageJson" | perl -0777 -MJSON::PP -n -E '$r=decode_json($_); do{($k=$_)=~s/:/\\:/g;say $k}for sort keys %{$r->{scripts}}')) fi _describe 'command or script' _commands -- _global_commands -- scripts -- binaries @@ -144,7 +144,7 @@ _yarn_scripts() { fi if [[ -n $packageJson ]]; then - scripts=("${(@f)$(cat ${packageJson} | perl -0777 -MJSON::PP -n -E '%r=%{decode_json($_)->{scripts}}; printf "$_:$r{$_}\n" for sort keys %r')}") + scripts=("${(@f)$(cat ${packageJson} | perl -0777 -MJSON::PP -n -E '%r=%{decode_json($_)->{scripts}}; do{$k=$_;($e=$k)=~s/:/\\:/g; printf "$e:$r{$k}\n"} for sort keys %r')}") fi commands=('env' $scripts $binaries) diff --git a/themes/Soliah.zsh-theme b/themes/Soliah.zsh-theme index 070c54981..c3dd6af89 100644 --- a/themes/Soliah.zsh-theme +++ b/themes/Soliah.zsh-theme @@ -45,9 +45,7 @@ function rvm_gemset() { function git_time_since_commit() { if git rev-parse --git-dir > /dev/null 2>&1; then # Only proceed if there is actually a commit. - if [[ $(git log 2>&1 > /dev/null | grep -c "^fatal: bad default revision") == 0 ]]; then - # Get the last commit. - last_commit=`git log --pretty=format:'%at' -1 2> /dev/null` + if last_commit=`git -c log.showSignature=false log --pretty=format:'%at' -1 2> /dev/null`; then now=`date +%s` seconds_since_last_commit=$((now-last_commit)) diff --git a/themes/avit.zsh-theme b/themes/avit.zsh-theme index 1e20d8f9f..f90ba331b 100644 --- a/themes/avit.zsh-theme +++ b/themes/avit.zsh-theme @@ -31,7 +31,7 @@ function _git_time_since_commit() { local last_commit now seconds_since_last_commit local minutes hours days years commit_age # Only proceed if there is actually a commit. - if last_commit=$(git log --pretty=format:'%at' -1 2> /dev/null); then + if last_commit=$(command git -c log.showSignature=false log --format='%at' -1 2>/dev/null); then now=$(date +%s) seconds_since_last_commit=$((now-last_commit)) diff --git a/themes/dogenpunk.zsh-theme b/themes/dogenpunk.zsh-theme index 6a9921288..923ca74bc 100644 --- a/themes/dogenpunk.zsh-theme +++ b/themes/dogenpunk.zsh-theme @@ -37,9 +37,7 @@ ZSH_THEME_GIT_TIME_SINCE_COMMIT_NEUTRAL="%{$fg[cyan]%}" function git_time_since_commit() { if git rev-parse --git-dir > /dev/null 2>&1; then # Only proceed if there is actually a commit. - if git log -n 1 > /dev/null 2>&1; then - # Get the last commit. - last_commit=`git log --pretty=format:'%at' -1 2> /dev/null` + if last_commit=`git -c log.showSignature=false log --pretty=format:'%at' -1 2> /dev/null`; then now=`date +%s` seconds_since_last_commit=$((now-last_commit)) diff --git a/themes/smt.zsh-theme b/themes/smt.zsh-theme index 7f54472c6..52e6d9a21 100644 --- a/themes/smt.zsh-theme +++ b/themes/smt.zsh-theme @@ -40,7 +40,7 @@ function git_time_since_commit() { local last_commit seconds_since_last_commit # Only proceed if there is actually a commit - if ! last_commit=$(command git log --pretty=format:'%at' -1 2>/dev/null); then + if ! last_commit=$(command git -c log.showSignature=false log --pretty=format:'%at' -1 2>/dev/null); then echo "[$ZSH_THEME_GIT_TIME_SINCE_COMMIT_NEUTRAL~%{$reset_color%}]" return fi diff --git a/themes/wedisagree.zsh-theme b/themes/wedisagree.zsh-theme index 07006ecd9..e9e9d6ef8 100644 --- a/themes/wedisagree.zsh-theme +++ b/themes/wedisagree.zsh-theme @@ -69,9 +69,7 @@ function rvm_gemset() { function git_time_since_commit() { if git rev-parse --git-dir > /dev/null 2>&1; then # Only proceed if there is actually a commit. - if [[ $(git log 2>&1 > /dev/null | grep -c "^fatal: bad default revision") == 0 ]]; then - # Get the last commit. - last_commit=`git log --pretty=format:'%at' -1 2> /dev/null` + if last_commit=`git -c log.showSignature=false log --pretty=format:'%at' -1 2> /dev/null`; then now=`date +%s` seconds_since_last_commit=$((now-last_commit)) diff --git a/themes/ys.zsh-theme b/themes/ys.zsh-theme index 45bbae2d1..5ef500e14 100644 --- a/themes/ys.zsh-theme +++ b/themes/ys.zsh-theme @@ -19,6 +19,13 @@ ZSH_THEME_GIT_PROMPT_SUFFIX="$YS_VCS_PROMPT_SUFFIX" ZSH_THEME_GIT_PROMPT_DIRTY="$YS_VCS_PROMPT_DIRTY" ZSH_THEME_GIT_PROMPT_CLEAN="$YS_VCS_PROMPT_CLEAN" +# SVN info +local svn_info='$(svn_prompt_info)' +ZSH_THEME_SVN_PROMPT_PREFIX="${YS_VCS_PROMPT_PREFIX1}svn${YS_VCS_PROMPT_PREFIX2}" +ZSH_THEME_SVN_PROMPT_SUFFIX="$YS_VCS_PROMPT_SUFFIX" +ZSH_THEME_SVN_PROMPT_DIRTY="$YS_VCS_PROMPT_DIRTY" +ZSH_THEME_SVN_PROMPT_CLEAN="$YS_VCS_PROMPT_CLEAN" + # HG info local hg_info='$(ys_hg_prompt_info)' ys_hg_prompt_info() { @@ -66,6 +73,7 @@ PROMPT=" %{$terminfo[bold]$fg[yellow]%}%~%{$reset_color%}\ ${hg_info}\ ${git_info}\ +${svn_info}\ ${venv_info}\ \ [%*] $exit_code diff --git a/tools/changelog.sh b/tools/changelog.sh index 664f34608..49532a4a4 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -395,12 +395,12 @@ function main { # Get the first version name: # 1) try tag-like version, or - # 2) try name-rev, or - # 3) try branch name, or + # 2) try branch name, or + # 3) try name-rev, or # 4) try short hash version=$(command git describe --tags $until 2>/dev/null) \ - || version=$(command git name-rev --no-undefined --name-only --exclude="remotes/*" $until 2>/dev/null) \ || version=$(command git symbolic-ref --quiet --short $until 2>/dev/null) \ + || version=$(command git name-rev --no-undefined --name-only --exclude="remotes/*" $until 2>/dev/null) \ || version=$(command git rev-parse --short $until 2>/dev/null) # Get commit list from $until commit until $since commit, or until root commit if $since is unset @@ -414,7 +414,7 @@ function main { # --first-parent: commits from merged branches are omitted local SEP="0mZmAgIcSeP" local -a raw_commits - raw_commits=(${(0)"$(command git log -z \ + raw_commits=(${(0)"$(command git -c log.showSignature=false log -z \ --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=7 \ --no-merges --first-parent $range)"}) diff --git a/tools/check_for_upgrade.sh b/tools/check_for_upgrade.sh index 293f48edf..3f6d35c3e 100644 --- a/tools/check_for_upgrade.sh +++ b/tools/check_for_upgrade.sh @@ -10,11 +10,13 @@ fi # - auto: the update is performed automatically when it's time # - reminder: a reminder is shown to the user when it's time to update # - disabled: automatic update is turned off -zstyle -s ':omz:update' mode update_mode || update_mode=prompt +zstyle -s ':omz:update' mode update_mode || { + update_mode=prompt -# Support old-style settings -[[ "$DISABLE_UPDATE_PROMPT" != true ]] || update_mode=auto -[[ "$DISABLE_AUTO_UPDATE" != true ]] || update_mode=disabled + # If the mode zstyle setting is not set, support old-style settings + [[ "$DISABLE_UPDATE_PROMPT" != true ]] || update_mode=auto + [[ "$DISABLE_AUTO_UPDATE" != true ]] || update_mode=disabled +} # Cancel update if: # - the automatic update is disabled. @@ -34,11 +36,11 @@ function current_epoch() { function is_update_available() { local branch - branch=${"$(cd "$ZSH"; git config --local oh-my-zsh.branch)":-master} + branch=${"$(cd -q "$ZSH"; git config --local oh-my-zsh.branch)":-master} local remote remote_url remote_repo - remote=${"$(cd "$ZSH"; git config --local oh-my-zsh.remote)":-origin} - remote_url=$(cd "$ZSH"; git config remote.$remote.url) + remote=${"$(cd -q "$ZSH"; git config --local oh-my-zsh.remote)":-origin} + remote_url=$(cd -q "$ZSH"; git config remote.$remote.url) local repo case "$remote_url" in @@ -56,7 +58,7 @@ function is_update_available() { # Get local HEAD. If this fails assume there are updates local local_head - local_head=$(cd "$ZSH"; git rev-parse $branch 2>/dev/null) || return 0 + local_head=$(cd -q "$ZSH"; git rev-parse $branch 2>/dev/null) || return 0 # Get remote HEAD. If no suitable command is found assume there are updates # On any other error, skip the update (connection may be down) @@ -134,7 +136,7 @@ function update_ohmyzsh() { fi # Test if Oh My Zsh directory is a git repository - if ! (cd "$ZSH" && LANG= git rev-parse &>/dev/null); then + if ! (cd -q "$ZSH" && LANG= git rev-parse &>/dev/null); then echo >&2 "[oh-my-zsh] Can't update: not a git repository." return fi diff --git a/tools/install.sh b/tools/install.sh index 731d89a29..d3f1ee640 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -56,6 +56,28 @@ command_exists() { command -v "$@" >/dev/null 2>&1 } +user_can_sudo() { + # The following command has 3 parts: + # + # 1. Run `sudo` with `-v`. Does the following: + # • with privilege: asks for a password immediately. + # • without privilege: exits with error code 1 and prints the message: + # Sorry, user may not run sudo on + # + # 2. Pass `-n` to `sudo` to tell it to not ask for a password. If the + # password is not required, the command will finish with exit code 0. + # If one is required, sudo will exit with error code 1 and print the + # message: + # sudo: a password is required + # + # 3. Check for the words "may not run sudo" in the output to really tell + # whether the user has privileges or not. For that we have to make sure + # to run `sudo` in the default locale (with `LANG=`) so that the message + # stays consistent regardless of the user's locale. + # + LANG= sudo -n -v 2>&1 | grep -q "may not run sudo" +} + # The [ -t 1 ] check only works when the function is not called from # a subshell (like in `$(...)` or `(...)`, so this hack redefines the # function at the top level to always return false when stdout is not @@ -127,6 +149,24 @@ supports_hyperlinks() { return 1 } +# Adapted from code and information by Anton Kochkov (@XVilka) +# Source: https://gist.github.com/XVilka/8346728 +supports_truecolor() { + case "$COLORTERM" in + truecolor|24bit) return 0 ;; + esac + + case "$TERM" in + iterm |\ + tmux-truecolor |\ + linux-truecolor |\ + xterm-truecolor |\ + screen-truecolor) return 0 ;; + esac + + return 1 +} + fmt_link() { # $1: text, $2: url, $3: fallback mode if supports_hyperlinks; then @@ -155,7 +195,28 @@ fmt_error() { setup_color() { # Only use colors if connected to a terminal - if is_tty; then + if ! is_tty; then + RAINBOW="" + RED="" + GREEN="" + YELLOW="" + BLUE="" + BOLD="" + RESET="" + return + fi + + if supports_truecolor; then + RAINBOW=" + $(printf '\033[38;2;255;0;0m') + $(printf '\033[38;2;255;97;0m') + $(printf '\033[38;2;247;255;0m') + $(printf '\033[38;2;0;255;30m') + $(printf '\033[38;2;77;0;255m') + $(printf '\033[38;2;168;0;255m') + $(printf '\033[38;2;245;0;172m') + " + else RAINBOW=" $(printf '\033[38;5;196m') $(printf '\033[38;5;202m') @@ -165,21 +226,14 @@ setup_color() { $(printf '\033[38;5;093m') $(printf '\033[38;5;163m') " - RED=$(printf '\033[31m') - GREEN=$(printf '\033[32m') - YELLOW=$(printf '\033[33m') - BLUE=$(printf '\033[34m') - BOLD=$(printf '\033[1m') - RESET=$(printf '\033[m') - else - RAINBOW="" - RED="" - GREEN="" - YELLOW="" - BLUE="" - BOLD="" - RESET="" fi + + RED=$(printf '\033[31m') + GREEN=$(printf '\033[32m') + YELLOW=$(printf '\033[33m') + BLUE=$(printf '\033[34m') + BOLD=$(printf '\033[1m') + RESET=$(printf '\033[0m') } setup_ohmyzsh() { @@ -285,7 +339,7 @@ EOF "$YELLOW" "$RESET" read -r opt case $opt in - y*|Y*|"") echo "Changing the shell..." ;; + y*|Y*|"") ;; n*|N*) echo "Shell change skipped."; return ;; *) echo "Invalid choice. Shell change skipped."; return ;; esac @@ -323,11 +377,28 @@ EOF if [ -n "$SHELL" ]; then echo "$SHELL" > ~/.shell.pre-oh-my-zsh else - grep "^$USERNAME:" /etc/passwd | awk -F: '{print $7}' > ~/.shell.pre-oh-my-zsh + grep "^$USER:" /etc/passwd | awk -F: '{print $7}' > ~/.shell.pre-oh-my-zsh fi - # Actually change the default shell to zsh - if ! chsh -s "$zsh"; then + echo "Changing your shell to $zsh..." + + # Check if user has sudo privileges to run `chsh` with or without `sudo` + # + # This allows the call to succeed without password on systems where the + # user does not have a password but does have sudo privileges, like in + # Google Cloud Shell. + # + # On systems that don't have a user with passwordless sudo, the user will + # be prompted for the password either way, so this shouldn't cause any issues. + # + if user_can_sudo; then + chsh -s "$zsh" "$USER" # run chsh normally + else + sudo -k chsh -s "$zsh" "$USER" # -k forces the password prompt + fi + + # Check if the shell change was successful + if [ $? -ne 0 ]; then fmt_error "chsh command unsuccessful. Change your default shell manually." else export SHELL="$zsh" diff --git a/tools/upgrade.sh b/tools/upgrade.sh index 994ffe9c9..55412062a 100755 --- a/tools/upgrade.sh +++ b/tools/upgrade.sh @@ -86,6 +86,24 @@ supports_hyperlinks() { return 1 } +# Adapted from code and information by Anton Kochkov (@XVilka) +# Source: https://gist.github.com/XVilka/8346728 +supports_truecolor() { + case "$COLORTERM" in + truecolor|24bit) return 0 ;; + esac + + case "$TERM" in + iterm |\ + tmux-truecolor |\ + linux-truecolor |\ + xterm-truecolor |\ + screen-truecolor) return 0 ;; + esac + + return 1 +} + fmt_link() { # $1: text, $2: url, $3: fallback mode if supports_hyperlinks; then @@ -107,15 +125,27 @@ setopt typeset_silent typeset -a RAINBOW if is_tty; then - RAINBOW=( - "$(printf '\033[38;5;196m')" - "$(printf '\033[38;5;202m')" - "$(printf '\033[38;5;226m')" - "$(printf '\033[38;5;082m')" - "$(printf '\033[38;5;021m')" - "$(printf '\033[38;5;093m')" - "$(printf '\033[38;5;163m')" - ) + if supports_truecolor; then + RAINBOW=( + "$(printf '\033[38;2;255;0;0m')" + "$(printf '\033[38;2;255;97;0m')" + "$(printf '\033[38;2;247;255;0m')" + "$(printf '\033[38;2;0;255;30m')" + "$(printf '\033[38;2;77;0;255m')" + "$(printf '\033[38;2;168;0;255m')" + "$(printf '\033[38;2;245;0;172m')" + ) + else + RAINBOW=( + "$(printf '\033[38;5;196m')" + "$(printf '\033[38;5;202m')" + "$(printf '\033[38;5;226m')" + "$(printf '\033[38;5;082m')" + "$(printf '\033[38;5;021m')" + "$(printf '\033[38;5;093m')" + "$(printf '\033[38;5;163m')" + ) + fi RED=$(printf '\033[31m') GREEN=$(printf '\033[32m') @@ -164,7 +194,7 @@ last_commit=$(git rev-parse "$branch") # Update Oh My Zsh printf "${BLUE}%s${RESET}\n" "Updating Oh My Zsh" -if git pull --rebase --stat $remote $branch; then +if git pull --rebase $remote $branch; then # Check if it was really updated or not if [[ "$(git rev-parse HEAD)" = "$last_commit" ]]; then message="Oh My Zsh is already at the latest version."