summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS2
-rw-r--r--lib/cli.zsh593
-rw-r--r--lib/functions.zsh13
-rw-r--r--lib/git.zsh23
-rw-r--r--plugins/ansible/ansible.plugin.zsh4
-rw-r--r--plugins/archlinux/archlinux.plugin.zsh18
-rw-r--r--plugins/command-not-found/command-not-found.plugin.zsh24
-rw-r--r--plugins/common-aliases/README.md4
-rw-r--r--plugins/common-aliases/common-aliases.plugin.zsh2
-rw-r--r--plugins/composer/composer.plugin.zsh2
-rw-r--r--plugins/genpass/README.md66
-rwxr-xr-xplugins/genpass/genpass-apple79
-rwxr-xr-xplugins/genpass/genpass-monkey32
-rwxr-xr-xplugins/genpass/genpass-xkcd68
-rw-r--r--plugins/genpass/genpass.plugin.zsh1
-rw-r--r--plugins/git-auto-fetch/README.md43
-rw-r--r--plugins/git-auto-fetch/git-auto-fetch.plugin.zsh81
-rw-r--r--plugins/git-prompt/gitstatus.py4
-rw-r--r--plugins/git/git.plugin.zsh1
-rw-r--r--plugins/grc/README.md37
-rw-r--r--plugins/grc/grc.plugin.zsh44
-rw-r--r--plugins/hanami/README.md63
-rw-r--r--plugins/hanami/hanami.plugin.zsh6
-rw-r--r--plugins/magic-enter/magic-enter.plugin.zsh53
-rw-r--r--plugins/wp-cli/README.md202
-rw-r--r--plugins/wp-cli/wp-cli.plugin.zsh51
-rwxr-xr-xtools/changelog.sh429
-rw-r--r--tools/check_for_upgrade.sh110
-rwxr-xr-x[-rw-r--r--]tools/upgrade.sh117
29 files changed, 1525 insertions, 647 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e16ebb39b..b091f5d89 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,5 +1,7 @@
# Plugin owners
plugins/aws/ @maksyms
+plugins/genpass/ @atoponce
plugins/git-lfs/ @vietduc01100001
plugins/gitfast/ @felipec
plugins/sdk/ @rgoldberg
+plugins/wp-cli/ @joshmedeski
diff --git a/lib/cli.zsh b/lib/cli.zsh
index b1478a89f..92d447a8e 100644
--- a/lib/cli.zsh
+++ b/lib/cli.zsh
@@ -1,360 +1,397 @@
#!/usr/bin/env zsh
function omz {
- [[ $# -gt 0 ]] || {
- _omz::help
- return 1
- }
-
- local command="$1"
- shift
-
- # Subcommand functions start with _ so that they don't
- # appear as completion entries when looking for `omz`
- (( $+functions[_omz::$command] )) || {
- _omz::help
- return 1
- }
-
- _omz::$command "$@"
+ [[ $# -gt 0 ]] || {
+ _omz::help
+ return 1
+ }
+
+ local command="$1"
+ shift
+
+ # Subcommand functions start with _ so that they don't
+ # appear as completion entries when looking for `omz`
+ (( $+functions[_omz::$command] )) || {
+ _omz::help
+ return 1
+ }
+
+ _omz::$command "$@"
}
function _omz {
- local -a cmds subcmds
- cmds=(
- 'help:Usage information'
- 'plugin:Commands for Oh My Zsh plugins management'
- 'pr:Commands for Oh My Zsh Pull Requests management'
- 'theme:Commands for Oh My Zsh themes management'
- 'update:Update Oh My Zsh'
- )
-
- if (( CURRENT == 2 )); then
- _describe 'command' cmds
- elif (( CURRENT == 3 )); then
- case "$words[2]" in
- plugin) subcmds=('list:List plugins')
- _describe 'command' subcmds ;;
- pr) subcmds=('test:Test a Pull Request' 'clean:Delete all Pull Request branches')
- _describe 'command' subcmds ;;
- theme) subcmds=('use:Load a theme' 'list:List themes')
- _describe 'command' subcmds ;;
- esac
- elif (( CURRENT == 4 )); then
- case "$words[2]::$words[3]" in
- theme::use) compadd "$ZSH"/themes/*.zsh-theme(.N:t:r) \
- "$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::) ;;
- esac
- fi
-
- return 0
+ local -a cmds subcmds
+ cmds=(
+ 'changelog:Print the changelog'
+ 'help:Usage information'
+ 'plugin:Manage plugins'
+ 'pr:Manage Oh My Zsh Pull Requests'
+ 'theme:Manage themes'
+ 'update:Update Oh My Zsh'
+ )
+
+ if (( CURRENT == 2 )); then
+ _describe 'command' cmds
+ elif (( CURRENT == 3 )); then
+ case "$words[2]" in
+ changelog) local -a refs
+ refs=("${(@f)$(command git for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}")
+ _describe 'command' refs ;;
+ plugin) subcmds=('list:List plugins')
+ _describe 'command' subcmds ;;
+ pr) subcmds=('test:Test a Pull Request' 'clean:Delete all Pull Request branches')
+ _describe 'command' subcmds ;;
+ theme) subcmds=('use:Load a theme' 'list:List themes')
+ _describe 'command' subcmds ;;
+ esac
+ elif (( CURRENT == 4 )); then
+ case "$words[2]::$words[3]" in
+ theme::use) compadd "$ZSH"/themes/*.zsh-theme(.N:t:r) \
+ "$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::) ;;
+ esac
+ fi
+
+ return 0
}
compdef _omz omz
+## Utility functions
+
+function _omz::confirm {
+ # If question supplied, ask it before reading the answer
+ # NOTE: uses the logname of the caller function
+ if [[ -n "$1" ]]; then
+ _omz::log prompt "$1" "${${functrace[1]#_}%:*}"
+ fi
+
+ # Read one character
+ read -r -k 1
+
+ # If no newline entered, add a newline
+ if [[ "$REPLY" != $'\n' ]]; then
+ echo
+ fi
+}
+
+function _omz::log {
+ # if promptsubst is set, a message with `` or $()
+ # will be run even if quoted due to `print -P`
+ setopt localoptions nopromptsubst
+
+ # $1 = info|warn|error|debug
+ # $2 = text
+ # $3 = (optional) name of the logger
+
+ local logtype=$1
+ local logname=${3:-${${functrace[1]#_}%:*}}
+
+ # Don't print anything if debug is not active
+ if [[ $logtype = debug && -z $_OMZ_DEBUG ]]; then
+ return
+ fi
+
+ # Choose coloring based on log type
+ case "$logtype" in
+ prompt) print -Pn "%S%F{blue}$logname%f%s: $2" ;;
+ debug) print -P "%F{white}$logname%f: $2" ;;
+ info) print -P "%F{green}$logname%f: $2" ;;
+ warn) print -P "%S%F{yellow}$logname%f%s: $2" ;;
+ error) print -P "%S%F{red}$logname%f%s: $2" ;;
+ esac >&2
+}
+
+## User-facing commands
function _omz::help {
- cat <<EOF
+ cat <<EOF
Usage: omz <command> [options]
Available commands:
- help Print this help message
- plugin <command> Manage plugins
- pr <command> Manage Oh My Zsh Pull Requests
- theme <command> Manage themes
- update Update Oh My Zsh
+ help Print this help message
+ changelog Print the changelog
+ plugin <command> Manage plugins
+ pr <command> Manage Oh My Zsh Pull Requests
+ theme <command> Manage themes
+ update Update Oh My Zsh
EOF
}
-function _omz::confirm {
- # If question supplied, ask it before reading the answer
- # NOTE: uses the logname of the caller function
- if [[ -n "$1" ]]; then
- _omz::log prompt "$1" "${${functrace[1]#_}%:*}"
- fi
-
- # Read one character
- read -r -k 1
-
- # If no newline entered, add a newline
- if [[ "$REPLY" != $'\n' ]]; then
- echo
- fi
-}
-
-function _omz::log {
- # if promptsubst is set, a message with `` or $()
- # will be run even if quoted due to `print -P`
- setopt localoptions nopromptsubst
-
- # $1 = info|warn|error|debug
- # $2 = text
- # $3 = (optional) name of the logger
+function _omz::changelog {
+ local version=${1:-HEAD} format=${3:-"--text"}
- local logtype=$1
- local logname=${3:-${${functrace[1]#_}%:*}}
+ if ! command git -C "$ZSH" show-ref --verify refs/heads/$version &>/dev/null && \
+ ! command git -C "$ZSH" show-ref --verify refs/tags/$version &>/dev/null && \
+ ! command git -C "$ZSH" rev-parse --verify "${version}^{commit}" &>/dev/null; then
+ cat <<EOF
+Usage: omz changelog [version]
- # Don't print anything if debug is not active
- if [[ $logtype = debug && -z $_OMZ_DEBUG ]]; then
- return
- fi
+NOTE: <version> must be a valid branch, tag or commit.
+EOF
+ return 1
+ fi
- # Choose coloring based on log type
- case "$logtype" in
- prompt) print -Pn "%S%F{blue}$logname%f%s: $2" ;;
- debug) print -P "%F{white}$logname%f: $2" ;;
- info) print -P "%F{green}$logname%f: $2" ;;
- warn) print -P "%S%F{yellow}$logname%f%s: $2" ;;
- error) print -P "%S%F{red}$logname%f%s: $2" ;;
- esac >&2
+ "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format"
}
function _omz::plugin {
- (( $# > 0 && $+functions[_omz::plugin::$1] )) || {
- cat <<EOF
+ (( $# > 0 && $+functions[_omz::plugin::$1] )) || {
+ cat <<EOF
Usage: omz plugin <command> [options]
Available commands:
- list List all available Oh My Zsh plugins
+ list List all available Oh My Zsh plugins
EOF
- return 1
- }
+ return 1
+ }
- local command="$1"
- shift
+ local command="$1"
+ shift
- _omz::plugin::$command "$@"
+ _omz::plugin::$command "$@"
}
function _omz::plugin::list {
- local -a custom_plugins builtin_plugins
- custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t))
- builtin_plugins=("$ZSH"/plugins/*(-/N:t))
-
- # If the command is being piped, print all found line by line
- if [[ ! -t 1 ]]; then
- print -l ${(q-)custom_plugins} ${(q-)builtin_plugins}
- return
- fi
-
- if (( ${#custom_plugins} )); then
- print -P "%U%BCustom plugins%b%u:"
- print -l ${(q-)custom_plugins} | column
- fi
-
- if (( ${#builtin_plugins} )); then
- (( ${#custom_plugins} )) && echo # add a line of separation
-
- print -P "%U%BBuilt-in plugins%b%u:"
- print -l ${(q-)builtin_plugins} | column
- fi
+ local -a custom_plugins builtin_plugins
+ custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t))
+ builtin_plugins=("$ZSH"/plugins/*(-/N:t))
+
+ # If the command is being piped, print all found line by line
+ if [[ ! -t 1 ]]; then
+ print -l ${(q-)custom_plugins} ${(q-)builtin_plugins}
+ return
+ fi
+
+ if (( ${#custom_plugins} )); then
+ print -P "%U%BCustom plugins%b%u:"
+ print -l ${(q-)custom_plugins} | column
+ fi
+
+ if (( ${#builtin_plugins} )); then
+ (( ${#custom_plugins} )) && echo # add a line of separation
+
+ print -P "%U%BBuilt-in plugins%b%u:"
+ print -l ${(q-)builtin_plugins} | column
+ fi
}
function _omz::pr {
- (( $# > 0 && $+functions[_omz::pr::$1] )) || {
- cat <<EOF
+ (( $# > 0 && $+functions[_omz::pr::$1] )) || {
+ cat <<EOF
Usage: omz pr <command> [options]
Available commands:
- clean Delete all PR branches (ohmyzsh/pull-*)
- test <PR_number_or_URL> Fetch PR #NUMBER and rebase against master
+ clean Delete all PR branches (ohmyzsh/pull-*)
+ test <PR_number_or_URL> Fetch PR #NUMBER and rebase against master
EOF
- return 1
- }
+ return 1
+ }
- local command="$1"
- shift
+ local command="$1"
+ shift
- _omz::pr::$command "$@"
+ _omz::pr::$command "$@"
}
function _omz::pr::clean {
- (
- set -e
- builtin cd -q "$ZSH"
-
- # Check if there are PR branches
- local fmt branches
- fmt="%(color:bold blue)%(align:18,right)%(refname:short)%(end)%(color:reset) %(color:dim bold red)%(objectname:short)%(color:reset) %(color:yellow)%(contents:subject)"
- branches="$(command git for-each-ref --sort=-committerdate --color --format="$fmt" "refs/heads/ohmyzsh/pull-*")"
-
- # Exit if there are no PR branches
- if [[ -z "$branches" ]]; then
- _omz::log info "there are no Pull Request branches to remove."
- return
- fi
-
- # Print found PR branches
- echo "$branches\n"
- # Confirm before removing the branches
- _omz::confirm "do you want remove these Pull Request branches? [Y/n] "
- # Only proceed if the answer is a valid yes option
- [[ "$REPLY" != [yY$'\n'] ]] && return
-
- _omz::log info "removing all Oh My Zsh Pull Request branches..."
- command git branch --list 'ohmyzsh/pull-*' | while read branch; do
- command git branch -D "$branch"
- done
- )
+ (
+ set -e
+ builtin cd -q "$ZSH"
+
+ # Check if there are PR branches
+ local fmt branches
+ fmt="%(color:bold blue)%(align:18,right)%(refname:short)%(end)%(color:reset) %(color:dim bold red)%(objectname:short)%(color:reset) %(color:yellow)%(contents:subject)"
+ branches="$(command git for-each-ref --sort=-committerdate --color --format="$fmt" "refs/heads/ohmyzsh/pull-*")"
+
+ # Exit if there are no PR branches
+ if [[ -z "$branches" ]]; then
+ _omz::log info "there are no Pull Request branches to remove."
+ return
+ fi
+
+ # Print found PR branches
+ echo "$branches\n"
+ # Confirm before removing the branches
+ _omz::confirm "do you want remove these Pull Request branches? [Y/n] "
+ # Only proceed if the answer is a valid yes option
+ [[ "$REPLY" != [yY$'\n'] ]] && return
+
+ _omz::log info "removing all Oh My Zsh Pull Request branches..."
+ command git branch --list 'ohmyzsh/pull-*' | while read branch; do
+ command git branch -D "$branch"
+ done
+ )
}
function _omz::pr::test {
- # Allow $1 to be a URL to the pull request
- if [[ "$1" = https://* ]]; then
- 1="${1:t}"
- fi
+ # Allow $1 to be a URL to the pull request
+ if [[ "$1" = https://* ]]; then
+ 1="${1:t}"
+ fi
+
+ # Check the input
+ if ! [[ -n "$1" && "$1" =~ ^[[:digit:]]+$ ]]; then
+ echo >&2 "Usage: omz pr test <PR_NUMBER_or_URL>"
+ return 1
+ fi
+
+ # Save current git HEAD
+ local branch
+ branch=$(builtin cd -q "$ZSH"; git symbolic-ref --short HEAD) || {
+ _omz::log error "error when getting the current git branch. Aborting..."
+ return 1
+ }
+
+
+ # Fetch PR onto ohmyzsh/pull-<PR_NUMBER> branch and rebase against master
+ # If any of these operations fail, undo the changes made
+ (
+ set -e
+ builtin cd -q "$ZSH"
+
+ # Get the ohmyzsh git remote
+ command git remote -v | while read remote url _; do
+ case "$url" in
+ https://github.com/ohmyzsh/ohmyzsh(|.git)) found=1; break ;;
+ git@github.com:ohmyzsh/ohmyzsh(|.git)) found=1; break ;;
+ esac
+ done
+
+ (( $found )) || {
+ _omz::log error "could not found the ohmyzsh git remote. Aborting..."
+ return 1
+ }
- # Check the input
- if ! [[ -n "$1" && "$1" =~ ^[[:digit:]]+$ ]]; then
- echo >&2 "Usage: omz pr test <PR_NUMBER_or_URL>"
- return 1
- fi
+ # Fetch pull request head
+ _omz::log info "fetching PR #$1 to ohmyzsh/pull-$1..."
+ command git fetch -f "$remote" refs/pull/$1/head:ohmyzsh/pull-$1 || {
+ _omz::log error "error when trying to fetch PR #$1."
+ return 1
+ }
- # Save current git HEAD
- local branch
- branch=$(builtin cd -q "$ZSH"; git symbolic-ref --short HEAD) || {
- _omz::log error "error when getting the current git branch. Aborting..."
- return 1
+ # Rebase pull request branch against the current master
+ _omz::log info "rebasing PR #$1..."
+ command git rebase master ohmyzsh/pull-$1 || {
+ command git rebase --abort &>/dev/null
+ _omz::log warn "could not rebase PR #$1 on top of master."
+ _omz::log warn "you might not see the latest stable changes."
+ _omz::log info "run \`zsh\` to test the changes."
+ return 1
}
+ _omz::log info "fetch of PR #${1} successful."
+ )
- # Fetch PR onto ohmyzsh/pull-<PR_NUMBER> branch and rebase against master
- # If any of these operations fail, undo the changes made
- (
- set -e
- builtin cd -q "$ZSH"
-
- # Get the ohmyzsh git remote
- command git remote -v | while read remote url _; do
- case "$url" in
- https://github.com/ohmyzsh/ohmyzsh(|.git)) found=1; break ;;
- git@github.com:ohmyzsh/ohmyzsh(|.git)) found=1; break ;;
- esac
- done
-
- (( $found )) || {
- _omz::log error "could not found the ohmyzsh git remote. Aborting..."
- return 1
- }
-
- # Fetch pull request head
- _omz::log info "fetching PR #$1 to ohmyzsh/pull-$1..."
- command git fetch -f "$remote" refs/pull/$1/head:ohmyzsh/pull-$1 || {
- _omz::log error "error when trying to fetch PR #$1."
- return 1
- }
-
- # Rebase pull request branch against the current master
- _omz::log info "rebasing PR #$1..."
- command git rebase master ohmyzsh/pull-$1 || {
- command git rebase --abort &>/dev/null
- _omz::log warn "could not rebase PR #$1 on top of master."
- _omz::log warn "you might not see the latest stable changes."
- _omz::log info "run \`zsh\` to test the changes."
- return 1
- }
-
- _omz::log info "fetch of PR #${1} successful."
- )
-
- # If there was an error, abort running zsh to test the PR
- [[ $? -eq 0 ]] || return 1
-
- # Run zsh to test the changes
- _omz::log info "running \`zsh\` to test the changes. Run \`exit\` to go back."
- command zsh -l
-
- # After testing, go back to the previous HEAD if the user wants
- _omz::confirm "do you want to go back to the previous branch? [Y/n] "
- # Only proceed if the answer is a valid yes option
- [[ "$REPLY" != [yY$'\n'] ]] && return
+ # If there was an error, abort running zsh to test the PR
+ [[ $? -eq 0 ]] || return 1
+
+ # Run zsh to test the changes
+ _omz::log info "running \`zsh\` to test the changes. Run \`exit\` to go back."
+ command zsh -l
- (
- set -e
- builtin cd -q "$ZSH"
+ # After testing, go back to the previous HEAD if the user wants
+ _omz::confirm "do you want to go back to the previous branch? [Y/n] "
+ # Only proceed if the answer is a valid yes option
+ [[ "$REPLY" != [yY$'\n'] ]] && return
- command git checkout "$branch" -- || {
- _omz::log error "could not go back to the previous branch ('$branch')."
- return 1
- }
- )
+ (
+ set -e
+ builtin cd -q "$ZSH"
+
+ command git checkout "$branch" -- || {
+ _omz::log error "could not go back to the previous branch ('$branch')."
+ return 1
+ }
+ )
}
function _omz::theme {
- (( $# > 0 && $+functions[_omz::theme::$1] )) || {
- cat <<EOF
+ (( $# > 0 && $+functions[_omz::theme::$1] )) || {
+ cat <<EOF
Usage: omz theme <command> [options]
Available commands:
- list List all available Oh My Zsh themes
- use <theme> Load an Oh My Zsh theme
+ list List all available Oh My Zsh themes
+ use <theme> Load an Oh My Zsh theme
EOF
- return 1
- }
+ return 1
+ }
- local command="$1"
- shift
+ local command="$1"
+ shift
- _omz::theme::$command "$@"
+ _omz::theme::$command "$@"
}
function _omz::theme::list {
- local -a custom_themes builtin_themes
- custom_themes=("$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::))
- builtin_themes=("$ZSH"/themes/*.zsh-theme(.N:t:r))
-
- # If the command is being piped, print all found line by line
- if [[ ! -t 1 ]]; then
- print -l ${(q-)custom_themes} ${(q-)builtin_themes}
- return
- fi
-
- if (( ${#custom_themes} )); then
- print -P "%U%BCustom themes%b%u:"
- print -l ${(q-)custom_themes} | column
- fi
-
- if (( ${#builtin_themes} )); then
- (( ${#custom_themes} )) && echo # add a line of separation
-
- print -P "%U%BBuilt-in themes%b%u:"
- print -l ${(q-)builtin_themes} | column
- fi
+ local -a custom_themes builtin_themes
+ custom_themes=("$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::))
+ builtin_themes=("$ZSH"/themes/*.zsh-theme(.N:t:r))
+
+ # If the command is being piped, print all found line by line
+ if [[ ! -t 1 ]]; then
+ print -l ${(q-)custom_themes} ${(q-)builtin_themes}
+ return
+ fi
+
+ if (( ${#custom_themes} )); then
+ print -P "%U%BCustom themes%b%u:"
+ print -l ${(q-)custom_themes} | column
+ fi
+
+ if (( ${#builtin_themes} )); then
+ (( ${#custom_themes} )) && echo # add a line of separation
+
+ print -P "%U%BBuilt-in themes%b%u:"
+ print -l ${(q-)builtin_themes} | column
+ fi
}
function _omz::theme::use {
- if [[ -z "$1" ]]; then
- echo >&2 "Usage: omz theme use <theme>"
- return 1
- fi
-
- # Respect compatibility with old lookup order
- if [[ -f "$ZSH_CUSTOM/$1.zsh-theme" ]]; then
- source "$ZSH_CUSTOM/$1.zsh-theme"
- elif [[ -f "$ZSH_CUSTOM/themes/$1.zsh-theme" ]]; then
- source "$ZSH_CUSTOM/themes/$1.zsh-theme"
- elif [[ -f "$ZSH/themes/$1.zsh-theme" ]]; then
- source "$ZSH/themes/$1.zsh-theme"
- else
- _omz::log error "theme '$1' not found"
- return 1
- fi
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz theme use <theme>"
+ return 1
+ fi
+
+ # Respect compatibility with old lookup order
+ if [[ -f "$ZSH_CUSTOM/$1.zsh-theme" ]]; then
+ source "$ZSH_CUSTOM/$1.zsh-theme"
+ elif [[ -f "$ZSH_CUSTOM/themes/$1.zsh-theme" ]]; then
+ source "$ZSH_CUSTOM/themes/$1.zsh-theme"
+ elif [[ -f "$ZSH/themes/$1.zsh-theme" ]]; then
+ source "$ZSH/themes/$1.zsh-theme"
+ else
+ _omz::log error "theme '$1' not found"
+ return 1
+ fi
}
function _omz::update {
- # Run update script
- env ZSH="$ZSH" sh "$ZSH/tools/upgrade.sh"
- # Update last updated file
- zmodload zsh/datetime
- echo "LAST_EPOCH=$(( EPOCHSECONDS / 60 / 60 / 24 ))" >! "${ZSH_CACHE_DIR}/.zsh-update"
- # Remove update lock if it exists
- command rm -rf "$ZSH/log/update.lock"
+ # Run update script
+ if [[ "$1" != --unattended ]]; then
+ ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh" --interactive
+ else
+ ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh"
+ fi
+ local ret=$?
+
+ # Update last updated file
+ zmodload zsh/datetime
+ echo "LAST_EPOCH=$(( EPOCHSECONDS / 60 / 60 / 24 ))" >! "${ZSH_CACHE_DIR}/.zsh-update"
+ # Remove update lock if it exists
+ command rm -rf "$ZSH/log/update.lock"
+
+ # Restart the zsh session
+ if [[ $ret -eq 0 && "$1" != --unattended ]]; then
+ # Check whether to run a login shell
+ [[ "$ZSH_ARGZERO" = -* ]] && exec -l "${ZSH_ARGZERO#-}" || exec "$ZSH_ARGZERO"
+ fi
}
diff --git a/lib/functions.zsh b/lib/functions.zsh
index 15526cd5f..7beb62ad9 100644
--- a/lib/functions.zsh
+++ b/lib/functions.zsh
@@ -9,17 +9,8 @@ function uninstall_oh_my_zsh() {
}
function upgrade_oh_my_zsh() {
- if (( $+functions[_omz::update] )); then
- echo >&2 "${fg[yellow]}Note: \`$0\` is deprecated. Use \`omz update\` instead.$reset_color"
- fi
-
- # Run update script
- env ZSH="$ZSH" sh "$ZSH/tools/upgrade.sh"
- # Update last updated file
- zmodload zsh/datetime
- echo "LAST_EPOCH=$(( EPOCHSECONDS / 60 / 60 / 24 ))" >! "${ZSH_CACHE_DIR}/.zsh-update"
- # Remove update lock if it exists
- command rm -rf "$ZSH/log/update.lock"
+ echo >&2 "${fg[yellow]}Note: \`$0\` is deprecated. Use \`omz update\` instead.$reset_color"
+ omz update
}
function take() {
diff --git a/lib/git.zsh b/lib/git.zsh
index 53d39609e..157c85062 100644
--- a/lib/git.zsh
+++ b/lib/git.zsh
@@ -9,14 +9,27 @@ function __git_prompt_git() {
GIT_OPTIONAL_LOCKS=0 command git "$@"
}
-# Outputs current branch info in prompt format
function git_prompt_info() {
+ # If we are on a folder not tracked by git, get out.
+ # Otherwise, check for hide-info at global and local repository level
+ if ! __git_prompt_git rev-parse --git-dir &> /dev/null \
+ || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then
+ return 0
+ fi
+
local ref
- if [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" != "1" ]]; then
- ref=$(__git_prompt_git symbolic-ref HEAD 2> /dev/null) || \
- ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return 0
- echo "$ZSH_THEME_GIT_PROMPT_PREFIX${ref#refs/heads/}$(parse_git_dirty)$ZSH_THEME_GIT_PROMPT_SUFFIX"
+ ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \
+ || ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) \
+ || return 0
+
+ # Use global ZSH_THEME_GIT_SHOW_UPSTREAM=1 for including upstream remote info
+ local upstream
+ if (( ${+ZSH_THEME_GIT_SHOW_UPSTREAM} )); then
+ upstream=$(__git_prompt_git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null) \
+ && upstream=" -> ${upstream}"
fi
+
+ echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref}${upstream}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}"
}
# Checks if working tree is dirty
diff --git a/plugins/ansible/ansible.plugin.zsh b/plugins/ansible/ansible.plugin.zsh
index f68ff23a5..75393b704 100644
--- a/plugins/ansible/ansible.plugin.zsh
+++ b/plugins/ansible/ansible.plugin.zsh
@@ -4,7 +4,7 @@ function ansible-version(){
}
function ansible-role-init(){
- if ! [ -z $1] ; then
+ if ! [ -z $1 ] ; then
echo "Ansible Role : $1 Creating...."
ansible-galaxy init $1
tree $1
@@ -25,4 +25,4 @@ alias ainv='ansible-inventory '
alias adoc='ansible-doc '
alias agal='ansible-galaxy '
alias apull='ansible-pull '
-alias aval='ansible-vault' \ No newline at end of file
+alias aval='ansible-vault'
diff --git a/plugins/archlinux/archlinux.plugin.zsh b/plugins/archlinux/archlinux.plugin.zsh
index 4d39bd86b..c72e06dc2 100644
--- a/plugins/archlinux/archlinux.plugin.zsh
+++ b/plugins/archlinux/archlinux.plugin.zsh
@@ -171,14 +171,13 @@ function paclist() {
}
function pacdisowned() {
- emulate -L zsh
-
+ local tmp db fs
tmp=${TMPDIR-/tmp}/pacman-disowned-$UID-$$
db=$tmp/db
fs=$tmp/fs
mkdir "$tmp"
- trap 'rm -rf "$tmp"' EXIT
+ trap 'rm -rf "$tmp"' EXIT
pacman -Qlq | sort -u > "$db"
@@ -189,15 +188,14 @@ function pacdisowned() {
}
function pacmanallkeys() {
- emulate -L zsh
curl -s https://www.archlinux.org/people/{developers,trustedusers}/ | \
awk -F\" '(/pgp.mit.edu/) { sub(/.*search=0x/,""); print $1}' | \
xargs sudo pacman-key --recv-keys
}
function pacmansignkeys() {
- emulate -L zsh
- for key in $*; do
+ local key
+ for key in $@; do
sudo pacman-key --recv-keys $key
sudo pacman-key --lsign-key $key
printf 'trust\n3\n' | sudo gpg --homedir /etc/pacman.d/gnupg \
@@ -207,13 +205,13 @@ function pacmansignkeys() {
if (( $+commands[xdg-open] )); then
function pacweb() {
- pkg="$1"
- infos="$(LANG=C pacman -Si "$pkg")"
+ local pkg="$1"
+ local infos="$(LANG=C pacman -Si "$pkg")"
if [[ -z "$infos" ]]; then
return
fi
- repo="$(grep -m 1 '^Repo' <<< "$infos" | grep -oP '[^ ]+$')"
- arch="$(grep -m 1 '^Arch' <<< "$infos" | grep -oP '[^ ]+$')"
+ local repo="$(grep -m 1 '^Repo' <<< "$infos" | grep -oP '[^ ]+$')"
+ local arch="$(grep -m 1 '^Arch' <<< "$infos" | grep -oP '[^ ]+$')"
xdg-open "https://www.archlinux.org/packages/$repo/$arch/$pkg/" &>/dev/null
}
fi
diff --git a/plugins/command-not-found/command-not-found.plugin.zsh b/plugins/command-not-found/command-not-found.plugin.zsh
index 81d76e638..aea1e1b4c 100644
--- a/plugins/command-not-found/command-not-found.plugin.zsh
+++ b/plugins/command-not-found/command-not-found.plugin.zsh
@@ -2,7 +2,22 @@
# as seen in https://www.porcheron.info/command-not-found-for-zsh/
# this is installed in Ubuntu
-[[ -e /etc/zsh_command_not_found ]] && source /etc/zsh_command_not_found
+if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
+ function command_not_found_handler {
+ # check because c-n-f could've been removed in the meantime
+ if [ -x /usr/lib/command-not-found ]; then
+ /usr/lib/command-not-found -- "$1"
+ return $?
+ elif [ -x /usr/share/command-not-found/command-not-found ]; then
+ /usr/share/command-not-found/command-not-found -- "$1"
+ return $?
+ else
+ printf "zsh: command not found: %s\n" "$1" >&2
+ return 127
+ fi
+ return 0
+ }
+fi
# Arch Linux command-not-found support, you must have package pkgfile installed
# https://wiki.archlinux.org/index.php/Pkgfile#.22Command_not_found.22_hook
@@ -10,13 +25,12 @@
# Fedora command-not-found support
if [ -f /usr/libexec/pk-command-not-found ]; then
- command_not_found_handler () {
+ command_not_found_handler() {
runcnf=1
retval=127
[ ! -S /var/run/dbus/system_bus_socket ] && runcnf=0
[ ! -x /usr/libexec/packagekitd ] && runcnf=0
- if [ $runcnf -eq 1 ]
- then
+ if [ $runcnf -eq 1 ]; then
/usr/libexec/pk-command-not-found $@
retval=$?
fi
@@ -32,7 +46,7 @@ fi
# NixOS command-not-found support
if [ -x /run/current-system/sw/bin/command-not-found ]; then
- command_not_found_handler () {
+ command_not_found_handler() {
/run/current-system/sw/bin/command-not-found $@
}
fi
diff --git a/plugins/common-aliases/README.md b/plugins/common-aliases/README.md
index d198a29ac..b6f34cb54 100644
--- a/plugins/common-aliases/README.md
+++ b/plugins/common-aliases/README.md
@@ -40,11 +40,13 @@ plugins=(... common-aliases)
| Alias | Command | Description |
|-------|-----------------------------------------------------|-----------------------------------------|
-| fd | `find . -type d -name` | Find a directory with the given name |
+| fd\* | `find . -type d -name` | Find a directory with the given name |
| ff | `find . -type f -name` | Find a file with the given name |
| grep | `grep --color` | Searches for a query string |
| sgrep | `grep -R -n -H -C 5 --exclude-dir={.git,.svn,CVS}` | Useful for searching within files |
+\* Only if the [`fd`](https://github.com/sharkdp/fd) command isn't installed.
+
### Other Aliases
| Alias | Command | Description |
diff --git a/plugins/common-aliases/common-aliases.plugin.zsh b/plugins/common-aliases/common-aliases.plugin.zsh
index a9d4f1a3d..4e5ff848f 100644
--- a/plugins/common-aliases/common-aliases.plugin.zsh
+++ b/plugins/common-aliases/common-aliases.plugin.zsh
@@ -34,7 +34,7 @@ alias -g P="2>&1| pygmentize -l pytb"
alias dud='du -d 1 -h'
alias duf='du -sh *'
-alias fd='find . -type d -name'
+(( $+commands[fd] )) || alias fd='find . -type d -name'
alias ff='find . -type f -name'
alias h='history'
diff --git a/plugins/composer/composer.plugin.zsh b/plugins/composer/composer.plugin.zsh
index 75b03ffe7..218a13e5f 100644
--- a/plugins/composer/composer.plugin.zsh
+++ b/plugins/composer/composer.plugin.zsh
@@ -51,7 +51,7 @@ alias cget='curl -s https://getcomposer.org/installer | php'
# Add Composer's global binaries to PATH, using Composer if available.
if (( $+commands[composer] )); then
- autoload -Uz _store_cache _retrieve_cache
+ autoload -Uz _store_cache _retrieve_cache _cache_invalid
_retrieve_cache composer
diff --git a/plugins/genpass/README.md b/plugins/genpass/README.md
new file mode 100644
index 000000000..a5ff4a876
--- /dev/null
+++ b/plugins/genpass/README.md
@@ -0,0 +1,66 @@
+# genpass
+
+This plugin provides three unique password generators for ZSH. Each generator
+has at least a 128-bit security margin and generates passwords from the
+cryptographically secure `/dev/urandom`. Each generator can also take an
+optional numeric argument to generate multiple passwords.
+
+To use it from an interactive ZSH, add `genpass` to the plugins array in your
+zshrc file:
+
+ plugins=(... genpass)
+
+You can also invoke password generators directly (they are implemented as
+standalone executable files), which can be handy when you need to generate
+passwords in a script:
+
+ ~/.oh-my-zsh/plugins/genpass/genpass-apple 3
+
+## genpass-apple
+
+Generates a pronounceable pseudoword passphrase of the "cvccvc" consonant/vowel
+syntax, inspired by [Apple's iCloud Keychain password generator][1]. Each
+password has exactly 1 digit placed at the edge of a "word" and exactly 1
+capital letter to satisfy most password security requirements.
+
+ % genpass-apple
+ gelcyv-foqtam-fotqoh-viMleb-lexduv-6ixfuk
+
+ % genpass-apple 3
+ japvyz-qyjti4-kajrod-nubxaW-hukkan-dijcaf
+ vydpig-fucnul-3ukpog-voggom-zygNad-jepgad
+ zocmez-byznis-hegTaj-jecdyq-qiqmiq-5enwom
+
+[1]: https://developer.apple.com/password-rules/
+
+## genpass-monkey
+
+Generates visually unambiguous random meaningless strings using [Crockford's
+base32][2].
+
+ % genpass-monkey
+ xt7gn976e7jj3fstgpy27330x3
+
+ % genpass-monkey 3
+ n1qqwtzgejwgqve9yzf2gxvx4m
+ r2n3f5s6vbqs2yx7xjnmahqewy
+ 296w9y9rts3p5r9yay0raek8e5
+
+[2]: https://www.crockford.com/base32.html
+
+## genpass-xkcd
+
+Generates passphrases from `/usr/share/dict/words` inspired by the [famous (and
+slightly misleading) XKCD comic][3]. Each passphrase is prepended with a digit
+showing the number of words in the passphrase to adhere to password security
+requirements that require digits. Each word is 6 characters or less.
+
+ % genpass-xkcd
+ 9-eaten-Slav-rife-aired-hill-cordon-splits-welsh-napes
+
+ % genpass-xkcd 3
+ 9-worker-Vlad-horde-shrubs-smite-thwart-paw-alters-prawns
+ 9-tutors-stink-rhythm-junk-snappy-hooray-barbs-mewl-clomp
+ 9-vital-escape-Angkor-Huff-wet-Mayra-abbés-putts-guzzle
+
+[3]: https://xkcd.com/936/
diff --git a/plugins/genpass/genpass-apple b/plugins/genpass/genpass-apple
new file mode 100755
index 000000000..963ab6447
--- /dev/null
+++ b/plugins/genpass/genpass-apple
@@ -0,0 +1,79 @@
+#!/usr/bin/env zsh
+#
+# Usage: genpass-apple [NUM]
+#
+# Generate a password made of 6 pseudowords of 6 characters each
+# with the security margin of at least 128 bits.
+#
+# Example password: xudmec-4ambyj-tavric-mumpub-mydVop-bypjyp
+#
+# If given a numerical argument, generate that many passwords.
+
+emulate -L zsh -o no_unset -o warn_create_global -o warn_nested_var
+
+if [[ ARGC -gt 1 || ${1-1} != ${~:-<1-$((16#7FFFFFFF))>} ]]; then
+ print -ru2 -- "usage: $0 [NUM]"
+ return 1
+fi
+
+zmodload zsh/system zsh/mathfunc || return
+
+{
+ local -r vowels=aeiouy
+ local -r consonants=bcdfghjklmnpqrstvwxz
+ local -r digits=0123456789
+
+ # Sets REPLY to a uniformly distributed random number in [1, $1].
+ # Requires: $1 <= 256.
+ function -$0-rand() {
+ local c
+ while true; do
+ sysread -s1 c || return
+ # Avoid bias towards smaller numbers.
+ (( #c < 256 / $1 * $1 )) && break
+ done
+ typeset -g REPLY=$((#c % $1 + 1))
+ }
+
+ local REPLY chars
+
+ repeat ${1-1}; do
+ # Generate 6 pseudowords of the form cvccvc where c and v
+ # denote random consonants and vowels respectively.
+ local words=()
+ repeat 6; do
+ words+=('')
+ repeat 2; do
+ for chars in $consonants $vowels $consonants; do
+ -$0-rand $#chars || return
+ words[-1]+=$chars[REPLY]
+ done
+ done
+ done
+
+ local pwd=${(j:-:)words}
+
+ # Replace either the first or the last character in one of
+ # the words with a random digit.
+ -$0-rand $#digits || return
+ local digit=$digits[REPLY]
+ -$0-rand $((2 * $#words)) || return
+ pwd[REPLY/2*7+2*(REPLY%2)-1]=$digit
+
+ # Convert one lower-case character to upper case.
+ while true; do
+ -$0-rand $#pwd || return
+ [[ $vowels$consonants == *$pwd[REPLY]* ]] && break
+ done
+ # NOTE: We aren't using ${(U)c} here because its results are
+ # locale-dependent. For example, when upper-casing 'i' in Turkish
+ # locale we would get 'İ', a.k.a. latin capital letter i with dot
+ # above. We could set LC_CTYPE=C locally but then we would run afoul
+ # of this zsh bug: https://www.zsh.org/mla/workers/2020/msg00588.html.
+ local c=$pwd[REPLY]
+ printf -v c '%o' $((#c - 32))
+ printf "%s\\$c%s\\n" "$pwd[1,REPLY-1]" "$pwd[REPLY+1,-1]" || return
+ done
+} always {
+ unfunction -m -- "-${(b)0}-*"
+} </dev/urandom
diff --git a/plugins/genpass/genpass-monkey b/plugins/genpass/genpass-monkey
new file mode 100755
index 000000000..94ff5e131
--- /dev/null
+++ b/plugins/genpass/genpass-monkey
@@ -0,0 +1,32 @@
+#!/usr/bin/env zsh
+#
+# Usage: genpass-monkey [NUM]
+#
+# Generate a password made of 26 alphanumeric characters
+# with the security margin of at least 128 bits.
+#
+# Example password: nz5ej2kypkvcw0rn5cvhs6qxtm
+#
+# If given a numerical argument, generate that many passwords.
+
+emulate -L zsh -o no_unset -o warn_create_global -o warn_nested_var
+
+if [[ ARGC -gt 1 || ${1-1} != ${~:-<1-$((16#7FFFFFFF))>} ]]; then
+ print -ru2 -- "usage: $0 [NUM]"
+ return 1
+fi
+
+zmodload zsh/system || return
+
+{
+ local -r chars=abcdefghjkmnpqrstvwxyz0123456789
+ local c
+ repeat ${1-1}; do
+ repeat 26; do
+ sysread -s1 c || return
+ # There is uniform because $#chars divides 256.
+ print -rn -- $chars[#c%$#chars+1]
+ done
+ print
+ done
+} </dev/urandom
diff --git a/plugins/genpass/genpass-xkcd b/plugins/genpass/genpass-xkcd
new file mode 100755
index 000000000..a486ccb40
--- /dev/null
+++ b/plugins/genpass/genpass-xkcd
@@ -0,0 +1,68 @@
+#!/usr/bin/env zsh
+#
+# Usage: genpass-xkcd [NUM]
+#
+# Generate a password made of words from /usr/share/dict/words
+# with the security margin of at least 128 bits.
+#
+# Example password: 9-mien-flood-Patti-buxom-dozes-ickier-pay-ailed-Foster
+#
+# If given a numerical argument, generate that many passwords.
+#
+# The name of this utility is a reference to https://xkcd.com/936/.
+
+emulate -L zsh -o no_unset -o warn_create_global -o warn_nested_var -o extended_glob
+
+if [[ ARGC -gt 1 || ${1-1} != ${~:-<1-$((16#7FFFFFFF))>} ]]; then
+ print -ru2 -- "usage: $0 [NUM]"
+ return 1
+fi
+
+zmodload zsh/system zsh/mathfunc || return
+
+local -r dict=/usr/share/dict/words
+
+if [[ ! -e $dict ]]; then
+ print -ru2 -- "$0: file not found: $dict"
+ return 1
+fi
+
+# Read all dictionary words and leave only those made of 1-6 characters.
+local -a words
+words=(${(M)${(f)"$(<$dict)"}:#[a-zA-Z](#c1,6)}) || return
+
+if (( $#words < 2 )); then
+ print -ru2 -- "$0: not enough suitable words in $dict"
+ return 1
+fi
+
+if (( $#words > 16#7FFFFFFF )); then
+ print -ru2 -- "$0: too many words in $dict"
+ return 1
+fi
+
+# Figure out how many words we need for 128 bits of security margin.
+# Each word adds log2($#words) bits.
+local -i n=$((ceil(128. / log2($#words))))
+
+{
+ local c
+ repeat ${1-1}; do
+ print -rn -- $n
+ repeat $n; do
+ while true; do
+ # Generate a random number in [0, 2**31).
+ local -i rnd=0
+ repeat 4; do
+ sysread -s1 c || return
+ (( rnd = (~(1 << 23) & rnd) << 8 | #c ))
+ done
+ # Avoid bias towards words in the beginning of the list.
+ (( rnd < 16#7FFFFFFF / $#words * $#words )) || continue
+ print -rn -- -$words[rnd%$#words+1]
+ break
+ done
+ done
+ print
+ done
+} </dev/urandom
diff --git a/plugins/genpass/genpass.plugin.zsh b/plugins/genpass/genpass.plugin.zsh
new file mode 100644
index 000000000..a0ea841cd
--- /dev/null
+++ b/plugins/genpass/genpass.plugin.zsh
@@ -0,0 +1 @@
+autoload -Uz genpass-apple genpass-monkey genpass-xkcd
diff --git a/plugins/git-auto-fetch/README.md b/plugins/git-auto-fetch/README.md
index 35f3c2f71..e96ab42a3 100644
--- a/plugins/git-auto-fetch/README.md
+++ b/plugins/git-auto-fetch/README.md
@@ -1,26 +1,29 @@
# Git auto-fetch
-Automatically fetches all changes from all remotes while you are working in git-initialized directory.
+Automatically fetches all changes from all remotes while you are working in a git-initialized directory.
-#### Usage
-
-Add `git-auto-fetch` to the plugins array in your zshrc file:
+To use it, add `git-auto-fetch` to the plugins array in your zshrc file:
```shell
plugins=(... git-auto-fetch)
```
-Every time you launch a command in your shell all remotes will be fetched in background.
-By default autofetch will be triggered only if last fetch was done at least 60 seconds ago.
-You can change fetch interval in your .zshrc:
-```
-GIT_AUTO_FETCH_INTERVAL=1200 #in seconds
+## Usage
+
+Every time the command prompt is shown all remotes will be fetched in the background. By default,
+`git-auto-fetch` will be triggered only if the last auto-fetch was done at least 60 seconds ago.
+You can change the fetch interval in your .zshrc:
+
+```sh
+GIT_AUTO_FETCH_INTERVAL=1200 # in seconds
```
-Log of `git fetch --all` will be saved into `.git/FETCH_LOG`
+A log of `git fetch --all` will be saved in `.git/FETCH_LOG`.
+
+## Toggle auto-fetch per folder
-#### Toggle auto fetch per folder
-If you are using mobile connection or for any other reason you can disable git-auto-fetch for any folder:
+If you are using a mobile connection or for any other reason you can disable git-auto-fetch
+for any folder:
```shell
$ cd to/your/project
@@ -29,3 +32,19 @@ disabled
$ git-auto-fetch
enabled
```
+
+## Caveats
+
+Automatically fetching all changes defeats the purpose of `git push --force-with-lease`,
+and makes it behave like `git push --force` in some cases. For example:
+
+Consider that you made some changes and possibly rebased some stuff, which means you'll
+need to use `--force-with-lease` to overwrite the remote history of a branch. Between the
+time when you make the changes (maybe do a `git log`) and the time when you `git push`,
+it's possible that someone else updates the branch you're working on.
+
+If `git-auto-fetch` triggers then, you'll have fetched the remote changes without knowing
+it, and even though you're running the push with `--force-with-lease`, git will overwrite
+the recent changes because you already have them in your local repository. The
+[`git push --force-with-lease` docs](https://git-scm.com/docs/git-push) talk about possible
+solutions to this problem.
diff --git a/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh b/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh
index 5c42c21a7..0da84f2f5 100644
--- a/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh
+++ b/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh
@@ -1,36 +1,61 @@
-GIT_AUTO_FETCH_INTERVAL=${GIT_AUTO_FETCH_INTERVAL:=60}
+# Default auto-fetch interval: 60 seconds
+: ${GIT_AUTO_FETCH_INTERVAL:=60}
+
+# Necessary for the git-fetch-all function
+zmodload zsh/datetime zsh/stat
function git-fetch-all {
- (`command git rev-parse --is-inside-work-tree 2>/dev/null` &&
- dir=`command git rev-parse --git-dir` &&
- [[ ! -f $dir/NO_AUTO_FETCH ]] &&
- (( `date +%s` - `date -r $dir/FETCH_LOG +%s 2>/dev/null || echo 0` > $GIT_AUTO_FETCH_INTERVAL )) &&
- GIT_SSH_COMMAND="command ssh -o BatchMode=yes" \
- command git fetch --all 2>/dev/null &>! $dir/FETCH_LOG &)
+ (
+ # Get git root directory
+ if ! gitdir="$(command git rev-parse --git-dir 2>/dev/null)"; then
+ return 0
+ fi
+
+ # Do nothing if auto-fetch disabled
+ if [[ -z "$gitdir" || -f "$gitdir/NO_AUTO_FETCH" ]]; then
+ return 0
+ fi
+
+ # Get time (seconds) when auto-fetch was last run
+ lastrun="$(zstat +mtime "$gitdir/FETCH_LOG" 2>/dev/null || echo 0)"
+ # Do nothing if not enough time has passed since last auto-fetch
+ if (( EPOCHSECONDS - lastrun < $GIT_AUTO_FETCH_INTERVAL )); then
+ return 0
+ fi
+
+ # Fetch all remotes (avoid ssh passphrase prompt)
+ GIT_SSH_COMMAND="command ssh -o BatchMode=yes" \
+ command git fetch --all 2>/dev/null &>! "$gitdir/FETCH_LOG"
+ ) &|
}
function git-auto-fetch {
- `command git rev-parse --is-inside-work-tree 2>/dev/null` || return
- guard="`command git rev-parse --git-dir`/NO_AUTO_FETCH"
+ # Do nothing if not in a git repository
+ command git rev-parse --is-inside-work-tree &>/dev/null || return 0
- (rm $guard 2>/dev/null &&
- echo "${fg_bold[green]}enabled${reset_color}") ||
- (touch $guard &&
- echo "${fg_bold[red]}disabled${reset_color}")
+ # Remove or create guard file depending on its existence
+ local guard="$(command git rev-parse --git-dir)/NO_AUTO_FETCH"
+ if [[ -f "$guard" ]]; then
+ command rm "$guard" && echo "${fg_bold[green]}enabled${reset_color}"
+ else
+ command touch "$guard" && echo "${fg_bold[red]}disabled${reset_color}"
+ fi
}
-# Override zle-line-init if it exists
-if (( $+functions[zle-line-init] )); then
- eval "override-git-auto-fetch-$(declare -f zle-line-init)"
-
- function zle-line-init () {
- git-fetch-all
- override-git-auto-fetch-zle-line-init
- }
-else
- function zle-line-init () {
- git-fetch-all
- }
-fi
-
-zle -N zle-line-init
+# zle-line-init widget (don't redefine if already defined)
+(( ! ${+functions[_git-auto-fetch_zle-line-init]} )) || return 0
+
+case "$widgets[zle-line-init]" in
+ # Simply define the function if zle-line-init doesn't yet exist
+ builtin|"") function _git-auto-fetch_zle-line-init() {
+ git-fetch-all
+ } ;;
+ # Override the current zle-line-init widget, calling the old one
+ user:*) zle -N _git-auto-fetch_orig_zle-line-init "${widgets[zle-line-init]#user:}"
+ function _git-auto-fetch_zle-line-init() {
+ git-fetch-all
+ zle _git-auto-fetch_orig_zle-line-init -- "$@"
+ } ;;
+esac
+
+zle -N zle-line-init _git-auto-fetch_zle-line-init
diff --git a/plugins/git-prompt/gitstatus.py b/plugins/git-prompt/gitstatus.py
index 300365d71..bf3173614 100644
--- a/plugins/git-prompt/gitstatus.py
+++ b/plugins/git-prompt/gitstatus.py
@@ -11,11 +11,11 @@ def get_tagname_or_hash():
"""return tagname if exists else hash"""
# get hash
hash_cmd = ['git', 'rev-parse', '--short', 'HEAD']
- hash_ = check_output(hash_cmd).strip()
+ hash_ = check_output(hash_cmd).decode('utf-8').strip()
# get tagname
tags_cmd = ['git', 'for-each-ref', '--points-at=HEAD', '--count=2', '--sort=-version:refname', '--format=%(refname:short)', 'refs/tags']
- tags = check_output(tags_cmd).split()
+ tags = check_output(tags_cmd).decode('utf-8').split()
if tags:
return tags[0] + ('+' if len(tags) > 1 else '')
diff --git a/plugins/git/git.plugin.zsh b/plugins/git/git.plugin.zsh
index bf2619976..e32136f15 100644
--- a/plugins/git/git.plugin.zsh
+++ b/plugins/git/git.plugin.zsh
@@ -31,6 +31,7 @@ function work_in_progress() {
# Check if main exists and use instead of master
function git_main_branch() {
+ command git rev-parse --git-dir &>/dev/null || return
local branch
for branch in main trunk; do
if command git show-ref -q --verify refs/heads/$branch; then
diff --git a/plugins/grc/README.md b/plugins/grc/README.md
new file mode 100644
index 000000000..dfda41466
--- /dev/null
+++ b/plugins/grc/README.md
@@ -0,0 +1,37 @@
+# Generic Colouriser plugin
+
+This plugin adds wrappers for commands supported by [Generic Colouriser](https://github.com/garabik/grc):
+
+To use it, add `grc` to the plugins array in your zshrc file:
+
+```zsh
+plugins=(... grc)
+```
+
+## Commands
+
+The following commands are wrapped by `grc` so that their output is automatically colored:
+
+- `cc`
+- `configure`
+- `cvs`
+- `df`
+- `diff`
+- `dig`
+- `gcc`
+- `gmake`
+- `ifconfig`
+- `iwconfig`
+- `last`
+- `ldap`
+- `make`
+- `mount`
+- `mtr`
+- `netstat`
+- `ping`
+- `ping6`
+- `ps`
+- `traceroute`
+- `traceroute6`
+- `wdiff`
+- `whois`
diff --git a/plugins/grc/grc.plugin.zsh b/plugins/grc/grc.plugin.zsh
new file mode 100644
index 000000000..6a52ec568
--- /dev/null
+++ b/plugins/grc/grc.plugin.zsh
@@ -0,0 +1,44 @@
+# Adapted from: https://github.com/garabik/grc/blob/master/grc.zsh
+
+if [[ "$TERM" = dumb ]] || (( ! $+commands[grc] )); then
+ return
+fi
+
+# Supported commands
+cmds=(
+ cc
+ configure
+ cvs
+ df
+ diff
+ dig
+ gcc
+ gmake
+ ifconfig
+ iwconfig
+ last
+ ldap
+ make
+ mount
+ mtr
+ netstat
+ ping
+ ping6
+ ps
+ traceroute
+ traceroute6
+ wdiff
+ whois
+)
+
+# Set alias for supported commands
+for cmd in $cmds; do
+ if (( $+commands[$cmd] )); then
+ eval "function $cmd {
+ grc --colour=auto \"${commands[$cmd]}\" \"\$@\"
+ }"
+ fi
+done
+
+# Clean up variables
+unset cmds cmd
diff --git a/plugins/hanami/README.md b/plugins/hanami/README.md
index 3ac8defbb..c9e09f4f2 100644
--- a/plugins/hanami/README.md
+++ b/plugins/hanami/README.md
@@ -1,32 +1,45 @@
-# Hanami Plugin #
-This plugin adds convenient ways to work with [Hanami](https://hanamirb.org/) via console.
+# Hanami Plugin
+
+This plugin adds convenient aliases to work with [Hanami](https://hanamirb.org/) via console.
It's inspired by Rails plugin, so if you've used it, you'll feel like home.
-## Usage ##
+To use it, add `hanami` to the plugins array in your zshrc file:
+
+```zsh
+plugins=(... hanami)
+```
+
+## Usage
For example, type `hc` into your console when you're within Hanami project directory to run
the application console. Have a look at available shortcuts below. You can read more about
these commands [on the official website](https://hanamirb.org/guides/command-line/applications/).
-## Aliases ##
-
-| Alias | Command | Description |
-|-------|---------------------------|---------------------------------------------------------|
-| HED | HANAMI_ENV=development | Set environment variable HANAMI_ENV to development |
-| HEP | HANAMI_ENV=production | Set environment variable HANAMI_ENV to production |
-| HET | HANAMI_ENV=test | Set environment variable HANAMI_ENV to test |
-| hc | hanami console | Run application console |
-| hd | hanami destroy | Remove specified hanami resource |
-| hg | hanami generate | Create specified hanami resource |
-| hgm | hanami generate migration | Create migration file |
-| hs | hanami server | Launch server with hanami application |
-| hsp | hanami server -p | Launch server with specified port |
-| hr | hanami routes | List application routes |
-| hdc | hanami db create | Create application database |
-| hdd | hanami db drop | Delete application database |
-| hdp | hanami db prepare | Prepare database for the current environment |
-| hda | hanami db apply | Recreates a fresh schema after migrations (destructive) |
-| hdv | hanami db version | Print current database version |
-| hdrs | hdd && hdp | Drop and recreate application database |
-| hdtp | HET hdp | Actualize test environment database |
-| hrg | hr &#124; grep | Grep hanami routes with specified pattern |
+## Aliases
+
+| Alias | Command | Description |
+|-------|-----------------------------|---------------------------------------------------------|
+| HED\* | `HANAMI_ENV=development` | Set environment variable HANAMI_ENV to development |
+| HEP\* | `HANAMI_ENV=production` | Set environment variable HANAMI_ENV to production |
+| HET\* | `HANAMI_ENV=test` | Set environment variable HANAMI_ENV to test |
+| hc | `hanami console` | Run application console |
+| hd | `hanami destroy` | Remove specified hanami resource |
+| hg | `hanami generate` | Create specified hanami resource |
+| hgm | `hanami generate migration` | Create migration file |
+| hs | `hanami server` | Launch server with hanami application |
+| hsp | `hanami server -p` | Launch server with specified port |
+| hr | `hanami routes` | List application routes |
+| hdc | `hanami db create` | Create application database |
+| hdd | `hanami db drop` | Delete application database |
+| hdp | `hanami db prepare` | Prepare database for the current environment |
+| hda | `hanami db apply` | Recreates a fresh schema after migrations (destructive) |
+| hdv | `hanami db version` | Print current database version |
+| hdrs | `hdd && hdp` | Drop and recreate application database |
+| hdtp | `HET hdp` | Actualize test environment database |
+| hrg | `hr | grep` | Grep hanami routes with specified pattern |
+
+\* You should use these at the beginning of a command, for example:
+
+```console
+$ HED hdd # equivalent to 'HANAMI_ENV=development hanami db drop'
+```
diff --git a/plugins/hanami/hanami.plugin.zsh b/plugins/hanami/hanami.plugin.zsh
index 349c42cae..42143b428 100644
--- a/plugins/hanami/hanami.plugin.zsh
+++ b/plugins/hanami/hanami.plugin.zsh
@@ -1,6 +1,6 @@
-alias -g HED='HANAMI_ENV=development'
-alias -g HEP='HANAMI_ENV=production'
-alias -g HET='HANAMI_ENV=test'
+alias HED='HANAMI_ENV=development '
+alias HEP='HANAMI_ENV=production '
+alias HET='HANAMI_ENV=test '
alias hc='hanami console'
alias hd='hanami destroy'
diff --git a/plugins/magic-enter/magic-enter.plugin.zsh b/plugins/magic-enter/magic-enter.plugin.zsh
index 2d4d578b6..55b893535 100644
--- a/plugins/magic-enter/magic-enter.plugin.zsh
+++ b/plugins/magic-enter/magic-enter.plugin.zsh
@@ -1,27 +1,38 @@
-# Bind quick stuff to enter!
-#
-# Pressing enter in a git directory runs `git status`
-# in other directories `ls`
-magic-enter () {
- # If commands are not already set, use the defaults
- [ -z "$MAGIC_ENTER_GIT_COMMAND" ] && MAGIC_ENTER_GIT_COMMAND="git status -u ."
- [ -z "$MAGIC_ENTER_OTHER_COMMAND" ] && MAGIC_ENTER_OTHER_COMMAND="ls -lh ."
+# Default commands
+: ${MAGIC_ENTER_GIT_COMMAND:="git status -u ."} # run when in a git repository
+: ${MAGIC_ENTER_OTHER_COMMAND:="ls -lh ."} # run anywhere else
- if [[ -z $BUFFER ]]; then
- echo ""
- if git rev-parse --is-inside-work-tree &>/dev/null; then
- eval "$MAGIC_ENTER_GIT_COMMAND"
- else
- eval "$MAGIC_ENTER_OTHER_COMMAND"
- fi
- zle redisplay
+magic-enter() {
+ # Only run MAGIC_ENTER commands when in PS1 and command line is empty
+ # http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#User_002dDefined-Widgets
+ if [[ -n "$BUFFER" || "$CONTEXT" != start ]]; then
+ return
+ fi
+
+ if command git rev-parse --is-inside-work-tree &>/dev/null; then
+ BUFFER="$MAGIC_ENTER_GIT_COMMAND"
else
- zle accept-line
+ BUFFER="$MAGIC_ENTER_OTHER_COMMAND"
fi
}
-zle -N magic-enter
+# Wrapper for the accept-line zle widget (run when pressing Enter)
+
+# If the wrapper already exists don't redefine it
+(( ! ${+functions[_magic-enter_accept-line]} )) || return 0
+
+case "$widgets[accept-line]" in
+ # Override the current accept-line widget, calling the old one
+ user:*) zle -N _magic-enter_orig_accept-line "${widgets[accept-line]#user:}"
+ function _magic-enter_accept-line() {
+ magic-enter
+ zle _magic-enter_orig_accept-line -- "$@"
+ } ;;
+ # If no user widget defined, call the original accept-line widget
+ builtin) function _magic-enter_accept-line() {
+ magic-enter
+ zle .accept-line
+ } ;;
+esac
-bindkey -M emacs "^M" magic-enter
-bindkey -M vicmd "^M" magic-enter
-bindkey -M viins "^M" magic-enter
+zle -N accept-line _magic-enter_accept-line
diff --git a/plugins/wp-cli/README.md b/plugins/wp-cli/README.md
index 43c41eb53..c4993ab4c 100644
--- a/plugins/wp-cli/README.md
+++ b/plugins/wp-cli/README.md
@@ -1,107 +1,109 @@
# WP-CLI
-**Maintainer:** [joshmedeski](https://github.com/joshmedeski)
-
-WordPress Command Line Interface (https://wp-cli.org/)
-
-WP-CLI is a set of command-line tools for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser.
-
-This plugin adds [tab completion](https://wp-cli.org/#tab-completions) for `wp-cli` as well as several aliases.
-
-## List of Aliases
-
-### Core
-- wpcc='wp core config'
-- wpcd='wp core download'
-- wpci='wp core install'
-- wpcii='wp core is-installed'
-- wpcmc='wp core multisite-convert'
-- wpcmi='wp core multisite-install'
-- wpcu='wp core update'
-- wpcudb='wp core update-db'
-- wpcvc='wp core verify-checksums'
-
-### Cron
-- wpcre='wp cron event'
-- wpcrs='wp cron schedule'
-- wpcrt='wp cron test'
+The [WordPress CLI](https://wp-cli.org/) is a command-line tool for managing WordPress installations. You can update plugins, set up multisite installs and much more, without using a web browser.
-### Menu
-- wpmc='wp menu create'
-- wpmd='wp menu delete'
-- wpmi='wp menu item'
-- wpml='wp menu list'
-- wpmlo='wp menu location'
+This plugin adds [tab completion](https://wp-cli.org/#tab-completions) for `wp-cli` as well as several aliases for commonly used commands.
-### Plugin
-- wppa='activate'
-- wppda='deactivate'
-- wppd='delete'
-- wppg='get'
-- wppi='install'
-- wppis='is-installed'
-- wppl='list'
-- wppp='path'
-- wpps='search'
-- wppst='status'
-- wppt='toggle'
-- wppun='uninstall'
-- wppu='update'
+To use it, add `wp-cli` to the plugins array in your zshrc file:
-### Post
-- wppoc='wp post create'
-- wppod='wp post delete'
-- wppoe='wp post edit'
-- wppogen='wp post generate'
-- wppog='wp post get'
-- wppol='wp post list'
-- wppom='wp post meta'
-- wppou='wp post update'
-- wppourl='wp post url'
+```zsh
+plugins=(... wp-cli)
+```
-### Sidebar
-- wpsbl='wp sidebar list'
-
-### Theme
-- wpta='wp theme activate'
-- wptd='wp theme delete'
-- wptdis='wp theme disable'
-- wpte='wp theme enable'
-- wptg='wp theme get'
-- wpti='wp theme install'
-- wptis='wp theme is-installed'
-- wptl='wp theme list'
-- wptm='wp theme mod'
-- wptp='wp theme path'
-- wpts='wp theme search'
-- wptst='wp theme status'
-- wptu='wp theme update'
-
-### User
-- wpuac='wp user add-cap'
-- wpuar='wp user add-role'
-- wpuc='wp user create'
-- wpud='wp user delete'
-- wpugen='wp user generate'
-- wpug='wp user get'
-- wpui='wp user import-csv'
-- wpul='wp user list'
-- wpulc='wp user list-caps'
-- wpum='wp user meta'
-- wpurc='wp user remove-cap'
-- wpurr='wp user remove-role'
-- wpusr='wp user set-role'
-- wpuu='wp user update'
-
-### Widget
-- wpwa='wp widget add'
-- wpwda='wp widget deactivate'
-- wpwd='wp widget delete'
-- wpwl='wp widget list'
-- wpwm='wp widget move'
-- wpwu='wp widget update'
-
-The entire list of wp-cli commands can be found here: https://wp-cli.org/commands/
-
-I only included the commands that are most used. Please feel free to contribute to this project if you want more commands.
+**Maintainer:** [joshmedeski](https://github.com/joshmedeski)
+## Aliases
+
+The entire list of `wp-cli` commands can be found here: https://developer.wordpress.org/cli/commands/
+
+| Alias | Command |
+|-----------|-----------------------------|
+| **Core** |
+| `wpcc` | `wp core config` |
+| `wpcd` | `wp core download` |
+| `wpci` | `wp core install` |
+| `wpcii` | `wp core is-installed` |
+| `wpcmc` | `wp core multisite-convert` |
+| `wpcmi` | `wp core multisite-install` |
+| `wpcu` | `wp core update` |
+| `wpcudb` | `wp core update-db` |
+| `wpcvc` | `wp core verify-checksums` |
+| **Cron** |
+| `wpcre` | `wp cron event` |
+| `wpcrs` | `wp cron schedule` |
+| `wpcrt` | `wp cron test` |
+| **Database** |
+| `wpdbe` | `wp db export` |
+| `wpdbi` | `wp db import` |
+| `wpdbcr` | `wp db create` |
+| `wpdbs` | `wp db search` |
+| `wpdbch` | `wp db check` |
+| `wpdbr` | `wp db repair` |
+| **Menu** |
+| `wpmc` | `wp menu create` |
+| `wpmd` | `wp menu delete` |
+| `wpmi` | `wp menu item` |
+| `wpml` | `wp menu list` |
+| `wpmlo` | `wp menu location` |
+| **Plugin** |
+| `wppa` | `wp plugin activate` |
+| `wppda` | `wp plugin deactivate` |
+| `wppd` | `wp plugin delete` |
+| `wppg` | `wp plugin get` |
+| `wppi` | `wp plugin install` |
+| `wppis` | `wp plugin is-installed` |
+| `wppl` | `wp plugin list` |
+| `wppp` | `wp plugin path` |
+| `wpps` | `wp plugin search` |
+| `wppst` | `wp plugin status` |
+| `wppt` | `wp plugin toggle` |
+| `wppun` | `wp plugin uninstall` |
+| `wppu` | `wp plugin update` |
+| **Post** |
+| `wppoc` | `wp post create` |
+| `wppod` | `wp post delete` |
+| `wppoe` | `wp post edit` |
+| `wppogen` | `wp post generate` |
+| `wppog` | `wp post get` |
+| `wppol` | `wp post list` |
+| `wppom` | `wp post meta` |
+| `wppou` | `wp post update` |
+| `wppourl` | `wp post url` |
+| **Sidebar** |
+| `wpsbl` | `wp sidebar list` |
+| **Theme** |
+| `wpta` | `wp theme activate` |
+| `wptd` | `wp theme delete` |
+| `wptdis` | `wp theme disable` |
+| `wpte` | `wp theme enable` |
+| `wptg` | `wp theme get` |
+| `wpti` | `wp theme install` |
+| `wptis` | `wp theme is-installed` |
+| `wptl` | `wp theme list` |
+| `wptm` | `wp theme mod` |
+| `wptp` | `wp theme path` |
+| `wpts` | `wp theme search` |
+| `wptst` | `wp theme status` |
+| `wptu` | `wp theme update` |
+| **User** |
+| `wpuac` | `wp user add-cap` |
+| `wpuar` | `wp user add-role` |
+| `wpuc` | `wp user create` |
+| `wpud` | `wp user delete` |
+| `wpugen` | `wp user generate` |
+| `wpug` | `wp user get` |
+| `wpui` | `wp user import-csv` |
+| `wpul` | `wp user list` |
+| `wpulc` | `wp user list-caps` |
+| `wpum` | `wp user meta` |
+| `wpurc` | `wp user remove-cap` |
+| `wpurr` | `wp user remove-role` |
+| `wpusr` | `wp user set-role` |
+| `wpuu` | `wp user update` |
+| **Widget** |
+| `wpwa` | `wp widget add` |
+| `wpwda` | `wp widget deactivate` |
+| `wpwd` | `wp widget delete` |
+| `wpwl` | `wp widget list` |
+| `wpwm` | `wp widget move` |
+| `wpwu` | `wp widget update` |
diff --git a/plugins/wp-cli/wp-cli.plugin.zsh b/plugins/wp-cli/wp-cli.plugin.zsh
index 97bed406e..09bdf3260 100644
--- a/plugins/wp-cli/wp-cli.plugin.zsh
+++ b/plugins/wp-cli/wp-cli.plugin.zsh
@@ -2,14 +2,6 @@
# A command line interface for WordPress
# https://wp-cli.org/
-# Cache
-
-# Cap
-
-# CLI
-
-# Comment
-
# Core
alias wpcc='wp core config'
alias wpcd='wp core download'
@@ -27,18 +19,12 @@ alias wpcrs='wp cron schedule'
alias wpcrt='wp cron test'
# Db
-
-# Eval
-
-# Eval-File
-
-# Export
-
-# Help
-
-# Import
-
-# Media
+alias wpdbe='wp db export'
+alias wpdbi='wp db import'
+alias wpdbcr='wp db create'
+alias wpdbs='wp db search'
+alias wpdbch='wp db check'
+alias wpdbr='wp db repair'
# Menu
alias wpmc='wp menu create'
@@ -47,10 +33,6 @@ alias wpmi='wp menu item'
alias wpml='wp menu list'
alias wpmlo='wp menu location'
-# Network
-
-# Option
-
# Plugin
alias wppa='wp plugin activate'
alias wppda='wp plugin deactivate'
@@ -77,25 +59,9 @@ alias wppom='wp post meta'
alias wppou='wp post update'
alias wppourl='wp post url'
-# Rewrite
-
-# Role
-
-# Scaffold
-
-# Search-Replace
-
-# Shell
-
# Sidebar
alias wpsbl='wp sidebar list'
-# Site
-
-# Super-Admin
-
-# Term
-
# Theme
alias wpta='wp theme activate'
alias wptd='wp theme delete'
@@ -111,8 +77,6 @@ alias wpts='wp theme search'
alias wptst='wp theme status'
alias wptu='wp theme update'
-# Transient
-
# User
alias wpuac='wp user add-cap'
alias wpuar='wp user add-role'
@@ -138,9 +102,8 @@ alias wpwm='wp widget move'
alias wpwu='wp widget update'
+# Completion for wp
autoload -U +X bashcompinit && bashcompinit
-# bash completion for the `wp` command
-
_wp_complete() {
local cur=${COMP_WORDS[COMP_CWORD]}
diff --git a/tools/changelog.sh b/tools/changelog.sh
new file mode 100755
index 000000000..8753212e9
--- /dev/null
+++ b/tools/changelog.sh
@@ -0,0 +1,429 @@
+#!/usr/bin/env zsh
+
+##############################
+# CHANGELOG SCRIPT CONSTANTS #
+##############################
+
+#* Holds the list of valid types recognized in a commit subject
+#* and the display string of such type
+local -A TYPES
+TYPES=(
+ build "Build system"
+ chore "Chore"
+ ci "CI"
+ docs "Documentation"
+ feat "Features"
+ fix "Bug fixes"
+ perf "Performance"
+ refactor "Refactor"
+ style "Style"
+ test "Testing"
+)
+
+#* Types that will be displayed in their own section,
+#* in the order specified here.
+local -a MAIN_TYPES
+MAIN_TYPES=(feat fix perf docs)
+
+#* Types that will be displayed under the category of other changes
+local -a OTHER_TYPES
+OTHER_TYPES=(refactor style other)
+
+#* Commit types that don't appear in $MAIN_TYPES nor $OTHER_TYPES
+#* will not be displayed and will simply be ignored.
+
+
+############################
+# COMMIT PARSING UTILITIES #
+############################
+
+function parse-commit {
+
+ # This function uses the following globals as output: commits (A),
+ # subjects (A), scopes (A) and breaking (A). All associative arrays (A)
+ # have $hash as the key.
+ # - commits holds the commit type
+ # - subjects holds the commit subject
+ # - scopes holds the scope of a commit
+ # - breaking holds the breaking change warning if a commit does
+ # make a breaking change
+
+ function commit:type {
+ local type="$(sed -E 's/^([a-zA-Z_\-]+)(\(.+\))?!?: .+$/\1/' <<< "$1")"
+
+ # If $type doesn't appear in $TYPES array mark it as 'other'
+ if [[ -n "${(k)TYPES[(i)$type]}" ]]; then
+ echo $type
+ else
+ echo other
+ fi
+ }
+
+ function commit:scope {
+ local scope
+
+ # Try to find scope in "type(<scope>):" format
+ scope=$(sed -nE 's/^[a-zA-Z_\-]+\((.+)\)!?: .+$/\1/p' <<< "$1")
+ if [[ -n "$scope" ]]; then
+ echo "$scope"
+ return
+ fi
+
+ # If no scope found, try to find it in "<scope>:" format
+ # Make sure it's not a type before printing it
+ scope=$(sed -nE 's/^([a-zA-Z_\-]+): .+$/\1/p' <<< "$1")
+ if [[ -z "${(k)TYPES[(i)$scope]}" ]]; then
+ echo "$scope"
+ fi
+ }
+
+ function commit:subject {
+ # Only display the relevant part of the commit, i.e. if it has the format
+ # type[(scope)!]: subject, where the part between [] is optional, only
+ # displays subject. If it doesn't match the format, returns the whole string.
+ sed -E 's/^[a-zA-Z_\-]+(\(.+\))?!?: (.+)$/\2/' <<< "$1"
+ }
+
+ # Return subject if the body or subject match the breaking change format
+ function commit:is-breaking {
+ local subject="$1" body="$2" message
+
+ if [[ "$body" =~ "BREAKING CHANGE: (.*)" || \
+ "$subject" =~ '^[^ :\)]+\)?!: (.*)$' ]]; then
+ message="${match[1]}"
+ # skip next paragraphs (separated by two newlines or more)
+ message="${message%%$'\n\n'*}"
+ # ... and replace newlines with spaces
+ echo "${message//$'\n'/ }"
+ else
+ return 1
+ fi
+ }
+
+ # Return truncated hash of the reverted commit
+ function commit:is-revert {
+ local subject="$1" body="$2"
+
+ if [[ "$subject" = Revert* && \
+ "$body" =~ "This reverts commit ([^.]+)\." ]]; then
+ echo "${match[1]:0:7}"
+ else
+ return 1
+ fi
+ }
+
+ # Parse commit with hash $1
+ local hash="$1" subject body warning rhash
+ subject="$(command git show -s --format=%s $hash)"
+ body="$(command git show -s --format=%b $hash)"
+
+ # Commits following Conventional Commits (https://www.conventionalcommits.org/)
+ # have the following format, where parts between [] are optional:
+ #
+ # type[(scope)][!]: subject
+ #
+ # commit body
+ # [BREAKING CHANGE: warning]
+
+ # commits holds the commit type
+ commits[$hash]="$(commit:type "$subject")"
+ # scopes holds the commit scope
+ scopes[$hash]="$(commit:scope "$subject")"
+ # subjects holds the commit subject
+ subjects[$hash]="$(commit:subject "$subject")"
+
+ # breaking holds whether a commit has breaking changes
+ # and its warning message if it does
+ if warning=$(commit:is-breaking "$subject" "$body"); then
+ breaking[$hash]="$warning"
+ fi
+
+ # reverts holds commits reverted in the same release
+ if rhash=$(commit:is-revert "$subject" "$body"); then
+ reverts[$hash]=$rhash
+ fi
+}
+
+#############################
+# RELEASE CHANGELOG DISPLAY #
+#############################
+
+function display-release {
+
+ # This function uses the following globals: output, version,
+ # commits (A), subjects (A), scopes (A), breaking (A) and reverts (A).
+ #
+ # - output is the output format to use when formatting (raw|text|md)
+ # - version is the version in which the commits are made
+ # - commits, subjects, scopes, breaking, and reverts are associative arrays
+ # with commit hashes as keys
+
+ # Remove commits that were reverted
+ local hash rhash
+ for hash rhash in ${(kv)reverts}; do
+ if (( ${+commits[$rhash]} )); then
+ # Remove revert commit
+ unset "commits[$hash]" "subjects[$hash]" "scopes[$hash]" "breaking[$hash]"
+ # Remove reverted commit
+ unset "commits[$rhash]" "subjects[$rhash]" "scopes[$rhash]" "breaking[$rhash]"
+ fi
+ done
+
+ # If no commits left skip displaying the release
+ if (( $#commits == 0 )); then
+ return
+ fi
+
+ ##* Formatting functions
+
+ # Format the hash according to output format
+ # If no parameter is passed, assume it comes from `$hash`
+ function fmt:hash {
+ #* Uses $hash from outer scope
+ local hash="${1:-$hash}"
+ case "$output" in
+ raw) printf "$hash" ;;
+ text) printf "\e[33m$hash\e[0m" ;; # red
+ md) printf "[\`$hash\`](https://github.com/ohmyzsh/ohmyzsh/commit/$hash)" ;;
+ esac
+ }
+
+ # Format headers according to output format
+ # Levels 1 to 2 are considered special, the rest are formatted
+ # the same, except in md output format.
+ function fmt:header {
+ local header="$1" level="$2"
+ case "$output" in
+ raw)
+ case "$level" in
+ 1) printf "$header\n$(printf '%.0s=' {1..${#header}})\n\n" ;;
+ 2) printf "$header\n$(printf '%.0s-' {1..${#header}})\n\n" ;;
+ *) printf "$header:\n\n" ;;
+ esac ;;
+ text)
+ case "$level" in
+ 1|2) printf "\e[1;4m$header\e[0m\n\n" ;; # bold, underlined
+ *) printf "\e[1m$header:\e[0m\n\n" ;; # bold
+ esac ;;
+ md) printf "$(printf '%.0s#' {1..${level}}) $header\n\n" ;;
+ esac
+ }
+
+ function fmt:scope {
+ #* Uses $scopes (A) and $hash from outer scope
+ local scope="${1:-${scopes[$hash]}}"
+
+ # Get length of longest scope for padding
+ local max_scope=0 padding=0
+ for hash in ${(k)scopes}; do
+ max_scope=$(( max_scope < ${#scopes[$hash]} ? ${#scopes[$hash]} : max_scope ))
+ done
+
+ # If no scopes, exit the function
+ if [[ $max_scope -eq 0 ]]; then
+ return
+ fi
+
+ # Get how much padding is required for this scope
+ padding=$(( max_scope < ${#scope} ? 0 : max_scope - ${#scope} ))
+ padding="${(r:$padding:: :):-}"
+
+ # If no scope, print padding and 3 spaces (equivalent to "[] ")
+ if [[ -z "$scope" ]]; then
+ printf "${padding} "
+ return
+ fi
+
+ # Print [scope]
+ case "$output" in
+ raw|md) printf "[$scope]${padding} " ;;
+ text) printf "[\e[38;5;9m$scope\e[0m]${padding} " ;; # red 9
+ esac
+ }
+
+ # If no parameter is passed, assume it comes from `$subjects[$hash]`
+ function fmt:subject {
+ #* Uses $subjects (A) and $hash from outer scope
+ local subject="${1:-${subjects[$hash]}}"
+
+ # Capitalize first letter of the subject
+ subject="${(U)subject:0:1}${subject:1}"
+
+ case "$output" in
+ raw) printf "$subject" ;;
+ # In text mode, highlight (#<issue>) and dim text between `backticks`
+ text) sed -E $'s|#([0-9]+)|\e[32m#\\1\e[0m|g;s|`([^`]+)`|`\e[2m\\1\e[0m`|g' <<< "$subject" ;;
+ # In markdown mode, link to (#<issue>) issues
+ md) sed -E 's|#([0-9]+)|[#\1](https://github.com/ohmyzsh/ohmyzsh/issues/\1)|g' <<< "$subject" ;;
+ esac
+ }
+
+ function fmt:type {
+ #* Uses $type from outer scope
+ local type="${1:-${TYPES[$type]:-${(C)type}}}"
+ [[ -z "$type" ]] && return 0
+ case "$output" in
+ raw|md) printf "$type: " ;;
+ text) printf "\e[4m$type\e[24m: " ;; # underlined
+ esac
+ }
+
+ ##* Section functions
+
+ function display:version {
+ fmt:header "$version" 2
+ }
+
+ function display:breaking {
+ (( $#breaking != 0 )) || return 0
+
+ case "$output" in
+ raw) fmt:header "BREAKING CHANGES" 3 ;;
+ text|md) fmt:header "⚠ BREAKING CHANGES" 3 ;;
+ esac
+
+ local hash subject
+ for hash message in ${(kv)breaking}; do
+ echo " - $(fmt:hash) $(fmt:subject "${message}")"
+ done | sort
+ echo
+ }
+
+ function display:type {
+ local hash type="$1"
+
+ local -a hashes
+ hashes=(${(k)commits[(R)$type]})
+
+ # If no commits found of type $type, go to next type
+ (( $#hashes != 0 )) || return 0
+
+ fmt:header "${TYPES[$type]}" 3
+ for hash in $hashes; do
+ echo " - $(fmt:hash) $(fmt:scope)$(fmt:subject)"
+ done | sort -k3 # sort by scope
+ echo
+ }
+
+ function display:others {
+ local hash type
+
+ # Commits made under types considered other changes
+ local -A changes
+ changes=(${(kv)commits[(R)${(j:|:)OTHER_TYPES}]})
+
+ # If no commits found under "other" types, don't display anything
+ (( $#changes != 0 )) || return 0
+
+ fmt:header "Other changes" 3
+ for hash type in ${(kv)changes}; do
+ case "$type" in
+ other) echo " - $(fmt:hash) $(fmt:scope)$(fmt:subject)" ;;
+ *) echo " - $(fmt:hash) $(fmt:scope)$(fmt:type)$(fmt:subject)" ;;
+ esac
+ done | sort -k3 # sort by scope
+ echo
+ }
+
+ ##* Release sections order
+
+ # Display version header
+ display:version
+
+ # Display breaking changes first
+ display:breaking
+
+ # Display changes for commit types in the order specified
+ for type in $MAIN_TYPES; do
+ display:type "$type"
+ done
+
+ # Display other changes
+ display:others
+}
+
+function main {
+ # $1 = until commit, $2 = since commit
+ local until="$1" since="$2"
+
+ # $3 = output format (--text|--raw|--md)
+ # --md: uses markdown formatting
+ # --raw: outputs without style
+ # --text: uses ANSI escape codes to style the output
+ local output=${${3:-"--text"}#--*}
+
+ if [[ -z "$until" ]]; then
+ until=HEAD
+ fi
+
+ if [[ -z "$since" ]]; then
+ # If $since is not specified:
+ # 1) try to find the version used before updating
+ # 2) try to find the first version tag before $until
+ since=$(command git config --get oh-my-zsh.lastVersion 2>/dev/null) || \
+ since=$(command git describe --abbrev=0 --tags "$until^" 2>/dev/null) || \
+ unset since
+ elif [[ "$since" = --all ]]; then
+ unset since
+ fi
+
+ # Commit classification arrays
+ local -A commits subjects scopes breaking reverts
+ local truncate=0 read_commits=0
+ local hash version tag
+
+ # Get the first version name:
+ # 1) try tag-like version, or
+ # 2) try name-rev, or
+ # 3) try branch name, 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 rev-parse --short $until 2>/dev/null)
+
+ # Get commit list from $until commit until $since commit, or until root
+ # commit if $since is unset, in short hash form.
+ # --first-parent is used when dealing with merges: it only prints the
+ # merge commit, not the commits of the merged branch.
+ command git rev-list --first-parent --abbrev-commit --abbrev=7 ${since:+$since..}$until | while read hash; do
+ # Truncate list on versions with a lot of commits
+ if [[ -z "$since" ]] && (( ++read_commits > 35 )); then
+ truncate=1
+ break
+ fi
+
+ # If we find a new release (exact tag)
+ if tag=$(command git describe --exact-match --tags $hash 2>/dev/null); then
+ # Output previous release
+ display-release
+ # Reinitialize commit storage
+ commits=()
+ subjects=()
+ scopes=()
+ breaking=()
+ reverts=()
+ # Start work on next release
+ version="$tag"
+ read_commits=1
+ fi
+
+ parse-commit "$hash"
+ done
+
+ display-release
+
+ if (( truncate )); then
+ echo " ...more commits omitted"
+ echo
+ fi
+}
+
+cd "$ZSH"
+
+# Use raw output if stdout is not a tty
+if [[ ! -t 1 && -z "$3" ]]; then
+ main "$1" "$2" --raw
+else
+ main "$@"
+fi
diff --git a/tools/check_for_upgrade.sh b/tools/check_for_upgrade.sh
index cadd5fe49..d0ceba92d 100644
--- a/tools/check_for_upgrade.sh
+++ b/tools/check_for_upgrade.sh
@@ -1,6 +1,6 @@
# Migrate .zsh-update file to $ZSH_CACHE_DIR
if [[ -f ~/.zsh-update && ! -f "${ZSH_CACHE_DIR}/.zsh-update" ]]; then
- mv ~/.zsh-update "${ZSH_CACHE_DIR}/.zsh-update"
+ mv ~/.zsh-update "${ZSH_CACHE_DIR}/.zsh-update"
fi
# Cancel update if:
@@ -10,79 +10,81 @@ fi
if [[ "$DISABLE_AUTO_UPDATE" = true ]] \
|| [[ ! -w "$ZSH" || ! -O "$ZSH" ]] \
|| ! command -v git &>/dev/null; then
- return
+ return
fi
function current_epoch() {
- zmodload zsh/datetime
- echo $(( EPOCHSECONDS / 60 / 60 / 24 ))
+ zmodload zsh/datetime
+ echo $(( EPOCHSECONDS / 60 / 60 / 24 ))
}
function update_last_updated_file() {
- echo "LAST_EPOCH=$(current_epoch)" >! "${ZSH_CACHE_DIR}/.zsh-update"
+ echo "LAST_EPOCH=$(current_epoch)" >! "${ZSH_CACHE_DIR}/.zsh-update"
}
function update_ohmyzsh() {
- ZSH="$ZSH" sh "$ZSH/tools/upgrade.sh"
- update_last_updated_file
+ ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh" --interactive
+ update_last_updated_file
}
() {
- emulate -L zsh
+ emulate -L zsh
- local epoch_target mtime option LAST_EPOCH
+ local epoch_target mtime option LAST_EPOCH
- # Remove lock directory if older than a day
- zmodload zsh/datetime
- zmodload -F zsh/stat b:zstat
- if mtime=$(zstat +mtime "$ZSH/log/update.lock" 2>/dev/null); then
- if (( (mtime + 3600 * 24) < EPOCHSECONDS )); then
- command rm -rf "$ZSH/log/update.lock"
- fi
+ # Remove lock directory if older than a day
+ zmodload zsh/datetime
+ zmodload -F zsh/stat b:zstat
+ if mtime=$(zstat +mtime "$ZSH/log/update.lock" 2>/dev/null); then
+ if (( (mtime + 3600 * 24) < EPOCHSECONDS )); then
+ command rm -rf "$ZSH/log/update.lock"
fi
+ fi
- # Check for lock directory
- if ! command mkdir "$ZSH/log/update.lock" 2>/dev/null; then
- return
- fi
+ # Check for lock directory
+ if ! command mkdir "$ZSH/log/update.lock" 2>/dev/null; then
+ return
+ fi
- # Remove lock directory on exit. `return 1` is important for when trapping a SIGINT:
- # The return status from the function is handled specially. If it is zero, the signal is
- # assumed to have been handled, and execution continues normally. Otherwise, the shell
- # will behave as interrupted except that the return status of the trap is retained.
- trap "command rm -rf '$ZSH/log/update.lock'; return 1" EXIT INT QUIT
+ # Remove lock directory on exit. `return 1` is important for when trapping a SIGINT:
+ # The return status from the function is handled specially. If it is zero, the signal is
+ # assumed to have been handled, and execution continues normally. Otherwise, the shell
+ # will behave as interrupted except that the return status of the trap is retained.
+ trap "
+ unset -f current_epoch update_last_updated_file update_ohmyzsh
+ command rm -rf '$ZSH/log/update.lock'
+ return 1
+ " EXIT INT QUIT
- # Create or update .zsh-update file if missing or malformed
- if ! source "${ZSH_CACHE_DIR}/.zsh-update" 2>/dev/null || [[ -z "$LAST_EPOCH" ]]; then
- update_last_updated_file
- return
- fi
+ # Create or update .zsh-update file if missing or malformed
+ if ! source "${ZSH_CACHE_DIR}/.zsh-update" 2>/dev/null || [[ -z "$LAST_EPOCH" ]]; then
+ update_last_updated_file
+ return
+ fi
- # Number of days before trying to update again
- epoch_target=${UPDATE_ZSH_DAYS:-13}
- # Test if enough time has passed until the next update
- if (( ( $(current_epoch) - $LAST_EPOCH ) < $epoch_target )); then
- return
- fi
+ # Number of days before trying to update again
+ epoch_target=${UPDATE_ZSH_DAYS:-13}
+ # Test if enough time has passed until the next update
+ if (( ( $(current_epoch) - $LAST_EPOCH ) < $epoch_target )); then
+ return
+ fi
- # Ask for confirmation before updating unless disabled
- if [[ "$DISABLE_UPDATE_PROMPT" = true ]]; then
- update_ohmyzsh
- else
- # input sink to swallow all characters typed before the prompt
- # and add a newline if there wasn't one after characters typed
- while read -t -k 1 option; do true; done
- [[ "$option" != ($'\n'|"") ]] && echo
+ # Ask for confirmation before updating unless disabled
+ if [[ "$DISABLE_UPDATE_PROMPT" = true ]]; then
+ update_ohmyzsh
+ else
+ # input sink to swallow all characters typed before the prompt
+ # and add a newline if there wasn't one after characters typed
+ while read -t -k 1 option; do true; done
+ [[ "$option" != ($'\n'|"") ]] && echo
- echo -n "[oh-my-zsh] Would you like to update? [Y/n] "
- read -r -k 1 option
- [[ "$option" != $'\n' ]] && echo
- case "$option" in
- [yY$'\n']) update_ohmyzsh ;;
- [nN]) update_last_updated_file ;;
- esac
- fi
+ echo -n "[oh-my-zsh] Would you like to update? [Y/n] "
+ read -r -k 1 option
+ [[ "$option" != $'\n' ]] && echo
+ case "$option" in
+ [yY$'\n']) update_ohmyzsh ;;
+ [nN]) update_last_updated_file ;;
+ esac
+ fi
}
-
-unset -f current_epoch update_last_updated_file update_ohmyzsh
diff --git a/tools/upgrade.sh b/tools/upgrade.sh
index e005519d6..4df7eb184 100644..100755
--- a/tools/upgrade.sh
+++ b/tools/upgrade.sh
@@ -1,40 +1,49 @@
-# Use colors, but only if connected to a terminal, and that terminal
-# supports them.
+#!/usr/bin/env zsh
+
+if [ -z "$ZSH_VERSION" ]; then
+ exec zsh "$0"
+fi
+
+cd "$ZSH"
+
+# Use colors, but only if connected to a terminal
+# and that terminal supports them.
+
+local -a RAINBOW
+local RED GREEN YELLOW BLUE BOLD DIM UNDER RESET
+
if [ -t 1 ]; then
- RB_RED=$(printf '\033[38;5;196m')
- RB_ORANGE=$(printf '\033[38;5;202m')
- RB_YELLOW=$(printf '\033[38;5;226m')
- RB_GREEN=$(printf '\033[38;5;082m')
- RB_BLUE=$(printf '\033[38;5;021m')
- RB_INDIGO=$(printf '\033[38;5;093m')
- RB_VIOLET=$(printf '\033[38;5;163m')
+ 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')"
+ )
RED=$(printf '\033[31m')
GREEN=$(printf '\033[32m')
YELLOW=$(printf '\033[33m')
BLUE=$(printf '\033[34m')
BOLD=$(printf '\033[1m')
+ DIM=$(printf '\033[2m')
UNDER=$(printf '\033[4m')
RESET=$(printf '\033[m')
-else
- RB_RED=""
- RB_ORANGE=""
- RB_YELLOW=""
- RB_GREEN=""
- RB_BLUE=""
- RB_INDIGO=""
- RB_VIOLET=""
-
- RED=""
- GREEN=""
- YELLOW=""
- BLUE=""
- UNDER=""
- BOLD=""
- RESET=""
fi
-cd "$ZSH"
+# Update upstream remote to ohmyzsh org
+git remote -v | while read remote url extra; do
+ case "$url" in
+ https://github.com/robbyrussell/oh-my-zsh(|.git))
+ git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git"
+ break ;;
+ git@github.com:robbyrussell/oh-my-zsh(|.git))
+ git remote set-url "$remote" "git@github.com:ohmyzsh/ohmyzsh.git"
+ break ;;
+ esac
+done
# Set git-config values known to fix git errors
# Line endings (#4069)
@@ -45,30 +54,50 @@ git config fsck.zeroPaddedFilemode ignore
git config fetch.fsck.zeroPaddedFilemode ignore
git config receive.fsck.zeroPaddedFilemode ignore
# autostash on rebase (#7172)
-resetAutoStash=$(git config --bool rebase.autoStash 2>&1)
+resetAutoStash=$(git config --bool rebase.autoStash 2>/dev/null)
git config rebase.autoStash true
-# Update upstream remote to ohmyzsh org
-remote=$(git remote -v | awk '/https:\/\/github\.com\/robbyrussell\/oh-my-zsh\.git/{ print $1; exit }')
-if [ -n "$remote" ]; then
- git remote set-url "$remote" "https://github.com/ohmyzsh/ohmyzsh.git"
-fi
+local ret=0
+# Update Oh My Zsh
printf "${BLUE}%s${RESET}\n" "Updating Oh My Zsh"
-if git pull --rebase --stat origin master
-then
- printf '%s %s__ %s %s %s %s %s__ %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf '%s ____ %s/ /_ %s ____ ___ %s__ __ %s ____ %s_____%s/ /_ %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf '%s / __ \%s/ __ \ %s / __ `__ \%s/ / / / %s /_ / %s/ ___/%s __ \ %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf '%s/ /_/ /%s / / / %s / / / / / /%s /_/ / %s / /_%s(__ )%s / / / %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf '%s\____/%s_/ /_/ %s /_/ /_/ /_/%s\__, / %s /___/%s____/%s_/ /_/ %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf '%s %s %s %s /____/ %s %s %s %s\n' $RB_RED $RB_ORANGE $RB_YELLOW $RB_GREEN $RB_BLUE $RB_INDIGO $RB_VIOLET $RB_RESET
- printf "${BLUE}%s\n" "Hooray! Oh My Zsh has been updated and/or is at the current version."
- printf "${BLUE}${BOLD}%s ${UNDER}%s${RESET}\n" "To keep up on the latest news and updates, follow us on Twitter:" "https://twitter.com/ohmyzsh"
+last_commit=$(git rev-parse HEAD)
+if git pull --rebase --stat origin master; 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."
+ ret=80 # non-zero exit code to indicate no changes pulled
+ else
+ message="Hooray! Oh My Zsh has been updated!"
+
+ # Save the commit prior to updating
+ git config oh-my-zsh.lastVersion "$last_commit"
+
+ # Display changelog with less if available, otherwise just print it to the terminal
+ if [[ "$1" = --interactive ]]; then
+ if (( $+commands[less] )); then
+ "$ZSH/tools/changelog.sh" HEAD "$last_commit" --text | LESS= command less -R
+ else
+ "$ZSH/tools/changelog.sh" HEAD "$last_commit"
+ fi
+ fi
+
+ printf "${BLUE}%s \`${BOLD}%s${RESET}${BLUE}\`${RESET}\n" "You can see the changelog again with" "omz changelog"
+ fi
+
+ printf '%s %s__ %s %s %s %s %s__ %s\n' $RAINBOW $RESET
+ printf '%s ____ %s/ /_ %s ____ ___ %s__ __ %s ____ %s_____%s/ /_ %s\n' $RAINBOW $RESET
+ printf '%s / __ \%s/ __ \ %s / __ `__ \%s/ / / / %s /_ / %s/ ___/%s __ \ %s\n' $RAINBOW $RESET
+ printf '%s/ /_/ /%s / / / %s / / / / / /%s /_/ / %s / /_%s(__ )%s / / / %s\n' $RAINBOW $RESET
+ printf '%s\____/%s_/ /_/ %s /_/ /_/ /_/%s\__, / %s /___/%s____/%s_/ /_/ %s\n' $RAINBOW $RESET
+ printf '%s %s %s %s /____/ %s %s %s %s\n' $RAINBOW $RESET
+ printf '\n'
+ printf "${BLUE}%s${RESET}\n" "$message"
+ printf "${BLUE}${BOLD}%s ${UNDER}%s${RESET}\n" "To keep up with the latest news and updates, follow us on Twitter:" "https://twitter.com/ohmyzsh"
printf "${BLUE}${BOLD}%s ${UNDER}%s${RESET}\n" "Want to get involved in the community? Join our Discord:" "https://discord.gg/ohmyzsh"
printf "${BLUE}${BOLD}%s ${UNDER}%s${RESET}\n" "Get your Oh My Zsh swag at:" "https://shop.planetargon.com/collections/oh-my-zsh"
else
- status=$?
+ ret=$?
printf "${RED}%s${RESET}\n" 'There was an error updating. Try again later?'
fi
@@ -79,4 +108,4 @@ case "$resetAutoStash" in
esac
# Exit with `1` if the update failed
-exit $status
+exit $ret