summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/cli.zsh871
-rw-r--r--lib/clipboard.zsh2
-rw-r--r--lib/completion.zsh20
-rw-r--r--lib/correction.zsh1
-rw-r--r--lib/diagnostics.zsh2
-rw-r--r--lib/functions.zsh45
-rw-r--r--lib/git.zsh215
-rw-r--r--lib/history.zsh3
-rw-r--r--lib/key-bindings.zsh107
-rw-r--r--lib/nvm.zsh9
-rw-r--r--lib/prompt_info_functions.zsh1
-rw-r--r--lib/termsupport.zsh38
-rw-r--r--lib/theme-and-appearance.zsh5
13 files changed, 1027 insertions, 292 deletions
diff --git a/lib/cli.zsh b/lib/cli.zsh
index e25a9f0b1..4b14360c1 100644
--- a/lib/cli.zsh
+++ b/lib/cli.zsh
@@ -1,195 +1,776 @@
#!/usr/bin/env zsh
function omz {
- [[ $# -gt 0 ]] || {
- _omz::help
- return 1
- }
+ [[ $# -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 "$@"
+}
- local command="$1"
- shift
+function _omz {
+ local -a cmds subcmds
+ cmds=(
+ 'changelog:Print the changelog'
+ 'help:Usage information'
+ 'plugin:Manage plugins'
+ 'pr:Manage Oh My Zsh Pull Requests'
+ 'reload:Reload the current zsh session'
+ '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 -C "$ZSH" for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}")
+ _describe 'command' refs ;;
+ plugin) subcmds=(
+ 'disable:Disable plugin(s)'
+ 'enable:Enable plugin(s)'
+ 'info:Get plugin information'
+ 'list:List plugins'
+ 'load:Load plugin(s)'
+ )
+ _describe 'command' subcmds ;;
+ pr) subcmds=('clean:Delete all Pull Request branches' 'test:Test a Pull Request')
+ _describe 'command' subcmds ;;
+ theme) subcmds=('list:List themes' 'set:Set a theme in your .zshrc file' 'use:Load a theme')
+ _describe 'command' subcmds ;;
+ esac
+ elif (( CURRENT == 4 )); then
+ case "${words[2]}::${words[3]}" in
+ plugin::(disable|enable|load))
+ local -aU valid_plugins
+
+ if [[ "${words[3]}" = disable ]]; then
+ # 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))
+ # if command is "enable", remove already enabled plugins
+ [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins})
+ fi
+
+ _describe 'plugin' valid_plugins ;;
+ plugin::info)
+ local -aU 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=("$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
+ case "${words[2]}::${words[3]}" in
+ plugin::(enable|disable|load))
+ local -aU valid_plugins
+
+ if [[ "${words[3]}" = disable ]]; then
+ # 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))
+ # if command is "enable", remove already enabled plugins
+ [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins})
+ fi
+
+ # Remove plugins already passed as arguments
+ # NOTE: $(( CURRENT - 1 )) is the last plugin argument completely passed, i.e. that which
+ # has a space after them. This is to avoid removing plugins partially passed, which makes
+ # the completion not add a space after the completed plugin.
+ local -a args
+ args=(${words[4,$(( CURRENT - 1))]})
+ valid_plugins=(${valid_plugins:|args})
+
+ _describe 'plugin' valid_plugins ;;
+ esac
+ fi
+
+ return 0
+}
- # Subcommand functions start with _ so that they don't
- # appear as completion entries when looking for `omz`
- (( $+functions[_omz::$command] )) || {
- _omz::help
- return 1
- }
+compdef _omz omz
- _omz::$command "$@"
-}
+## Utility functions
-function _omz {
- local -a cmds subcmds
- cmds=(
- 'help:Usage information'
- 'pr:Commands for Oh My Zsh Pull Requests'
- )
-
- if (( CURRENT == 2 )); then
- _describe 'command' cmds
- elif (( CURRENT == 3 )); then
- case "$words[2]" in
- pr) subcmds=( 'test:Test a Pull Request' 'clean:Delete all Pull Request branches' )
- _describe 'command' subcmds ;;
- esac
- fi
+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
- return 0
+ # If no newline entered, add a newline
+ if [[ "$REPLY" != $'\n' ]]; then
+ echo
+ fi
}
-compdef _omz omz
+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 >&2 <<EOF
Usage: omz <command> [options]
Available commands:
- help Print this help message
- pr <command> Commands for Oh My Zsh Pull Requests
+ help Print this help message
+ changelog Print the changelog
+ plugin <command> Manage plugins
+ pr <command> Manage Oh My Zsh Pull Requests
+ reload Reload the current zsh session
+ theme <command> Manage themes
+ update Update Oh My Zsh
EOF
}
-function _omz::log {
- # if promptsubst is set, a message with `` or $()
- # will be run even if quoted due to `print -P`
- setopt localoptions nopromptsubst
+function _omz::changelog {
+ local version=${1:-HEAD} format=${3:-"--text"}
+
+ 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 >&2 <<EOF
+Usage: omz changelog [version]
+
+NOTE: <version> must be a valid branch, tag or commit.
+EOF
+ return 1
+ fi
+
+ "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format"
+}
+
+function _omz::plugin {
+ (( $# > 0 && $+functions[_omz::plugin::$1] )) || {
+ cat >&2 <<EOF
+Usage: omz plugin <command> [options]
+
+Available commands:
+
+ disable <plugin> Disable plugin(s)
+ enable <plugin> Enable plugin(s)
+ info <plugin> Get information of a plugin
+ list List all available Oh My Zsh plugins
+ load <plugin> Load plugin(s)
+
+EOF
+ return 1
+ }
+
+ local command="$1"
+ shift
+
+ _omz::plugin::$command "$@"
+}
+
+function _omz::plugin::disable {
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz plugin disable <plugin> [...]"
+ return 1
+ fi
+
+ # Check that plugin is in $plugins
+ local -a dis_plugins
+ for plugin in "$@"; do
+ if [[ ${plugins[(Ie)$plugin]} -eq 0 ]]; then
+ _omz::log warn "plugin '$plugin' is not enabled."
+ continue
+ fi
+ dis_plugins+=("$plugin")
+ done
+
+ # Exit if there are no enabled plugins to disable
+ if [[ ${#dis_plugins} -eq 0 ]]; then
+ return 1
+ fi
+
+ # Remove plugins substitution awk script
+ local awk_subst_plugins="\
+ gsub(/\s+(${(j:|:)dis_plugins})/, \"\") # with spaces before
+ gsub(/(${(j:|:)dis_plugins})\s+/, \"\") # with spaces after
+ gsub(/\((${(j:|:)dis_plugins})\)/, \"\") # without spaces (only plugin)
+"
+ # Disable plugins awk script
+ local awk_script="
+# if plugins=() is in oneline form, substitute disabled plugins and go to next line
+/^\s*plugins=\([^#]+\).*\$/ {
+ $awk_subst_plugins
+ print \$0
+ next
+}
+
+# if plugins=() is in multiline form, enable multi flag and disable plugins if they're there
+/^\s*plugins=\(/ {
+ multi=1
+ $awk_subst_plugins
+ print \$0
+ next
+}
+
+# if multi flag is enabled and we find a valid closing parenthesis, remove plugins and disable multi flag
+multi == 1 && /^[^#]*\)/ {
+ multi=0
+ $awk_subst_plugins
+ print \$0
+ next
+}
+
+multi == 1 && length(\$0) > 0 {
+ $awk_subst_plugins
+ if (length(\$0) > 0) print \$0
+ next
+}
+
+{ print \$0 }
+"
+
+ awk "$awk_script" ~/.zshrc > ~/.zshrc.new \
+ && command mv -f ~/.zshrc ~/.zshrc.bck \
+ && command mv -f ~/.zshrc.new ~/.zshrc
+
+ # Exit if the new .zshrc file wasn't created correctly
+ [[ $? -eq 0 ]] || {
+ local ret=$?
+ _omz::log error "error disabling plugins."
+ return $ret
+ }
+
+ # Exit if the new .zshrc file has syntax errors
+ if ! zsh -n ~/.zshrc; then
+ _omz::log error "broken syntax in ~/.zshrc. Rolling back changes..."
+ command mv -f ~/.zshrc ~/.zshrc.new
+ command mv -f ~/.zshrc.bck ~/.zshrc
+ return 1
+ fi
+
+ # Restart the zsh session if there were no errors
+ _omz::log info "plugins disabled: ${(j:, :)dis_plugins}."
+
+ # Old zsh versions don't have ZSH_ARGZERO
+ local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}"
+ # Check whether to run a login shell
+ [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh"
+}
+
+function _omz::plugin::enable {
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz plugin enable <plugin> [...]"
+ return 1
+ fi
+
+ # Check that plugin is not in $plugins
+ local -a add_plugins
+ for plugin in "$@"; do
+ if [[ ${plugins[(Ie)$plugin]} -ne 0 ]]; then
+ _omz::log warn "plugin '$plugin' is already enabled."
+ continue
+ fi
+ add_plugins+=("$plugin")
+ done
+
+ # Exit if there are no plugins to enable
+ if [[ ${#add_plugins} -eq 0 ]]; then
+ return 1
+ fi
+
+ # Enable plugins awk script
+ local awk_script="
+# if plugins=() is in oneline form, substitute ) with new plugins and go to the next line
+/^\s*plugins=\([^#]+\).*\$/ {
+ sub(/\)/, \" $add_plugins&\")
+ print \$0
+ next
+}
+
+# if plugins=() is in multiline form, enable multi flag
+/^\s*plugins=\(/ {
+ multi=1
+}
+
+# if multi flag is enabled and we find a valid closing parenthesis,
+# add new plugins and disable multi flag
+multi == 1 && /^[^#]*\)/ {
+ multi=0
+ sub(/\)/, \" $add_plugins&\")
+ print \$0
+ next
+}
+
+{ print \$0 }
+"
+
+ awk "$awk_script" ~/.zshrc > ~/.zshrc.new \
+ && command mv -f ~/.zshrc ~/.zshrc.bck \
+ && command mv -f ~/.zshrc.new ~/.zshrc
+
+ # Exit if the new .zshrc file wasn't created correctly
+ [[ $? -eq 0 ]] || {
+ local ret=$?
+ _omz::log error "error enabling plugins."
+ return $ret
+ }
+
+ # Exit if the new .zshrc file has syntax errors
+ if ! zsh -n ~/.zshrc; then
+ _omz::log error "broken syntax in ~/.zshrc. Rolling back changes..."
+ command mv -f ~/.zshrc ~/.zshrc.new
+ command mv -f ~/.zshrc.bck ~/.zshrc
+ return 1
+ fi
+
+ # Restart the zsh session if there were no errors
+ _omz::log info "plugins enabled: ${(j:, :)add_plugins}."
+
+ # Old zsh versions don't have ZSH_ARGZERO
+ local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}"
+ # Check whether to run a login shell
+ [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh"
+}
+
+function _omz::plugin::info {
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz plugin info <plugin>"
+ return 1
+ fi
+
+ local readme
+ for readme in "$ZSH_CUSTOM/plugins/$1/README.md" "$ZSH/plugins/$1/README.md"; do
+ if [[ -f "$readme" ]]; then
+ (( ${+commands[less]} )) && less "$readme" || cat "$readme"
+ return 0
+ fi
+ done
- # $1 = info|warn|error|debug
- # $@ = text
+ if [[ -d "$ZSH_CUSTOM/plugins/$1" || -d "$ZSH/plugins/$1" ]]; then
+ _omz::log error "the '$1' plugin doesn't have a README file"
+ else
+ _omz::log error "'$1' plugin not found"
+ fi
- local logtype=$1
- local logname=${${functrace[1]#_}%:*}
- shift
+ return 1
+}
+
+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 -x
+ 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 -x
+ fi
+}
- # Don't print anything if debug is not active
- if [[ $logtype = debug && -z $_OMZ_DEBUG ]]; then
- return
+function _omz::plugin::load {
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz plugin load <plugin> [...]"
+ return 1
+ fi
+
+ local plugin base has_completion=0
+ for plugin in "$@"; do
+ if [[ -d "$ZSH_CUSTOM/plugins/$plugin" ]]; then
+ base="$ZSH_CUSTOM/plugins/$plugin"
+ elif [[ -d "$ZSH/plugins/$plugin" ]]; then
+ base="$ZSH/plugins/$plugin"
+ else
+ _omz::log warn "plugin '$plugin' not found"
+ continue
fi
- # Choose coloring based on log type
- case "$logtype" in
- prompt) print -Pn "%S%F{blue}$logname%f%s: $@" ;;
- debug) print -P "%F{white}$logname%f: $@" ;;
- info) print -P "%F{green}$logname%f: $@" ;;
- warn) print -P "%S%F{yellow}$logname%f%s: $@" ;;
- error) print -P "%S%F{red}$logname%f%s: $@" ;;
- esac >&2
+ # Check if its a valid plugin
+ if [[ ! -f "$base/_$plugin" && ! -f "$base/$plugin.plugin.zsh" ]]; then
+ _omz::log warn "'$plugin' is not a valid plugin"
+ continue
+ # It it is a valid plugin, add its directory to $fpath unless it is already there
+ elif (( ! ${fpath[(Ie)$base]} )); then
+ fpath=("$base" $fpath)
+ fi
+
+ # Check if it has completion to reload compinit
+ if [[ -f "$base/_$plugin" ]]; then
+ has_completion=1
+ fi
+
+ # Load the plugin
+ if [[ -f "$base/$plugin.plugin.zsh" ]]; then
+ source "$base/$plugin.plugin.zsh"
+ fi
+ done
+
+ # If we have completion, we need to reload the completion
+ # We pass -D to avoid generating a new dump file, which would overwrite our
+ # current one for the next session (and we don't want that because we're not
+ # actually enabling the plugins for the next session).
+ # Note that we still have to pass -d "$_comp_dumpfile", so that compinit
+ # doesn't use the default zcompdump location (${ZDOTDIR:-$HOME}/.zcompdump).
+ if (( has_completion )); then
+ compinit -D -d "$_comp_dumpfile"
+ fi
}
function _omz::pr {
- (( $# > 0 && $+functions[_omz::pr::$1] )) || {
- cat <<EOF
+ (( $# > 0 && $+functions[_omz::pr::$1] )) || {
+ cat >&2 <<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"
+ (
+ 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
- _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
- )
+ # 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."
+ )
+
+ # 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
+
+ (
+ 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::reload {
+ # Delete current completion cache
+ command rm -f $_comp_dumpfile $ZSH_COMPDUMP
+
+ # Old zsh versions don't have ZSH_ARGZERO
+ local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}"
+ # Check whether to run a login shell
+ [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh"
+}
+
+function _omz::theme {
+ (( $# > 0 && $+functions[_omz::theme::$1] )) || {
+ cat >&2 <<EOF
+Usage: omz theme <command> [options]
+
+Available commands:
+
+ list List all available Oh My Zsh themes
+ set <theme> Set a theme in your .zshrc file
+ use <theme> Load a theme
+
+EOF
+ return 1
+ }
+
+ local command="$1"
+ shift
+
+ _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
+
+ # Print theme in use
+ if [[ -n "$ZSH_THEME" ]]; then
+ print -Pn "%U%BCurrent theme%b%u: "
+ [[ $ZSH_THEME = random ]] && echo "$RANDOM_THEME (via random)" || echo "$ZSH_THEME"
+ echo
+ fi
+
+ # Print custom themes if there are any
+ if (( ${#custom_themes} )); then
+ print -P "%U%BCustom themes%b%u:"
+ print -l ${(q-)custom_themes} | column -x
+ echo
+ fi
+
+ # Print built-in themes
+ print -P "%U%BBuilt-in themes%b%u:"
+ print -l ${(q-)builtin_themes} | column -x
+}
+
+function _omz::theme::set {
+ if [[ -z "$1" ]]; then
+ echo >&2 "Usage: omz theme set <theme>"
+ return 1
+ fi
+
+ # Check that theme exists
+ if [[ ! -f "$ZSH_CUSTOM/$1.zsh-theme" ]] \
+ && [[ ! -f "$ZSH_CUSTOM/themes/$1.zsh-theme" ]] \
+ && [[ ! -f "$ZSH/themes/$1.zsh-theme" ]]; then
+ _omz::log error "%B$1%b theme not found"
+ return 1
+ fi
+
+ # Enable theme in .zshrc
+ local awk_script='
+!set && /^\s*ZSH_THEME=[^#]+.*$/ {
+ set=1
+ sub(/^\s*ZSH_THEME=[^#]+.*$/, "ZSH_THEME=\"'$1'\" # set by `omz`")
+ print $0
+ next
+}
+
+{ print $0 }
+
+END {
+ # If no ZSH_THEME= line was found, return an error
+ if (!set) exit 1
+}
+'
+
+ awk "$awk_script" ~/.zshrc > ~/.zshrc.new \
+ || {
+ # Prepend ZSH_THEME= line to .zshrc if it doesn't exist
+ cat <<EOF
+ZSH_THEME="$1" # set by \`omz\`
+
+EOF
+ cat ~/.zshrc
+ } > ~/.zshrc.new \
+ && command mv -f ~/.zshrc ~/.zshrc.bck \
+ && command mv -f ~/.zshrc.new ~/.zshrc
+
+ # Exit if the new .zshrc file wasn't created correctly
+ [[ $? -eq 0 ]] || {
+ local ret=$?
+ _omz::log error "error setting theme."
+ return $ret
+ }
+
+ # Exit if the new .zshrc file has syntax errors
+ if ! zsh -n ~/.zshrc; then
+ _omz::log error "broken syntax in ~/.zshrc. Rolling back changes..."
+ command mv -f ~/.zshrc ~/.zshrc.new
+ command mv -f ~/.zshrc.bck ~/.zshrc
+ return 1
+ fi
+
+ # Restart the zsh session if there were no errors
+ _omz::log info "'$1' theme set correctly."
+
+ # Old zsh versions don't have ZSH_ARGZERO
+ local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}"
+ # Check whether to run a login shell
+ [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh"
+}
+
+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 "%B$1%b theme not found"
+ return 1
+ fi
+
+ # Update theme settings
+ ZSH_THEME="$1"
+ [[ $1 = random ]] || unset RANDOM_THEME
+}
- # 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::log prompt "do you want to go back to the previous branch? [Y/n] "
- read -r -k 1
- [[ "$REPLY" = [nN] ]] && return
-
- (
- 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::update {
+ local last_commit=$(cd "$ZSH"; git rev-parse HEAD)
+
+ # 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
+
+ # 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 there were changes
+ if [[ "$1" != --unattended && "$(cd "$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
+ [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh"
+ fi
}
diff --git a/lib/clipboard.zsh b/lib/clipboard.zsh
index 122145f15..4e3ba0a45 100644
--- a/lib/clipboard.zsh
+++ b/lib/clipboard.zsh
@@ -76,7 +76,7 @@ function detect-clipboard() {
function clipcopy() { win32yank -i < "${1:-/dev/stdin}"; }
function clippaste() { win32yank -o; }
elif [[ $OSTYPE == linux-android* ]] && (( $+commands[termux-clipboard-set] )); then
- function clipcopy() { termux-clipboard-set "${1:-/dev/stdin}"; }
+ function clipcopy() { termux-clipboard-set < "${1:-/dev/stdin}"; }
function clippaste() { termux-clipboard-get; }
elif [ -n "${TMUX:-}" ] && (( ${+commands[tmux]} )); then
function clipcopy() { tmux load-buffer "${1:--}"; }
diff --git a/lib/completion.zsh b/lib/completion.zsh
index 43927a277..2c5695487 100644
--- a/lib/completion.zsh
+++ b/lib/completion.zsh
@@ -32,9 +32,9 @@ zstyle ':completion:*' list-colors ''
zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;34=0=01'
if [[ "$OSTYPE" = solaris* ]]; then
- zstyle ':completion:*:*:*:*:processes' command "ps -u $USER -o pid,user,comm"
+ zstyle ':completion:*:*:*:*:processes' command "ps -u $USERNAME -o pid,user,comm"
else
- zstyle ':completion:*:*:*:*:processes' command "ps -u $USER -o pid,user,comm -w -w"
+ zstyle ':completion:*:*:*:*:processes' command "ps -u $USERNAME -o pid,user,comm -w -w"
fi
# disable named-directories autocompletion
@@ -58,18 +58,20 @@ zstyle ':completion:*:*:*:users' ignored-patterns \
# ... unless we really want to.
zstyle '*' single-ignored show
-if [[ $COMPLETION_WAITING_DOTS = true ]]; then
+if [[ ${COMPLETION_WAITING_DOTS:-false} != false ]]; then
expand-or-complete-with-dots() {
- # toggle line-wrapping off and back on again
- [[ -n "$terminfo[rmam]" && -n "$terminfo[smam]" ]] && echoti rmam
- print -Pn "%{%F{red}......%f%}"
- [[ -n "$terminfo[rmam]" && -n "$terminfo[smam]" ]] && echoti smam
-
+ # use $COMPLETION_WAITING_DOTS either as toggle or as the sequence to show
+ [[ $COMPLETION_WAITING_DOTS = true ]] && COMPLETION_WAITING_DOTS="%F{red}…%f"
+ # turn off line wrapping and print prompt-expanded "dot" sequence
+ printf '\e[?7l%s\e[?7h' "${(%)COMPLETION_WAITING_DOTS}"
zle expand-or-complete
zle redisplay
}
zle -N expand-or-complete-with-dots
- bindkey "^I" expand-or-complete-with-dots
+ # Set the function as the default tab completion widget
+ bindkey -M emacs "^I" expand-or-complete-with-dots
+ bindkey -M viins "^I" expand-or-complete-with-dots
+ bindkey -M vicmd "^I" expand-or-complete-with-dots
fi
# automatically load bash completion functions
diff --git a/lib/correction.zsh b/lib/correction.zsh
index c635236b5..4259d3418 100644
--- a/lib/correction.zsh
+++ b/lib/correction.zsh
@@ -9,6 +9,7 @@ if [[ "$ENABLE_CORRECTION" == "true" ]]; then
alias mv='nocorrect mv'
alias mysql='nocorrect mysql'
alias sudo='nocorrect sudo'
+ alias su='nocorrect su'
setopt correct_all
fi
diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh
index 001de42b7..650520797 100644
--- a/lib/diagnostics.zsh
+++ b/lib/diagnostics.zsh
@@ -112,7 +112,7 @@ function _omz_diag_dump_one_big_text() {
command uname -a
builtin echo OSTYPE=$OSTYPE
builtin echo ZSH_VERSION=$ZSH_VERSION
- builtin echo User: $USER
+ builtin echo User: $USERNAME
builtin echo umask: $(umask)
builtin echo
_omz_diag_dump_os_specific_version
diff --git a/lib/functions.zsh b/lib/functions.zsh
index 678e29ce7..73b491a59 100644
--- a/lib/functions.zsh
+++ b/lib/functions.zsh
@@ -1,5 +1,7 @@
function zsh_stats() {
- fc -l 1 | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n20
+ fc -l 1 \
+ | awk '{ CMD[$2]++; count++; } END { for (a in CMD) print CMD[a] " " CMD[a]*100/count "% " a }' \
+ | grep -v "./" | sort -nr | head -20 | column -c3 -s " " -t | nl
}
function uninstall_oh_my_zsh() {
@@ -7,12 +9,8 @@ function uninstall_oh_my_zsh() {
}
function upgrade_oh_my_zsh() {
- env ZSH="$ZSH" sh "$ZSH/tools/upgrade.sh"
- command rm -rf "$ZSH/log/update.lock"
-}
-
-function take() {
- mkdir -p $@ && cd ${@:$#}
+ echo >&2 "${fg[yellow]}Note: \`$0\` is deprecated. Use \`omz update\` instead.$reset_color"
+ omz update
}
function open_command() {
@@ -35,6 +33,38 @@ function open_command() {
${=open_cmd} "$@" &>/dev/null
}
+# take functions
+
+# mkcd is equivalent to takedir
+function mkcd takedir() {
+ mkdir -p $@ && cd ${@:$#}
+}
+
+function takeurl() {
+ local data thedir
+ data="$(mktemp)"
+ curl -L "$1" > "$data"
+ tar xf "$data"
+ thedir="$(tar tf "$data" | head -1)"
+ rm "$data"
+ cd "$thedir"
+}
+
+function takegit() {
+ git clone "$1"
+ cd "$(basename ${1%%.git})"
+}
+
+function take() {
+ if [[ $1 =~ ^(https?|ftp).*\.tar\.(gz|bz2|xz)$ ]]; then
+ takeurl "$1"
+ elif [[ $1 =~ ^([A-Za-z0-9]\+@|https?|git|ssh|ftps?|rsync).*\.git/?$ ]]; then
+ takegit "$1"
+ else
+ takedir "$@"
+ fi
+}
+
#
# Get the value of an alias.
#
@@ -123,6 +153,7 @@ zmodload zsh/langinfo
# -P causes spaces to be encoded as '%20' instead of '+'
function omz_urlencode() {
emulate -L zsh
+ local -a opts
zparseopts -D -E -a opts r m P
local in_str=$1
diff --git a/lib/git.zsh b/lib/git.zsh
index 00cb00b19..9a615e77b 100644
--- a/lib/git.zsh
+++ b/lib/git.zsh
@@ -1,11 +1,35 @@
-# Outputs current branch info in prompt format
+# The git prompt's git commands are read-only and should not interfere with
+# other processes. This environment variable is equivalent to running with `git
+# --no-optional-locks`, but falls back gracefully for older versions of git.
+# See git(1) for and git-status(1) for a description of that flag.
+#
+# We wrap in a local function instead of exporting the variable directly in
+# order to avoid interfering with manually-run git commands by the user.
+function __git_prompt_git() {
+ GIT_OPTIONAL_LOCKS=0 command git "$@"
+}
+
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 [[ "$(command git config --get oh-my-zsh.hide-status 2>/dev/null)" != "1" ]]; then
- ref=$(command git symbolic-ref HEAD 2> /dev/null) || \
- ref=$(command 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
@@ -13,11 +37,11 @@ function parse_git_dirty() {
local STATUS
local -a FLAGS
FLAGS=('--porcelain')
- if [[ "$(command git config --get oh-my-zsh.hide-dirty)" != "1" ]]; then
- if [[ "$DISABLE_UNTRACKED_FILES_DIRTY" == "true" ]]; then
+ if [[ "$(__git_prompt_git config --get oh-my-zsh.hide-dirty)" != "1" ]]; then
+ if [[ "${DISABLE_UNTRACKED_FILES_DIRTY:-}" == "true" ]]; then
FLAGS+='--untracked-files=no'
fi
- case "$GIT_STATUS_IGNORE_SUBMODULES" in
+ case "${GIT_STATUS_IGNORE_SUBMODULES:-}" in
git)
# let git decide (this respects per-repo config in .gitmodules)
;;
@@ -27,7 +51,7 @@ function parse_git_dirty() {
FLAGS+="--ignore-submodules=${GIT_STATUS_IGNORE_SUBMODULES:-dirty}"
;;
esac
- STATUS=$(command git status ${FLAGS} 2> /dev/null | tail -n1)
+ STATUS=$(__git_prompt_git status ${FLAGS} 2> /dev/null | tail -1)
fi
if [[ -n $STATUS ]]; then
echo "$ZSH_THEME_GIT_PROMPT_DIRTY"
@@ -39,10 +63,10 @@ function parse_git_dirty() {
# Gets the difference between the local and remote branches
function git_remote_status() {
local remote ahead behind git_remote_status git_remote_status_detailed
- remote=${$(command git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/}
+ remote=${$(__git_prompt_git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/}
if [[ -n ${remote} ]]; then
- ahead=$(command git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l)
- behind=$(command git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l)
+ ahead=$(__git_prompt_git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l)
+ behind=$(__git_prompt_git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l)
if [[ $ahead -eq 0 ]] && [[ $behind -eq 0 ]]; then
git_remote_status="$ZSH_THEME_GIT_PROMPT_EQUAL_REMOTE"
@@ -71,11 +95,11 @@ function git_remote_status() {
# it's not a symbolic ref, but in a Git repo.
function git_current_branch() {
local ref
- ref=$(command git symbolic-ref --quiet HEAD 2> /dev/null)
+ ref=$(__git_prompt_git symbolic-ref --quiet HEAD 2> /dev/null)
local ret=$?
if [[ $ret != 0 ]]; then
[[ $ret == 128 ]] && return # no git repo.
- ref=$(command git rev-parse --short HEAD 2> /dev/null) || return
+ ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return
fi
echo ${ref#refs/heads/}
}
@@ -83,8 +107,8 @@ function git_current_branch() {
# Gets the number of commits ahead from remote
function git_commits_ahead() {
- if command git rev-parse --git-dir &>/dev/null; then
- local commits="$(git rev-list --count @{upstream}..HEAD 2>/dev/null)"
+ if __git_prompt_git rev-parse --git-dir &>/dev/null; then
+ local commits="$(__git_prompt_git rev-list --count @{upstream}..HEAD 2>/dev/null)"
if [[ -n "$commits" && "$commits" != 0 ]]; then
echo "$ZSH_THEME_GIT_COMMITS_AHEAD_PREFIX$commits$ZSH_THEME_GIT_COMMITS_AHEAD_SUFFIX"
fi
@@ -93,8 +117,8 @@ function git_commits_ahead() {
# Gets the number of commits behind remote
function git_commits_behind() {
- if command git rev-parse --git-dir &>/dev/null; then
- local commits="$(git rev-list --count HEAD..@{upstream} 2>/dev/null)"
+ if __git_prompt_git rev-parse --git-dir &>/dev/null; then
+ local commits="$(__git_prompt_git rev-list --count HEAD..@{upstream} 2>/dev/null)"
if [[ -n "$commits" && "$commits" != 0 ]]; then
echo "$ZSH_THEME_GIT_COMMITS_BEHIND_PREFIX$commits$ZSH_THEME_GIT_COMMITS_BEHIND_SUFFIX"
fi
@@ -103,21 +127,21 @@ function git_commits_behind() {
# Outputs if current branch is ahead of remote
function git_prompt_ahead() {
- if [[ -n "$(command git rev-list origin/$(git_current_branch)..HEAD 2> /dev/null)" ]]; then
+ if [[ -n "$(__git_prompt_git rev-list origin/$(git_current_branch)..HEAD 2> /dev/null)" ]]; then
echo "$ZSH_THEME_GIT_PROMPT_AHEAD"
fi
}
# Outputs if current branch is behind remote
function git_prompt_behind() {
- if [[ -n "$(command git rev-list HEAD..origin/$(git_current_branch) 2> /dev/null)" ]]; then
+ if [[ -n "$(__git_prompt_git rev-list HEAD..origin/$(git_current_branch) 2> /dev/null)" ]]; then
echo "$ZSH_THEME_GIT_PROMPT_BEHIND"
fi
}
# Outputs if current branch exists on remote or not
function git_prompt_remote() {
- if [[ -n "$(command git show-ref origin/$(git_current_branch) 2> /dev/null)" ]]; then
+ if [[ -n "$(__git_prompt_git show-ref origin/$(git_current_branch) 2> /dev/null)" ]]; then
echo "$ZSH_THEME_GIT_PROMPT_REMOTE_EXISTS"
else
echo "$ZSH_THEME_GIT_PROMPT_REMOTE_MISSING"
@@ -127,84 +151,131 @@ function git_prompt_remote() {
# Formats prompt string for current git commit short SHA
function git_prompt_short_sha() {
local SHA
- SHA=$(command git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
+ SHA=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}
# Formats prompt string for current git commit long SHA
function git_prompt_long_sha() {
local SHA
- SHA=$(command git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
+ SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER"
}
-# Get the status of the working tree
function git_prompt_status() {
- local INDEX STATUS
- INDEX=$(command git status --porcelain -b 2> /dev/null)
- STATUS=""
- if $(echo "$INDEX" | command grep -E '^\?\? ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_UNTRACKED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^A ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
- elif $(echo "$INDEX" | grep '^M ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
- elif $(echo "$INDEX" | grep '^MM ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^ M ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
- elif $(echo "$INDEX" | grep '^AM ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
- elif $(echo "$INDEX" | grep '^MM ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
- elif $(echo "$INDEX" | grep '^ T ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^R ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_RENAMED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^ D ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
- elif $(echo "$INDEX" | grep '^D ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
- elif $(echo "$INDEX" | grep '^AD ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
- fi
- if $(command git rev-parse --verify refs/stash >/dev/null 2>&1); then
- STATUS="$ZSH_THEME_GIT_PROMPT_STASHED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^UU ' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_UNMERGED$STATUS"
- fi
- if $(echo "$INDEX" | grep '^## [^ ]\+ .*ahead' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_AHEAD$STATUS"
+ [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return
+
+ # Maps a git status prefix to an internal constant
+ # This cannot use the prompt constants, as they may be empty
+ local -A prefix_constant_map
+ prefix_constant_map=(
+ '\?\? ' 'UNTRACKED'
+ 'A ' 'ADDED'
+ 'M ' 'ADDED'
+ 'MM ' 'MODIFIED'
+ ' M ' 'MODIFIED'
+ 'AM ' 'MODIFIED'
+ ' T ' 'MODIFIED'
+ 'R ' 'RENAMED'
+ ' D ' 'DELETED'
+ 'D ' 'DELETED'
+ 'UU ' 'UNMERGED'
+ 'ahead' 'AHEAD'
+ 'behind' 'BEHIND'
+ 'diverged' 'DIVERGED'
+ 'stashed' 'STASHED'
+ )
+
+ # Maps the internal constant to the prompt theme
+ local -A constant_prompt_map
+ constant_prompt_map=(
+ 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED"
+ 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED"
+ 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED"
+ 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED"
+ 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED"
+ 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED"
+ 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD"
+ 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND"
+ 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED"
+ 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED"
+ )
+
+ # The order that the prompt displays should be added to the prompt
+ local status_constants
+ status_constants=(
+ UNTRACKED ADDED MODIFIED RENAMED DELETED
+ STASHED UNMERGED AHEAD BEHIND DIVERGED
+ )
+
+ local status_text
+ status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)"
+
+ # Don't continue on a catastrophic failure
+ if [[ $? -eq 128 ]]; then
+ return 1
fi
- if $(echo "$INDEX" | grep '^## [^ ]\+ .*behind' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_BEHIND$STATUS"
+
+ # A lookup table of each git status encountered
+ local -A statuses_seen
+
+ if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then
+ statuses_seen[STASHED]=1
fi
- if $(echo "$INDEX" | grep '^## [^ ]\+ .*diverged' &> /dev/null); then
- STATUS="$ZSH_THEME_GIT_PROMPT_DIVERGED$STATUS"
+
+ local status_lines
+ status_lines=("${(@f)${status_text}}")
+
+ # If the tracking line exists, get and parse it
+ if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then
+ local branch_statuses
+ branch_statuses=("${(@s/,/)match}")
+ for branch_status in $branch_statuses; do
+ if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then
+ continue
+ fi
+ local last_parsed_status=$prefix_constant_map[$match[1]]
+ statuses_seen[$last_parsed_status]=$match[2]
+ done
fi
- echo $STATUS
+
+ # For each status prefix, do a regex comparison
+ for status_prefix in ${(k)prefix_constant_map}; do
+ local status_constant="${prefix_constant_map[$status_prefix]}"
+ local status_regex=$'(^|\n)'"$status_prefix"
+
+ if [[ "$status_text" =~ $status_regex ]]; then
+ statuses_seen[$status_constant]=1
+ fi
+ done
+
+ # Display the seen statuses in the order specified
+ local status_prompt
+ for status_constant in $status_constants; do
+ if (( ${+statuses_seen[$status_constant]} )); then
+ local next_display=$constant_prompt_map[$status_constant]
+ status_prompt="$next_display$status_prompt"
+ fi
+ done
+
+ echo $status_prompt
}
# Outputs the name of the current user
# Usage example: $(git_current_user_name)
function git_current_user_name() {
- command git config user.name 2>/dev/null
+ __git_prompt_git config user.name 2>/dev/null
}
# Outputs the email of the current user
# Usage example: $(git_current_user_email)
function git_current_user_email() {
- command git config user.email 2>/dev/null
+ __git_prompt_git config user.email 2>/dev/null
}
# Output the name of the root directory of the git repository
# Usage example: $(git_repo_name)
function git_repo_name() {
local repo_path
- if repo_path="$(git rev-parse --show-toplevel 2>/dev/null)" && [[ -n "$repo_path" ]]; then
+ if repo_path="$(__git_prompt_git rev-parse --show-toplevel 2>/dev/null)" && [[ -n "$repo_path" ]]; then
echo ${repo_path:t}
fi
}
diff --git a/lib/history.zsh b/lib/history.zsh
index 0ee8cfe7a..794076904 100644
--- a/lib/history.zsh
+++ b/lib/history.zsh
@@ -6,7 +6,8 @@ function omz_history {
if [[ -n "$clear" ]]; then
# if -c provided, clobber the history file
echo -n >| "$HISTFILE"
- echo >&2 History file deleted. Reload the session to see its effects.
+ fc -p "$HISTFILE"
+ echo >&2 History file deleted.
elif [[ -n "$list" ]]; then
# if -l provided, run as if calling `fc' directly
builtin fc "$@"
diff --git a/lib/key-bindings.zsh b/lib/key-bindings.zsh
index 0e056dc72..aaa73046e 100644
--- a/lib/key-bindings.zsh
+++ b/lib/key-bindings.zsh
@@ -15,56 +15,101 @@ if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
zle -N zle-line-finish
fi
-bindkey -e # Use emacs key bindings
+# Use emacs key bindings
+bindkey -e
-bindkey '\ew' kill-region # [Esc-w] - Kill from the cursor to the mark
-bindkey -s '\el' 'ls\n' # [Esc-l] - run command: ls
-bindkey '^r' history-incremental-search-backward # [Ctrl-r] - Search backward incrementally for a specified string. The string may begin with ^ to anchor the search to the beginning of the line.
-if [[ "${terminfo[kpp]}" != "" ]]; then
- bindkey "${terminfo[kpp]}" up-line-or-history # [PageUp] - Up a line of history
+# [PageUp] - Up a line of history
+if [[ -n "${terminfo[kpp]}" ]]; then
+ bindkey -M emacs "${terminfo[kpp]}" up-line-or-history
+ bindkey -M viins "${terminfo[kpp]}" up-line-or-history
+ bindkey -M vicmd "${terminfo[kpp]}" up-line-or-history
fi
-if [[ "${terminfo[knp]}" != "" ]]; then
- bindkey "${terminfo[knp]}" down-line-or-history # [PageDown] - Down a line of history
+# [PageDown] - Down a line of history
+if [[ -n "${terminfo[knp]}" ]]; then
+ bindkey -M emacs "${terminfo[knp]}" down-line-or-history
+ bindkey -M viins "${terminfo[knp]}" down-line-or-history
+ bindkey -M vicmd "${terminfo[knp]}" down-line-or-history
fi
-# start typing + [Up-Arrow] - fuzzy find history forward
-if [[ "${terminfo[kcuu1]}" != "" ]]; then
+# Start typing + [Up-Arrow] - fuzzy find history forward
+if [[ -n "${terminfo[kcuu1]}" ]]; then
autoload -U up-line-or-beginning-search
zle -N up-line-or-beginning-search
- bindkey "${terminfo[kcuu1]}" up-line-or-beginning-search
+
+ bindkey -M emacs "${terminfo[kcuu1]}" up-line-or-beginning-search
+ bindkey -M viins "${terminfo[kcuu1]}" up-line-or-beginning-search
+ bindkey -M vicmd "${terminfo[kcuu1]}" up-line-or-beginning-search
fi
-# start typing + [Down-Arrow] - fuzzy find history backward
-if [[ "${terminfo[kcud1]}" != "" ]]; then
+# Start typing + [Down-Arrow] - fuzzy find history backward
+if [[ -n "${terminfo[kcud1]}" ]]; then
autoload -U down-line-or-beginning-search
zle -N down-line-or-beginning-search
- bindkey "${terminfo[kcud1]}" down-line-or-beginning-search
+
+ bindkey -M emacs "${terminfo[kcud1]}" down-line-or-beginning-search
+ bindkey -M viins "${terminfo[kcud1]}" down-line-or-beginning-search
+ bindkey -M vicmd "${terminfo[kcud1]}" down-line-or-beginning-search
fi
-if [[ "${terminfo[khome]}" != "" ]]; then
- bindkey "${terminfo[khome]}" beginning-of-line # [Home] - Go to beginning of line
+# [Home] - Go to beginning of line
+if [[ -n "${terminfo[khome]}" ]]; then
+ bindkey -M emacs "${terminfo[khome]}" beginning-of-line
+ bindkey -M viins "${terminfo[khome]}" beginning-of-line
+ bindkey -M vicmd "${terminfo[khome]}" beginning-of-line
fi
-if [[ "${terminfo[kend]}" != "" ]]; then
- bindkey "${terminfo[kend]}" end-of-line # [End] - Go to end of line
+# [End] - Go to end of line
+if [[ -n "${terminfo[kend]}" ]]; then
+ bindkey -M emacs "${terminfo[kend]}" end-of-line
+ bindkey -M viins "${terminfo[kend]}" end-of-line
+ bindkey -M vicmd "${terminfo[kend]}" end-of-line
fi
-bindkey ' ' magic-space # [Space] - do history expansion
-
-bindkey '^[[1;5C' forward-word # [Ctrl-RightArrow] - move forward one word
-bindkey '^[[1;5D' backward-word # [Ctrl-LeftArrow] - move backward one word
-
-if [[ "${terminfo[kcbt]}" != "" ]]; then
- bindkey "${terminfo[kcbt]}" reverse-menu-complete # [Shift-Tab] - move through the completion menu backwards
+# [Shift-Tab] - move through the completion menu backwards
+if [[ -n "${terminfo[kcbt]}" ]]; then
+ bindkey -M emacs "${terminfo[kcbt]}" reverse-menu-complete
+ bindkey -M viins "${terminfo[kcbt]}" reverse-menu-complete
+ bindkey -M vicmd "${terminfo[kcbt]}" reverse-menu-complete
fi
-bindkey '^?' backward-delete-char # [Backspace] - delete backward
-if [[ "${terminfo[kdch1]}" != "" ]]; then
- bindkey "${terminfo[kdch1]}" delete-char # [Delete] - delete forward
+# [Backspace] - delete backward
+bindkey -M emacs '^?' backward-delete-char
+bindkey -M viins '^?' backward-delete-char
+bindkey -M vicmd '^?' backward-delete-char
+# [Delete] - delete forward
+if [[ -n "${terminfo[kdch1]}" ]]; then
+ bindkey -M emacs "${terminfo[kdch1]}" delete-char
+ bindkey -M viins "${terminfo[kdch1]}" delete-char
+ bindkey -M vicmd "${terminfo[kdch1]}" delete-char
else
- bindkey "^[[3~" delete-char
- bindkey "^[3;5~" delete-char
- bindkey "\e[3~" delete-char
+ bindkey -M emacs "^[[3~" delete-char
+ bindkey -M viins "^[[3~" delete-char
+ bindkey -M vicmd "^[[3~" delete-char
+
+ bindkey -M emacs "^[3;5~" delete-char
+ bindkey -M viins "^[3;5~" delete-char
+ bindkey -M vicmd "^[3;5~" delete-char
fi
+# [Ctrl-Delete] - delete whole forward-word
+bindkey -M emacs '^[[3;5~' kill-word
+bindkey -M viins '^[[3;5~' kill-word
+bindkey -M vicmd '^[[3;5~' kill-word
+
+# [Ctrl-RightArrow] - move forward one word
+bindkey -M emacs '^[[1;5C' forward-word
+bindkey -M viins '^[[1;5C' forward-word
+bindkey -M vicmd '^[[1;5C' forward-word
+# [Ctrl-LeftArrow] - move backward one word
+bindkey -M emacs '^[[1;5D' backward-word
+bindkey -M viins '^[[1;5D' backward-word
+bindkey -M vicmd '^[[1;5D' backward-word
+
+
+bindkey '\ew' kill-region # [Esc-w] - Kill from the cursor to the mark
+bindkey -s '\el' 'ls\n' # [Esc-l] - run command: ls
+bindkey '^r' history-incremental-search-backward # [Ctrl-r] - Search backward incrementally for a specified string. The string may begin with ^ to anchor the search to the beginning of the line.
+bindkey ' ' magic-space # [Space] - don't do history expansion
+
+
# Edit the current command line in $EDITOR
autoload -U edit-command-line
zle -N edit-command-line
diff --git a/lib/nvm.zsh b/lib/nvm.zsh
index 4a8b6811e..2fe57a8f4 100644
--- a/lib/nvm.zsh
+++ b/lib/nvm.zsh
@@ -1,9 +1,6 @@
-# get the node.js version
+# get the nvm-controlled node.js version
function nvm_prompt_info() {
- [[ -f "$NVM_DIR/nvm.sh" ]] || return
- local nvm_prompt
- nvm_prompt=$(node -v 2>/dev/null)
- [[ "${nvm_prompt}x" == "x" ]] && return
- nvm_prompt=${nvm_prompt:1}
+ which nvm &>/dev/null || return
+ local nvm_prompt=${$(nvm current)#v}
echo "${ZSH_THEME_NVM_PROMPT_PREFIX}${nvm_prompt}${ZSH_THEME_NVM_PROMPT_SUFFIX}"
}
diff --git a/lib/prompt_info_functions.zsh b/lib/prompt_info_functions.zsh
index 5069c4b21..48f033da6 100644
--- a/lib/prompt_info_functions.zsh
+++ b/lib/prompt_info_functions.zsh
@@ -18,6 +18,7 @@ function chruby_prompt_info \
vi_mode_prompt_info \
virtualenv_prompt_info \
jenv_prompt_info \
+ tf_prompt_info \
{
return 1
}
diff --git a/lib/termsupport.zsh b/lib/termsupport.zsh
index 3f71eb06a..ef0d78895 100644
--- a/lib/termsupport.zsh
+++ b/lib/termsupport.zsh
@@ -10,31 +10,29 @@ function title {
emulate -L zsh
setopt prompt_subst
- [[ "$EMACS" == *term* ]] && return
+ # Don't set the title if inside emacs, unless using vterm
+ [[ -n "$INSIDE_EMACS" && "$INSIDE_EMACS" != vterm ]] && return
# if $2 is unset use $1 as default
# if it is set and empty, leave it as is
: ${2=$1}
case "$TERM" in
- cygwin|xterm*|putty*|rxvt*|konsole*|ansi)
- print -Pn "\e]2;$2:q\a" # set window name
- print -Pn "\e]1;$1:q\a" # set tab name
+ cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty|st*)
+ print -Pn "\e]2;${2:q}\a" # set window name
+ print -Pn "\e]1;${1:q}\a" # set tab name
;;
screen*|tmux*)
- print -Pn "\ek$1:q\e\\" # set screen hardstatus
+ print -Pn "\ek${1:q}\e\\" # set screen hardstatus
;;
*)
if [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
- print -Pn "\e]2;$2:q\a" # set window name
- print -Pn "\e]1;$1:q\a" # set tab name
+ print -Pn "\e]2;${2:q}\a" # set window name
+ print -Pn "\e]1;${1:q}\a" # set tab name
else
- # Try to use terminfo to set the title
- # If the feature is available set title
- if [[ -n "$terminfo[fsl]" ]] && [[ -n "$terminfo[tsl]" ]]; then
- echoti tsl
- print -Pn "$1"
- echoti fsl
+ # Try to use terminfo to set the title if the feature is available
+ if (( ${+terminfo[fsl]} && ${+terminfo[tsl]} )); then
+ print -Pn "${terminfo[tsl]}$1${terminfo[fsl]}"
fi
fi
;;
@@ -42,7 +40,7 @@ function title {
}
ZSH_THEME_TERM_TAB_TITLE_IDLE="%15<..<%~%<<" #15 char left truncated PWD
-ZSH_THEME_TERM_TITLE_IDLE="%n@%m: %~"
+ZSH_THEME_TERM_TITLE_IDLE="%n@%m:%~"
# Avoid duplication of directory in terminals with independent dir display
if [[ "$TERM_PROGRAM" == Apple_Terminal ]]; then
ZSH_THEME_TERM_TITLE_IDLE="%n@%m"
@@ -50,13 +48,13 @@ fi
# Runs before showing the prompt
function omz_termsupport_precmd {
- [[ "$DISABLE_AUTO_TITLE" == true ]] && return
+ [[ "${DISABLE_AUTO_TITLE:-}" == true ]] && return
title $ZSH_THEME_TERM_TAB_TITLE_IDLE $ZSH_THEME_TERM_TITLE_IDLE
}
# Runs before executing the command
function omz_termsupport_preexec {
- [[ "$DISABLE_AUTO_TITLE" == true ]] && return
+ [[ "${DISABLE_AUTO_TITLE:-}" == true ]] && return
emulate -L zsh
setopt extended_glob
@@ -105,10 +103,12 @@ function omz_termsupport_preexec {
title '$CMD' '%100>...>$LINE%<<'
}
-autoload -U add-zsh-hook
-add-zsh-hook precmd omz_termsupport_precmd
-add-zsh-hook preexec omz_termsupport_preexec
+autoload -Uz add-zsh-hook
+if [[ -z "$INSIDE_EMACS" || "$INSIDE_EMACS" = vterm ]]; then
+ add-zsh-hook precmd omz_termsupport_precmd
+ add-zsh-hook preexec omz_termsupport_preexec
+fi
# Keep Apple Terminal.app's current working directory updated
# Based on this answer: https://superuser.com/a/315029
diff --git a/lib/theme-and-appearance.zsh b/lib/theme-and-appearance.zsh
index 5016d86ca..00947f72d 100644
--- a/lib/theme-and-appearance.zsh
+++ b/lib/theme-and-appearance.zsh
@@ -39,6 +39,11 @@ if [[ "$DISABLE_LS_COLORS" != "true" ]]; then
fi
fi
+# enable diff color if possible.
+if command diff --color /dev/null /dev/null &>/dev/null; then
+ alias diff='diff --color'
+fi
+
setopt auto_cd
setopt multios
setopt prompt_subst