diff options
Diffstat (limited to 'oh-my-zsh/lib')
-rw-r--r-- | oh-my-zsh/lib/bzr.zsh | 10 | ||||
-rw-r--r-- | oh-my-zsh/lib/cli.zsh | 820 | ||||
-rw-r--r-- | oh-my-zsh/lib/clipboard.zsh | 107 | ||||
-rw-r--r-- | oh-my-zsh/lib/compfix.zsh | 44 | ||||
-rw-r--r-- | oh-my-zsh/lib/completion.zsh | 78 | ||||
-rw-r--r-- | oh-my-zsh/lib/correction.zsh | 15 | ||||
-rw-r--r-- | oh-my-zsh/lib/diagnostics.zsh | 353 | ||||
-rw-r--r-- | oh-my-zsh/lib/directories.zsh | 38 | ||||
-rw-r--r-- | oh-my-zsh/lib/functions.zsh | 255 | ||||
-rw-r--r-- | oh-my-zsh/lib/git.zsh | 282 | ||||
-rw-r--r-- | oh-my-zsh/lib/grep.zsh | 41 | ||||
-rw-r--r-- | oh-my-zsh/lib/history.zsh | 40 | ||||
-rw-r--r-- | oh-my-zsh/lib/key-bindings.zsh | 138 | ||||
-rw-r--r-- | oh-my-zsh/lib/misc.zsh | 35 | ||||
-rw-r--r-- | oh-my-zsh/lib/nvm.zsh | 6 | ||||
-rw-r--r-- | oh-my-zsh/lib/prompt_info_functions.zsh | 43 | ||||
-rw-r--r-- | oh-my-zsh/lib/spectrum.zsh | 37 | ||||
-rw-r--r-- | oh-my-zsh/lib/termsupport.zsh | 136 | ||||
-rw-r--r-- | oh-my-zsh/lib/theme-and-appearance.zsh | 59 | ||||
-rw-r--r-- | oh-my-zsh/lib/vcs_info.zsh | 53 |
20 files changed, 2590 insertions, 0 deletions
diff --git a/oh-my-zsh/lib/bzr.zsh b/oh-my-zsh/lib/bzr.zsh new file mode 100644 index 0000000..005a165 --- /dev/null +++ b/oh-my-zsh/lib/bzr.zsh @@ -0,0 +1,10 @@ +## Bazaar integration +## Just works with the GIT integration just add $(bzr_prompt_info) to the PROMPT +function bzr_prompt_info() { + BZR_CB=`bzr nick 2> /dev/null | grep -v "ERROR" | cut -d ":" -f2 | awk -F / '{print "bzr::"$1}'` + if [ -n "$BZR_CB" ]; then + BZR_DIRTY="" + [[ -n `bzr status` ]] && BZR_DIRTY=" %{$fg[red]%} * %{$fg[green]%}" + echo "$ZSH_THEME_SCM_PROMPT_PREFIX$BZR_CB$BZR_DIRTY$ZSH_THEME_GIT_PROMPT_SUFFIX" + fi +}
\ No newline at end of file diff --git a/oh-my-zsh/lib/cli.zsh b/oh-my-zsh/lib/cli.zsh new file mode 100644 index 0000000..fed00d2 --- /dev/null +++ b/oh-my-zsh/lib/cli.zsh @@ -0,0 +1,820 @@ +#!/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 "$@" +} + +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' + 'version:Show the version' + ) + + if (( CURRENT == 2 )); then + _describe 'command' cmds + elif (( CURRENT == 3 )); then + case "$words[2]" in + changelog) local -a refs + refs=("${(@f)$(builtin cd -q "$ZSH"; command git for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}") + _describe 'command' refs ;; + plugin) subcmds=( + 'disable:Disable plugin(s)' + '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 + plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t)) + _describe 'plugin' plugins ;; + theme::(set|use)) + local -aU themes + themes=("$ZSH"/themes/*.zsh-theme(-.N:t:r) "$ZSH_CUSTOM"/**/*.zsh-theme(-.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) + _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 +} + +# If run from a script, do not set the completion function +if (( ${+functions[compdef]} )); then + compdef _omz omz +fi + +## 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 >&2 <<EOF +Usage: omz <command> [options] + +Available commands: + + 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 + version Show the version + +EOF +} + +function _omz::changelog { + local version=${1:-HEAD} format=${3:-"--text"} + + if ( + builtin cd -q "$ZSH" + ! command git show-ref --verify refs/heads/$version && \ + ! command git show-ref --verify refs/tags/$version && \ + ! command git rev-parse --verify "${version}^{commit}" + ) &>/dev/null; then + cat >&2 <<EOF +Usage: ${(j: :)${(s.::.)0#_}} [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[$0::$1] )) || { + cat >&2 <<EOF +Usage: ${(j: :)${(s.::.)0#_}} <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 + + $0::$command "$@" +} + +function _omz::plugin::disable { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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(/[ \t]+(${(j:|:)dis_plugins})/, \"\") # with spaces before + gsub(/(${(j:|:)dis_plugins})[ \t]+/, \"\") # 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 +/^[ \t]*plugins=\([^#]+\).*\$/ { + $awk_subst_plugins + print \$0 + next +} + +# if plugins=() is in multiline form, enable multi flag and disable plugins if they're there +/^[ \t]*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 } +" + + local zdot="${ZDOTDIR:-$HOME}" + local zshrc="${${:-"${zdot}/.zshrc"}:A}" + awk "$awk_script" "$zshrc" > "$zdot/.zshrc.new" \ + && command cp -f "$zshrc" "$zdot/.zshrc.bck" \ + && command mv -f "$zdot/.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 ! command zsh -n "$zdot/.zshrc"; then + _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." + command mv -f "$zdot/.zshrc.bck" "$zshrc" + return 1 + fi + + # Restart the zsh session if there were no errors + _omz::log info "plugins disabled: ${(j:, :)dis_plugins}." + + # Only reload zsh if run in an interactive session + [[ ! -o interactive ]] || _omz::reload +} + +function _omz::plugin::enable { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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 +/^[ \t]*plugins=\([^#]+\).*\$/ { + sub(/\)/, \" $add_plugins&\") + print \$0 + next +} + +# if plugins=() is in multiline form, enable multi flag +/^[ \t]*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 } +" + + local zdot="${ZDOTDIR:-$HOME}" + local zshrc="${${:-"${zdot}/.zshrc"}:A}" + awk "$awk_script" "$zshrc" > "$zdot/.zshrc.new" \ + && command cp -f "$zshrc" "$zdot/.zshrc.bck" \ + && command mv -f "$zdot/.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 ! command zsh -n "$zdot/.zshrc"; then + _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." + command mv -f "$zdot/.zshrc.bck" "$zshrc" + return 1 + fi + + # Restart the zsh session if there were no errors + _omz::log info "plugins enabled: ${(j:, :)add_plugins}." + + # Only reload zsh if run in an interactive session + [[ ! -o interactive ]] || _omz::reload +} + +function _omz::plugin::info { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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 + + 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 + + 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 -lac ${(q-)custom_plugins} + fi + + if (( ${#builtin_plugins} )); then + (( ${#custom_plugins} )) && echo # add a line of separation + + print -P "%U%BBuilt-in plugins%b%u:" + print -lac ${(q-)builtin_plugins} + fi +} + +function _omz::plugin::load { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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 + + # 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 + local -a comp_files + comp_files=($base/_*(N)) + has_completion=$(( $#comp_files > 0 )) + + # 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[$0::$1] )) || { + cat >&2 <<EOF +Usage: ${(j: :)${(s.::.)0#_}} <command> [options] + +Available commands: + + clean Delete all PR branches (ohmyzsh/pull-*) + test <PR_number_or_URL> Fetch PR #NUMBER and rebase against master + +EOF + return 1 + } + + local command="$1" + shift + + $0::$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 + ) +} + +function _omz::pr::test { + # 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: ${(j: :)${(s.::.)0#_}} <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 + } + + # 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..." + local ret gpgsign + { + # Back up commit.gpgsign setting: use --local to get the current repository + # setting, not the global one. If --local is not a known option, it will + # exit with a 129 status code. + gpgsign=$(command git config --local commit.gpgsign 2>/dev/null) || ret=$? + [[ $ret -ne 129 ]] || gpgsign=$(command git config commit.gpgsign 2>/dev/null) + command git config commit.gpgsign false + + 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 + } + } always { + case "$gpgsign" in + "") command git config --unset commit.gpgsign ;; + *) command git config commit.gpgsign "$gpgsign" ;; + esac + } + + _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[$0::$1] )) || { + cat >&2 <<EOF +Usage: ${(j: :)${(s.::.)0#_}} <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 + + $0::$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 -lac ${(q-)custom_themes} + echo + fi + + # Print built-in themes + print -P "%U%BBuilt-in themes%b%u:" + print -lac ${(q-)builtin_themes} +} + +function _omz::theme::set { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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 && /^[ \t]*ZSH_THEME=[^#]+.*$/ { + set=1 + sub(/^[ \t]*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 +} +' + + local zdot="${ZDOTDIR:-$HOME}" + local zshrc="${${:-"${zdot}/.zshrc"}:A}" + awk "$awk_script" "$zshrc" > "$zdot/.zshrc.new" \ + || { + # Prepend ZSH_THEME= line to .zshrc if it doesn't exist + cat <<EOF +ZSH_THEME="$1" # set by \`omz\` + +EOF + cat "$zdot/.zshrc" + } > "$zdot/.zshrc.new" \ + && command cp -f "$zshrc" "$zdot/.zshrc.bck" \ + && command mv -f "$zdot/.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 ! command zsh -n "$zdot/.zshrc"; then + _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." + command mv -f "$zdot/.zshrc.bck" "$zshrc" + return 1 + fi + + # Restart the zsh session if there were no errors + _omz::log info "'$1' theme set correctly." + + # Only reload zsh if run in an interactive session + [[ ! -o interactive ]] || _omz::reload +} + +function _omz::theme::use { + if [[ -z "$1" ]]; then + echo >&2 "Usage: ${(j: :)${(s.::.)0#_}} <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 +} + +function _omz::update { + local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD) + + # Run update script + if [[ "$1" != --unattended ]]; then + ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" --interactive || return $? + else + ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" || return $? + 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 && "$(builtin cd -q "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then + # Old zsh versions don't have ZSH_ARGZERO + local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" + # Check whether to run a login shell + [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" + fi +} + +function _omz::version { + ( + builtin cd -q "$ZSH" + + # Get the version name: + # 1) try tag-like version + # 2) try branch name + # 3) try name-rev (tag~<rev> or branch~<rev>) + local version + version=$(command git describe --tags HEAD 2>/dev/null) \ + || version=$(command git symbolic-ref --quiet --short HEAD 2>/dev/null) \ + || version=$(command git name-rev --no-undefined --name-only --exclude="remotes/*" HEAD 2>/dev/null) \ + || version="<detached>" + + # Get short hash for the current HEAD + local commit=$(command git rev-parse --short HEAD 2>/dev/null) + + # Show version and commit hash + printf "%s (%s)\n" "$version" "$commit" + ) +} diff --git a/oh-my-zsh/lib/clipboard.zsh b/oh-my-zsh/lib/clipboard.zsh new file mode 100644 index 0000000..ad83fc4 --- /dev/null +++ b/oh-my-zsh/lib/clipboard.zsh @@ -0,0 +1,107 @@ +# System clipboard integration +# +# This file has support for doing system clipboard copy and paste operations +# from the command line in a generic cross-platform fashion. +# +# This is uses essentially the same heuristic as neovim, with the additional +# special support for Cygwin. +# See: https://github.com/neovim/neovim/blob/e682d799fa3cf2e80a02d00c6ea874599d58f0e7/runtime/autoload/provider/clipboard.vim#L55-L121 +# +# - pbcopy, pbpaste (macOS) +# - cygwin (Windows running Cygwin) +# - wl-copy, wl-paste (if $WAYLAND_DISPLAY is set) +# - xsel (if $DISPLAY is set) +# - xclip (if $DISPLAY is set) +# - lemonade (for SSH) https://github.com/pocke/lemonade +# - doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/ +# - win32yank (Windows) +# - tmux (if $TMUX is set) +# +# Defines two functions, clipcopy and clippaste, based on the detected platform. +## +# +# clipcopy - Copy data to clipboard +# +# Usage: +# +# <command> | clipcopy - copies stdin to clipboard +# +# clipcopy <file> - copies a file's contents to clipboard +# +## +# +# clippaste - "Paste" data from clipboard to stdout +# +# Usage: +# +# clippaste - writes clipboard's contents to stdout +# +# clippaste | <command> - pastes contents and pipes it to another process +# +# clippaste > <file> - paste contents to a file +# +# Examples: +# +# # Pipe to another process +# clippaste | grep foo +# +# # Paste to a file +# clippaste > file.txt +# +function detect-clipboard() { + emulate -L zsh + + if [[ "${OSTYPE}" == darwin* ]] && (( ${+commands[pbcopy]} )) && (( ${+commands[pbpaste]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | pbcopy; } + function clippaste() { pbpaste; } + elif [[ "${OSTYPE}" == (cygwin|msys)* ]]; then + function clipcopy() { cat "${1:-/dev/stdin}" > /dev/clipboard; } + function clippaste() { cat /dev/clipboard; } + elif [ -n "${WAYLAND_DISPLAY:-}" ] && (( ${+commands[wl-copy]} )) && (( ${+commands[wl-paste]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | wl-copy &>/dev/null &|; } + function clippaste() { wl-paste; } + elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xsel]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | xsel --clipboard --input; } + function clippaste() { xsel --clipboard --output; } + elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xclip]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | xclip -selection clipboard -in &>/dev/null &|; } + function clippaste() { xclip -out -selection clipboard; } + elif (( ${+commands[lemonade]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | lemonade copy; } + function clippaste() { lemonade paste; } + elif (( ${+commands[doitclient]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | doitclient wclip; } + function clippaste() { doitclient wclip -r; } + elif (( ${+commands[win32yank]} )); then + function clipcopy() { cat "${1:-/dev/stdin}" | win32yank -i; } + function clippaste() { win32yank -o; } + elif [[ $OSTYPE == linux-android* ]] && (( $+commands[termux-clipboard-set] )); then + function clipcopy() { cat "${1:-/dev/stdin}" | termux-clipboard-set; } + function clippaste() { termux-clipboard-get; } + elif [ -n "${TMUX:-}" ] && (( ${+commands[tmux]} )); then + function clipcopy() { tmux load-buffer "${1:--}"; } + function clippaste() { tmux save-buffer -; } + elif [[ $(uname -r) = *icrosoft* ]]; then + function clipcopy() { cat "${1:-/dev/stdin}" | clip.exe; } + function clippaste() { powershell.exe -noprofile -command Get-Clipboard; } + else + function _retry_clipboard_detection_or_fail() { + local clipcmd="${1}"; shift + if detect-clipboard; then + "${clipcmd}" "$@" + else + print "${clipcmd}: Platform $OSTYPE not supported or xclip/xsel not installed" >&2 + return 1 + fi + } + function clipcopy() { _retry_clipboard_detection_or_fail clipcopy "$@"; } + function clippaste() { _retry_clipboard_detection_or_fail clippaste "$@"; } + return 1 + fi +} + +# Detect at startup. A non-zero exit here indicates that the dummy clipboards were set, +# which is not really an error. If the user calls them, they will attempt to redetect +# (for example, perhaps the user has now installed xclip) and then either print an error +# or proceed successfully. +detect-clipboard || true diff --git a/oh-my-zsh/lib/compfix.zsh b/oh-my-zsh/lib/compfix.zsh new file mode 100644 index 0000000..b09b283 --- /dev/null +++ b/oh-my-zsh/lib/compfix.zsh @@ -0,0 +1,44 @@ +# Handle completions insecurities (i.e., completion-dependent directories with +# insecure ownership or permissions) by: +# +# * Human-readably notifying the user of these insecurities. +function handle_completion_insecurities() { + # List of the absolute paths of all unique insecure directories, split on + # newline from compaudit()'s output resembling: + # + # There are insecure directories: + # /usr/share/zsh/site-functions + # /usr/share/zsh/5.0.6/functions + # /usr/share/zsh + # /usr/share/zsh/5.0.6 + # + # Since the ignorable first line is printed to stderr and thus not captured, + # stderr is squelched to prevent this output from leaking to the user. + local -aU insecure_dirs + insecure_dirs=( ${(f@):-"$(compaudit 2>/dev/null)"} ) + + # If no such directories exist, get us out of here. + [[ -z "${insecure_dirs}" ]] && return + + # List ownership and permissions of all insecure directories. + print "[oh-my-zsh] Insecure completion-dependent directories detected:" + ls -ld "${(@)insecure_dirs}" + + cat <<EOD + +[oh-my-zsh] For safety, we will not load completions from these directories until +[oh-my-zsh] you fix their permissions and ownership and restart zsh. +[oh-my-zsh] See the above list for directories with group or other writability. + +[oh-my-zsh] To fix your permissions you can do so by disabling +[oh-my-zsh] the write permission of "group" and "others" and making sure that the +[oh-my-zsh] owner of these directories is either root or your current user. +[oh-my-zsh] The following command may help: +[oh-my-zsh] compaudit | xargs chmod g-w,o-w + +[oh-my-zsh] If the above didn't help or you want to skip the verification of +[oh-my-zsh] insecure directories you can set the variable ZSH_DISABLE_COMPFIX to +[oh-my-zsh] "true" before oh-my-zsh is sourced in your zshrc file. + +EOD +} diff --git a/oh-my-zsh/lib/completion.zsh b/oh-my-zsh/lib/completion.zsh new file mode 100644 index 0000000..2c56954 --- /dev/null +++ b/oh-my-zsh/lib/completion.zsh @@ -0,0 +1,78 @@ +# fixme - the load process here seems a bit bizarre +zmodload -i zsh/complist + +WORDCHARS='' + +unsetopt menu_complete # do not autoselect the first completion entry +unsetopt flowcontrol +setopt auto_menu # show completion menu on successive tab press +setopt complete_in_word +setopt always_to_end + +# should this be in keybindings? +bindkey -M menuselect '^o' accept-and-infer-next-history +zstyle ':completion:*:*:*:*:*' menu select + +# case insensitive (all), partial-word and substring completion +if [[ "$CASE_SENSITIVE" = true ]]; then + zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*' +else + if [[ "$HYPHEN_INSENSITIVE" = true ]]; then + zstyle ':completion:*' matcher-list 'm:{a-zA-Z-_}={A-Za-z_-}' 'r:|=*' 'l:|=* r:|=*' + else + zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*' + fi +fi +unset CASE_SENSITIVE HYPHEN_INSENSITIVE + +# Complete . and .. special directories +zstyle ':completion:*' special-dirs true + +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 $USERNAME -o pid,user,comm" +else + zstyle ':completion:*:*:*:*:processes' command "ps -u $USERNAME -o pid,user,comm -w -w" +fi + +# disable named-directories autocompletion +zstyle ':completion:*:cd:*' tag-order local-directories directory-stack path-directories + +# Use caching so that commands like apt and dpkg complete are useable +zstyle ':completion:*' use-cache yes +zstyle ':completion:*' cache-path $ZSH_CACHE_DIR + +# Don't complete uninteresting users +zstyle ':completion:*:*:*:users' ignored-patterns \ + adm amanda apache at avahi avahi-autoipd beaglidx bin cacti canna \ + clamav daemon dbus distcache dnsmasq dovecot fax ftp games gdm \ + gkrellmd gopher hacluster haldaemon halt hsqldb ident junkbust kdm \ + ldap lp mail mailman mailnull man messagebus mldonkey mysql nagios \ + named netdump news nfsnobody nobody nscd ntp nut nx obsrun openvpn \ + operator pcap polkitd postfix postgres privoxy pulse pvm quagga radvd \ + rpc rpcuser rpm rtkit scard shutdown squid sshd statd svn sync tftp \ + usbmux uucp vcsa wwwrun xfs '_*' + +# ... unless we really want to. +zstyle '*' single-ignored show + +if [[ ${COMPLETION_WAITING_DOTS:-false} != false ]]; then + expand-or-complete-with-dots() { + # 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 + # 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 +autoload -U +X bashcompinit && bashcompinit diff --git a/oh-my-zsh/lib/correction.zsh b/oh-my-zsh/lib/correction.zsh new file mode 100644 index 0000000..4259d34 --- /dev/null +++ b/oh-my-zsh/lib/correction.zsh @@ -0,0 +1,15 @@ +if [[ "$ENABLE_CORRECTION" == "true" ]]; then + alias cp='nocorrect cp' + alias ebuild='nocorrect ebuild' + alias gist='nocorrect gist' + alias heroku='nocorrect heroku' + alias hpodder='nocorrect hpodder' + alias man='nocorrect man' + alias mkdir='nocorrect mkdir' + alias mv='nocorrect mv' + alias mysql='nocorrect mysql' + alias sudo='nocorrect sudo' + alias su='nocorrect su' + + setopt correct_all +fi diff --git a/oh-my-zsh/lib/diagnostics.zsh b/oh-my-zsh/lib/diagnostics.zsh new file mode 100644 index 0000000..eaeba7d --- /dev/null +++ b/oh-my-zsh/lib/diagnostics.zsh @@ -0,0 +1,353 @@ +# diagnostics.zsh +# +# Diagnostic and debugging support for oh-my-zsh + +# omz_diagnostic_dump() +# +# Author: Andrew Janke <andrew@apjanke.net> +# +# Usage: +# +# omz_diagnostic_dump [-v] [-V] [file] +# +# NOTE: This is a work in progress. Its interface and behavior are going to change, +# and probably in non-back-compatible ways. +# +# Outputs a bunch of information about the state and configuration of +# oh-my-zsh, zsh, and the user's system. This is intended to provide a +# bunch of context for diagnosing your own or a third party's problems, and to +# be suitable for posting to public bug reports. +# +# The output is human-readable and its format may change over time. It is not +# suitable for parsing. All the output is in one single file so it can be posted +# as a gist or bug comment on GitHub. GitHub doesn't support attaching tarballs +# or other files to bugs; otherwise, this would probably have an option to produce +# tarballs that contain copies of the config and customization files instead of +# catting them all in to one file. +# +# This is intended to be widely portable, and run anywhere that oh-my-zsh does. +# Feel free to report any portability issues as bugs. +# +# This is written in a defensive style so it still works (and can detect) cases when +# basic functionality like echo and which have been redefined. In particular, almost +# everything is invoked with "builtin" or "command", to work in the face of user +# redefinitions. +# +# OPTIONS +# +# [file] Specifies the output file. If not given, a file in the current directory +# is selected automatically. +# +# -v Increase the verbosity of the dump output. May be specified multiple times. +# Verbosity levels: +# 0 - Basic info, shell state, omz configuration, git state +# 1 - (default) Adds key binding info and configuration file contents +# 2 - Adds zcompdump file contents +# +# -V Reduce the verbosity of the dump output. May be specified multiple times. +# +# TODO: +# * Multi-file capture +# * Add automatic gist uploading +# * Consider whether to move default output file location to TMPDIR. More robust +# but less user friendly. +# + +autoload -Uz is-at-least + +function omz_diagnostic_dump() { + emulate -L zsh + + builtin echo "Generating diagnostic dump; please be patient..." + + local thisfcn=omz_diagnostic_dump + local -A opts + local opt_verbose opt_noverbose opt_outfile + local timestamp=$(date +%Y%m%d-%H%M%S) + local outfile=omz_diagdump_$timestamp.txt + builtin zparseopts -A opts -D -- "v+=opt_verbose" "V+=opt_noverbose" + local verbose n_verbose=${#opt_verbose} n_noverbose=${#opt_noverbose} + (( verbose = 1 + n_verbose - n_noverbose )) + + if [[ ${#*} > 0 ]]; then + opt_outfile=$1 + fi + if [[ ${#*} > 1 ]]; then + builtin echo "$thisfcn: error: too many arguments" >&2 + return 1 + fi + if [[ -n "$opt_outfile" ]]; then + outfile="$opt_outfile" + fi + + # Always write directly to a file so terminal escape sequences are + # captured cleanly + _omz_diag_dump_one_big_text &> "$outfile" + if [[ $? != 0 ]]; then + builtin echo "$thisfcn: error while creating diagnostic dump; see $outfile for details" + fi + + builtin echo + builtin echo Diagnostic dump file created at: "$outfile" + builtin echo + builtin echo To share this with OMZ developers, post it as a gist on GitHub + builtin echo at "https://gist.github.com" and share the link to the gist. + builtin echo + builtin echo "WARNING: This dump file contains all your zsh and omz configuration files," + builtin echo "so don't share it publicly if there's sensitive information in them." + builtin echo + +} + +function _omz_diag_dump_one_big_text() { + local program programs progfile md5 + + builtin echo oh-my-zsh diagnostic dump + builtin echo + builtin echo $outfile + builtin echo + + # Basic system and zsh information + command date + command uname -a + builtin echo OSTYPE=$OSTYPE + builtin echo ZSH_VERSION=$ZSH_VERSION + builtin echo User: $USERNAME + builtin echo umask: $(umask) + builtin echo + _omz_diag_dump_os_specific_version + builtin echo + + # Installed programs + programs=(sh zsh ksh bash sed cat grep ls find git posh) + local progfile="" extra_str="" sha_str="" + for program in $programs; do + extra_str="" sha_str="" + progfile=$(builtin which $program) + if [[ $? == 0 ]]; then + if [[ -e $progfile ]]; then + if builtin whence shasum &>/dev/null; then + sha_str=($(command shasum $progfile)) + sha_str=$sha_str[1] + extra_str+=" SHA $sha_str" + fi + if [[ -h "$progfile" ]]; then + extra_str+=" ( -> ${progfile:A} )" + fi + fi + builtin printf '%-9s %-20s %s\n' "$program is" "$progfile" "$extra_str" + else + builtin echo "$program: not found" + fi + done + builtin echo + builtin echo Command Versions: + builtin echo "zsh: $(zsh --version)" + builtin echo "this zsh session: $ZSH_VERSION" + builtin echo "bash: $(bash --version | command grep bash)" + builtin echo "git: $(git --version)" + builtin echo "grep: $(grep --version)" + builtin echo + + # Core command definitions + _omz_diag_dump_check_core_commands || return 1 + builtin echo + + # ZSH Process state + builtin echo Process state: + builtin echo pwd: $PWD + if builtin whence pstree &>/dev/null; then + builtin echo Process tree for this shell: + pstree -p $$ + else + ps -fT + fi + builtin set | command grep -a '^\(ZSH\|plugins\|TERM\|LC_\|LANG\|precmd\|chpwd\|preexec\|FPATH\|TTY\|DISPLAY\|PATH\)\|OMZ' + builtin echo + #TODO: Should this include `env` instead of or in addition to `export`? + builtin echo Exported: + builtin echo $(builtin export | command sed 's/=.*//') + builtin echo + builtin echo Locale: + command locale + builtin echo + + # Zsh installation and configuration + builtin echo Zsh configuration: + builtin echo setopt: $(builtin setopt) + builtin echo + builtin echo zstyle: + builtin zstyle + builtin echo + builtin echo 'compaudit output:' + compaudit + builtin echo + builtin echo '$fpath directories:' + command ls -lad $fpath + builtin echo + + # Oh-my-zsh installation + builtin echo oh-my-zsh installation: + command ls -ld ~/.z* + command ls -ld ~/.oh* + builtin echo + builtin echo oh-my-zsh git state: + (builtin cd $ZSH && builtin echo "HEAD: $(git rev-parse HEAD)" && git remote -v && git status | command grep "[^[:space:]]") + if [[ $verbose -ge 1 ]]; then + (builtin cd $ZSH && git reflog --date=default | command grep pull) + fi + builtin echo + if [[ -e $ZSH_CUSTOM ]]; then + local custom_dir=$ZSH_CUSTOM + if [[ -h $custom_dir ]]; then + custom_dir=$(builtin cd $custom_dir && pwd -P) + fi + builtin echo "oh-my-zsh custom dir:" + builtin echo " $ZSH_CUSTOM ($custom_dir)" + (builtin cd ${custom_dir:h} && command find ${custom_dir:t} -name .git -prune -o -print) + builtin echo + fi + + # Key binding and terminal info + if [[ $verbose -ge 1 ]]; then + builtin echo "bindkey:" + builtin bindkey + builtin echo + builtin echo "infocmp:" + command infocmp -L + builtin echo + fi + + # Configuration file info + local zdotdir=${ZDOTDIR:-$HOME} + builtin echo "Zsh configuration files:" + local cfgfile cfgfiles + # Some files for bash that zsh does not use are intentionally included + # to help with diagnosing behavior differences between bash and zsh + cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout + $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout + ~/.zsh.pre-oh-my-zsh + /etc/bashrc /etc/profile ~/.bashrc ~/.profile ~/.bash_profile ~/.bash_logout ) + command ls -lad $cfgfiles 2>&1 + builtin echo + if [[ $verbose -ge 1 ]]; then + for cfgfile in $cfgfiles; do + _omz_diag_dump_echo_file_w_header $cfgfile + done + fi + builtin echo + builtin echo "Zsh compdump files:" + local dumpfile dumpfiles + command ls -lad $zdotdir/.zcompdump* + dumpfiles=( $zdotdir/.zcompdump*(N) ) + if [[ $verbose -ge 2 ]]; then + for dumpfile in $dumpfiles; do + _omz_diag_dump_echo_file_w_header $dumpfile + done + fi + +} + +function _omz_diag_dump_check_core_commands() { + builtin echo "Core command check:" + local redefined name builtins externals reserved_words + redefined=() + # All the zsh non-module builtin commands + # These are taken from the zsh reference manual for 5.0.2 + # Commands from modules should not be included. + # (For back-compatibility, if any of these are newish, they should be removed, + # or at least made conditional on the version of the current running zsh.) + # "history" is also excluded because OMZ is known to redefine that + reserved_words=( do done esac then elif else fi for case if while function + repeat time until select coproc nocorrect foreach end '!' '[[' '{' '}' + ) + builtins=( alias autoload bg bindkey break builtin bye cd chdir command + comparguments compcall compctl compdescribe compfiles compgroups compquote comptags + comptry compvalues continue dirs disable disown echo echotc echoti emulate + enable eval exec exit false fc fg functions getln getopts hash + jobs kill let limit log logout noglob popd print printf + pushd pushln pwd r read rehash return sched set setopt shift + source suspend test times trap true ttyctl type ulimit umask unalias + unfunction unhash unlimit unset unsetopt vared wait whence where which zcompile + zle zmodload zparseopts zregexparse zstyle ) + if is-at-least 5.1; then + reserved_word+=( declare export integer float local readonly typeset ) + else + builtins+=( declare export integer float local readonly typeset ) + fi + builtins_fatal=( builtin command local ) + externals=( zsh ) + for name in $reserved_words; do + if [[ $(builtin whence -w $name) != "$name: reserved" ]]; then + builtin echo "reserved word '$name' has been redefined" + builtin which $name + redefined+=$name + fi + done + for name in $builtins; do + if [[ $(builtin whence -w $name) != "$name: builtin" ]]; then + builtin echo "builtin '$name' has been redefined" + builtin which $name + redefined+=$name + fi + done + for name in $externals; do + if [[ $(builtin whence -w $name) != "$name: command" ]]; then + builtin echo "command '$name' has been redefined" + builtin which $name + redefined+=$name + fi + done + + if [[ -n "$redefined" ]]; then + builtin echo "SOME CORE COMMANDS HAVE BEEN REDEFINED: $redefined" + else + builtin echo "All core commands are defined normally" + fi + +} + +function _omz_diag_dump_echo_file_w_header() { + local file=$1 + if [[ ( -f $file || -h $file ) ]]; then + builtin echo "========== $file ==========" + if [[ -h $file ]]; then + builtin echo "========== ( => ${file:A} ) ==========" + fi + command cat $file + builtin echo "========== end $file ==========" + builtin echo + elif [[ -d $file ]]; then + builtin echo "File '$file' is a directory" + elif [[ ! -e $file ]]; then + builtin echo "File '$file' does not exist" + else + command ls -lad "$file" + fi +} + +function _omz_diag_dump_os_specific_version() { + local osname osver version_file version_files + case "$OSTYPE" in + darwin*) + osname=$(command sw_vers -productName) + osver=$(command sw_vers -productVersion) + builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)" + ;; + cygwin) + command systeminfo | command head -n 4 | command tail -n 2 + ;; + esac + + if builtin which lsb_release >/dev/null; then + builtin echo "OS Release: $(command lsb_release -s -d)" + fi + + version_files=( /etc/*-release(N) /etc/*-version(N) /etc/*_version(N) ) + for version_file in $version_files; do + builtin echo "$version_file:" + command cat "$version_file" + builtin echo + done +} + diff --git a/oh-my-zsh/lib/directories.zsh b/oh-my-zsh/lib/directories.zsh new file mode 100644 index 0000000..c62f564 --- /dev/null +++ b/oh-my-zsh/lib/directories.zsh @@ -0,0 +1,38 @@ +# Changing/making/removing directory +setopt auto_pushd +setopt pushd_ignore_dups +setopt pushdminus + +alias -g ...='../..' +alias -g ....='../../..' +alias -g .....='../../../..' +alias -g ......='../../../../..' + +alias -- -='cd -' +alias 1='cd -1' +alias 2='cd -2' +alias 3='cd -3' +alias 4='cd -4' +alias 5='cd -5' +alias 6='cd -6' +alias 7='cd -7' +alias 8='cd -8' +alias 9='cd -9' + +alias md='mkdir -p' +alias rd=rmdir + +function d () { + if [[ -n $1 ]]; then + dirs "$@" + else + dirs -v | head -n 10 + fi +} +compdef _dirs d + +# List directory contents +alias lsa='ls -lah' +alias l='ls -lah' +alias ll='ls -lh' +alias la='ls -lAh' diff --git a/oh-my-zsh/lib/functions.zsh b/oh-my-zsh/lib/functions.zsh new file mode 100644 index 0000000..dfcc4d9 --- /dev/null +++ b/oh-my-zsh/lib/functions.zsh @@ -0,0 +1,255 @@ +function zsh_stats() { + 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 -n 20 | column -c3 -s " " -t | nl +} + +function uninstall_oh_my_zsh() { + env ZSH="$ZSH" sh "$ZSH/tools/uninstall.sh" +} + +function upgrade_oh_my_zsh() { + echo >&2 "${fg[yellow]}Note: \`$0\` is deprecated. Use \`omz update\` instead.$reset_color" + omz update +} + +function open_command() { + local open_cmd + + # define the open command + case "$OSTYPE" in + darwin*) open_cmd='open' ;; + cygwin*) open_cmd='cygstart' ;; + linux*) [[ "$(uname -r)" != *icrosoft* ]] && open_cmd='nohup xdg-open' || { + open_cmd='cmd.exe /c start ""' + [[ -e "$1" ]] && { 1="$(wslpath -w "${1:a}")" || return 1 } + } ;; + msys*) open_cmd='start ""' ;; + *) echo "Platform $OSTYPE not supported" + return 1 + ;; + esac + + ${=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 -n 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. +# +# Arguments: +# 1. alias - The alias to get its value from +# STDOUT: +# The value of alias $1 (if it has one). +# Return value: +# 0 if the alias was found, +# 1 if it does not exist +# +function alias_value() { + (( $+aliases[$1] )) && echo $aliases[$1] +} + +# +# Try to get the value of an alias, +# otherwise return the input. +# +# Arguments: +# 1. alias - The alias to get its value from +# STDOUT: +# The value of alias $1, or $1 if there is no alias $1. +# Return value: +# Always 0 +# +function try_alias_value() { + alias_value "$1" || echo "$1" +} + +# +# Set variable "$1" to default value "$2" if "$1" is not yet defined. +# +# Arguments: +# 1. name - The variable to set +# 2. val - The default value +# Return value: +# 0 if the variable exists, 3 if it was set +# +function default() { + (( $+parameters[$1] )) && return 0 + typeset -g "$1"="$2" && return 3 +} + +# +# Set environment variable "$1" to default value "$2" if "$1" is not yet defined. +# +# Arguments: +# 1. name - The env variable to set +# 2. val - The default value +# Return value: +# 0 if the env variable exists, 3 if it was set +# +function env_default() { + [[ ${parameters[$1]} = *-export* ]] && return 0 + export "$1=$2" && return 3 +} + + +# Required for $langinfo +zmodload zsh/langinfo + +# URL-encode a string +# +# Encodes a string using RFC 2396 URL-encoding (%-escaped). +# See: https://www.ietf.org/rfc/rfc2396.txt +# +# By default, reserved characters and unreserved "mark" characters are +# not escaped by this function. This allows the common usage of passing +# an entire URL in, and encoding just special characters in it, with +# the expectation that reserved and mark characters are used appropriately. +# The -r and -m options turn on escaping of the reserved and mark characters, +# respectively, which allows arbitrary strings to be fully escaped for +# embedding inside URLs, where reserved characters might be misinterpreted. +# +# Prints the encoded string on stdout. +# Returns nonzero if encoding failed. +# +# Usage: +# omz_urlencode [-r] [-m] [-P] <string> [<string> ...] +# +# -r causes reserved characters (;/?:@&=+$,) to be escaped +# +# -m causes "mark" characters (_.!~*''()-) to be escaped +# +# -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="$@" + local url_str="" + local spaces_as_plus + if [[ -z $opts[(r)-P] ]]; then spaces_as_plus=1; fi + local str="$in_str" + + # URLs must use UTF-8 encoding; convert str to UTF-8 if required + local encoding=$langinfo[CODESET] + local safe_encodings + safe_encodings=(UTF-8 utf8 US-ASCII) + if [[ -z ${safe_encodings[(r)$encoding]} ]]; then + str=$(echo -E "$str" | iconv -f $encoding -t UTF-8) + if [[ $? != 0 ]]; then + echo "Error converting string from $encoding to UTF-8" >&2 + return 1 + fi + fi + + # Use LC_CTYPE=C to process text byte-by-byte + local i byte ord LC_ALL=C + export LC_ALL + local reserved=';/?:@&=+$,' + local mark='_.!~*''()-' + local dont_escape="[A-Za-z0-9" + if [[ -z $opts[(r)-r] ]]; then + dont_escape+=$reserved + fi + # $mark must be last because of the "-" + if [[ -z $opts[(r)-m] ]]; then + dont_escape+=$mark + fi + dont_escape+="]" + + # Implemented to use a single printf call and avoid subshells in the loop, + # for performance (primarily on Windows). + local url_str="" + for (( i = 1; i <= ${#str}; ++i )); do + byte="$str[i]" + if [[ "$byte" =~ "$dont_escape" ]]; then + url_str+="$byte" + else + if [[ "$byte" == " " && -n $spaces_as_plus ]]; then + url_str+="+" + else + ord=$(( [##16] #byte )) + url_str+="%$ord" + fi + fi + done + echo -E "$url_str" +} + +# URL-decode a string +# +# Decodes a RFC 2396 URL-encoded (%-escaped) string. +# This decodes the '+' and '%' escapes in the input string, and leaves +# other characters unchanged. Does not enforce that the input is a +# valid URL-encoded string. This is a convenience to allow callers to +# pass in a full URL or similar strings and decode them for human +# presentation. +# +# Outputs the encoded string on stdout. +# Returns nonzero if encoding failed. +# +# Usage: +# omz_urldecode <urlstring> - prints decoded string followed by a newline +function omz_urldecode { + emulate -L zsh + local encoded_url=$1 + + # Work bytewise, since URLs escape UTF-8 octets + local caller_encoding=$langinfo[CODESET] + local LC_ALL=C + export LC_ALL + + # Change + back to ' ' + local tmp=${encoded_url:gs/+/ /} + # Protect other escapes to pass through the printf unchanged + tmp=${tmp:gs/\\/\\\\/} + # Handle %-escapes by turning them into `\xXX` printf escapes + tmp=${tmp:gs/%/\\x/} + local decoded="$(printf -- "$tmp")" + + # Now we have a UTF-8 encoded string in the variable. We need to re-encode + # it if caller is in a non-UTF-8 locale. + local -a safe_encodings + safe_encodings=(UTF-8 utf8 US-ASCII) + if [[ -z ${safe_encodings[(r)$caller_encoding]} ]]; then + decoded=$(echo -E "$decoded" | iconv -f UTF-8 -t $caller_encoding) + if [[ $? != 0 ]]; then + echo "Error converting string from UTF-8 to $caller_encoding" >&2 + return 1 + fi + fi + + echo -E "$decoded" +} diff --git a/oh-my-zsh/lib/git.zsh b/oh-my-zsh/lib/git.zsh new file mode 100644 index 0000000..f049f73 --- /dev/null +++ b/oh-my-zsh/lib/git.zsh @@ -0,0 +1,282 @@ +# 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 + ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ + || ref=$(__git_prompt_git describe --tags --exact-match 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:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" +} + +# Checks if working tree is dirty +function parse_git_dirty() { + local STATUS + local -a FLAGS + FLAGS=('--porcelain') + 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 + git) + # let git decide (this respects per-repo config in .gitmodules) + ;; + *) + # if unset: ignore dirty submodules + # other values are passed to --ignore-submodules + FLAGS+="--ignore-submodules=${GIT_STATUS_IGNORE_SUBMODULES:-dirty}" + ;; + esac + STATUS=$(__git_prompt_git status ${FLAGS} 2> /dev/null | tail -n 1) + fi + if [[ -n $STATUS ]]; then + echo "$ZSH_THEME_GIT_PROMPT_DIRTY" + else + echo "$ZSH_THEME_GIT_PROMPT_CLEAN" + fi +} + +# 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=${$(__git_prompt_git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/} + if [[ -n ${remote} ]]; then + 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" + elif [[ $ahead -gt 0 ]] && [[ $behind -eq 0 ]]; then + git_remote_status="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE" + git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}" + elif [[ $behind -gt 0 ]] && [[ $ahead -eq 0 ]]; then + git_remote_status="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" + git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" + elif [[ $ahead -gt 0 ]] && [[ $behind -gt 0 ]]; then + git_remote_status="$ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE" + git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" + fi + + if [[ -n $ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_DETAILED ]]; then + git_remote_status="$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_PREFIX${remote:gs/%/%%}$git_remote_status_detailed$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_SUFFIX" + fi + + echo $git_remote_status + fi +} + +# Outputs the name of the current branch +# Usage example: git pull origin $(git_current_branch) +# Using '--quiet' with 'symbolic-ref' will not cause a fatal error (128) if +# it's not a symbolic ref, but in a Git repo. +function git_current_branch() { + local ref + ref=$(__git_prompt_git symbolic-ref --quiet HEAD 2> /dev/null) + local ret=$? + if [[ $ret != 0 ]]; then + [[ $ret == 128 ]] && return # no git repo. + ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return + fi + echo ${ref#refs/heads/} +} + + +# Gets the number of commits ahead from remote +function git_commits_ahead() { + 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 + fi +} + +# Gets the number of commits behind remote +function git_commits_behind() { + 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 + fi +} + +# Outputs if current branch is ahead of remote +function git_prompt_ahead() { + 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 "$(__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 "$(__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" + fi +} + +# Formats prompt string for current git commit short SHA +function git_prompt_short_sha() { + local SHA + 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=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" +} + +function git_prompt_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 + + # 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 + + 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 + + # 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() { + __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() { + __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_prompt_git rev-parse --show-toplevel 2>/dev/null)" && [[ -n "$repo_path" ]]; then + echo ${repo_path:t} + fi +} diff --git a/oh-my-zsh/lib/grep.zsh b/oh-my-zsh/lib/grep.zsh new file mode 100644 index 0000000..54e0f69 --- /dev/null +++ b/oh-my-zsh/lib/grep.zsh @@ -0,0 +1,41 @@ +__GREP_CACHE_FILE="$ZSH_CACHE_DIR"/grep-alias + +# See if there's a cache file modified in the last day +__GREP_ALIAS_CACHES=("$__GREP_CACHE_FILE"(Nm-1)) +if [[ -n "$__GREP_ALIAS_CACHES" ]]; then + source "$__GREP_CACHE_FILE" +else + grep-flags-available() { + command grep "$@" "" &>/dev/null <<< "" + } + + # Ignore these folders (if the necessary grep flags are available) + EXC_FOLDERS="{.bzr,CVS,.git,.hg,.svn,.idea,.tox}" + + # Check for --exclude-dir, otherwise check for --exclude. If --exclude + # isn't available, --color won't be either (they were released at the same + # time (v2.5): https://git.savannah.gnu.org/cgit/grep.git/tree/NEWS?id=1236f007 + if grep-flags-available --color=auto --exclude-dir=.cvs; then + GREP_OPTIONS="--color=auto --exclude-dir=$EXC_FOLDERS" + elif grep-flags-available --color=auto --exclude=.cvs; then + GREP_OPTIONS="--color=auto --exclude=$EXC_FOLDERS" + fi + + if [[ -n "$GREP_OPTIONS" ]]; then + # export grep, egrep and fgrep settings + alias grep="grep $GREP_OPTIONS" + alias egrep="grep -E $GREP_OPTIONS" + alias fgrep="grep -F $GREP_OPTIONS" + + # write to cache file if cache directory is writable + if [[ -w "$ZSH_CACHE_DIR" ]]; then + alias -L grep egrep fgrep >| "$__GREP_CACHE_FILE" + fi + fi + + # Clean up + unset GREP_OPTIONS EXC_FOLDERS + unfunction grep-flags-available +fi + +unset __GREP_CACHE_FILE __GREP_ALIAS_CACHES diff --git a/oh-my-zsh/lib/history.zsh b/oh-my-zsh/lib/history.zsh new file mode 100644 index 0000000..7940769 --- /dev/null +++ b/oh-my-zsh/lib/history.zsh @@ -0,0 +1,40 @@ +## History wrapper +function omz_history { + local clear list + zparseopts -E c=clear l=list + + if [[ -n "$clear" ]]; then + # if -c provided, clobber the history file + echo -n >| "$HISTFILE" + fc -p "$HISTFILE" + echo >&2 History file deleted. + elif [[ -n "$list" ]]; then + # if -l provided, run as if calling `fc' directly + builtin fc "$@" + else + # unless a number is provided, show all history events (starting from 1) + [[ ${@[-1]-} = *[0-9]* ]] && builtin fc -l "$@" || builtin fc -l "$@" 1 + fi +} + +# Timestamp format +case ${HIST_STAMPS-} in + "mm/dd/yyyy") alias history='omz_history -f' ;; + "dd.mm.yyyy") alias history='omz_history -E' ;; + "yyyy-mm-dd") alias history='omz_history -i' ;; + "") alias history='omz_history' ;; + *) alias history="omz_history -t '$HIST_STAMPS'" ;; +esac + +## History file configuration +[ -z "$HISTFILE" ] && HISTFILE="$HOME/.zsh_history" +[ "$HISTSIZE" -lt 50000 ] && HISTSIZE=50000 +[ "$SAVEHIST" -lt 10000 ] && SAVEHIST=10000 + +## History command configuration +setopt extended_history # record timestamp of command in HISTFILE +setopt hist_expire_dups_first # delete duplicates first when HISTFILE size exceeds HISTSIZE +setopt hist_ignore_dups # ignore duplicated commands history list +setopt hist_ignore_space # ignore commands that start with space +setopt hist_verify # show command with history expansion to user before running it +setopt share_history # share command history data diff --git a/oh-my-zsh/lib/key-bindings.zsh b/oh-my-zsh/lib/key-bindings.zsh new file mode 100644 index 0000000..aaa7304 --- /dev/null +++ b/oh-my-zsh/lib/key-bindings.zsh @@ -0,0 +1,138 @@ +# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html +# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Builtins +# http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Standard-Widgets + +# Make sure that the terminal is in application mode when zle is active, since +# only then values from $terminfo are valid +if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then + function zle-line-init() { + echoti smkx + } + function zle-line-finish() { + echoti rmkx + } + zle -N zle-line-init + zle -N zle-line-finish +fi + +# Use emacs key bindings +bindkey -e + +# [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 +# [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 [[ -n "${terminfo[kcuu1]}" ]]; then + autoload -U up-line-or-beginning-search + zle -N 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 [[ -n "${terminfo[kcud1]}" ]]; then + autoload -U down-line-or-beginning-search + zle -N 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 + +# [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 +# [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 + +# [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 + +# [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 -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 +bindkey '\C-x\C-e' edit-command-line + +# file rename magick +bindkey "^[m" copy-prev-shell-word + +# consider emacs keybindings: + +#bindkey -e ## emacs key bindings +# +#bindkey '^[[A' up-line-or-search +#bindkey '^[[B' down-line-or-search +#bindkey '^[^[[C' emacs-forward-word +#bindkey '^[^[[D' emacs-backward-word +# +#bindkey -s '^X^Z' '%-^M' +#bindkey '^[e' expand-cmd-path +#bindkey '^[^I' reverse-menu-complete +#bindkey '^X^N' accept-and-infer-next-history +#bindkey '^W' kill-region +#bindkey '^I' complete-word +## Fix weird sequence that rxvt produces +#bindkey -s '^[[Z' '\t' +# diff --git a/oh-my-zsh/lib/misc.zsh b/oh-my-zsh/lib/misc.zsh new file mode 100644 index 0000000..1f63708 --- /dev/null +++ b/oh-my-zsh/lib/misc.zsh @@ -0,0 +1,35 @@ +autoload -Uz is-at-least + +# *-magic is known buggy in some versions; disable if so +if [[ $DISABLE_MAGIC_FUNCTIONS != true ]]; then + for d in $fpath; do + if [[ -e "$d/url-quote-magic" ]]; then + if is-at-least 5.1; then + autoload -Uz bracketed-paste-magic + zle -N bracketed-paste bracketed-paste-magic + fi + autoload -Uz url-quote-magic + zle -N self-insert url-quote-magic + break + fi + done +fi + +## jobs +setopt long_list_jobs + +env_default 'PAGER' 'less' +env_default 'LESS' '-R' + +## super user alias +alias _='sudo ' + +## more intelligent acking for ubuntu users and no alias for users without ack +if (( $+commands[ack-grep] )); then + alias afind='ack-grep -il' +elif (( $+commands[ack] )); then + alias afind='ack -il' +fi + +# recognize comments +setopt interactivecomments diff --git a/oh-my-zsh/lib/nvm.zsh b/oh-my-zsh/lib/nvm.zsh new file mode 100644 index 0000000..a8989f9 --- /dev/null +++ b/oh-my-zsh/lib/nvm.zsh @@ -0,0 +1,6 @@ +# get the nvm-controlled node.js version +function nvm_prompt_info() { + which nvm &>/dev/null || return + local nvm_prompt=${$(nvm current)#v} + echo "${ZSH_THEME_NVM_PROMPT_PREFIX}${nvm_prompt:gs/%/%%}${ZSH_THEME_NVM_PROMPT_SUFFIX}" +} diff --git a/oh-my-zsh/lib/prompt_info_functions.zsh b/oh-my-zsh/lib/prompt_info_functions.zsh new file mode 100644 index 0000000..e553584 --- /dev/null +++ b/oh-my-zsh/lib/prompt_info_functions.zsh @@ -0,0 +1,43 @@ +# *_prompt_info functions for usage in your prompt +# +# Plugin creators, please add your *_prompt_info function to the list +# of dummy implementations to help theme creators not receiving errors +# without the need of implementing conditional clauses. +# +# See also lib/bzr.zsh, lib/git.zsh and lib/nvm.zsh for +# git_prompt_info, bzr_prompt_info and nvm_prompt_info + +# Dummy implementations that return false to prevent command_not_found +# errors with themes, that implement these functions +# Real implementations will be used when the respective plugins are loaded +function chruby_prompt_info \ + rbenv_prompt_info \ + hg_prompt_info \ + pyenv_prompt_info \ + svn_prompt_info \ + vi_mode_prompt_info \ + virtualenv_prompt_info \ + jenv_prompt_info \ + tf_prompt_info \ +{ + return 1 +} + +# oh-my-zsh supports an rvm prompt by default +# get the name of the rvm ruby version +function rvm_prompt_info() { + [ -f $HOME/.rvm/bin/rvm-prompt ] || return 1 + local rvm_prompt + rvm_prompt=$($HOME/.rvm/bin/rvm-prompt ${=ZSH_THEME_RVM_PROMPT_OPTIONS} 2>/dev/null) + [[ -z "${rvm_prompt}" ]] && return 1 + echo "${ZSH_THEME_RUBY_PROMPT_PREFIX}${rvm_prompt:gs/%/%%}${ZSH_THEME_RUBY_PROMPT_SUFFIX}" +} + +ZSH_THEME_RVM_PROMPT_OPTIONS="i v g" + + +# use this to enable users to see their ruby version, no matter which +# version management system they use +function ruby_prompt_info() { + echo $(rvm_prompt_info || rbenv_prompt_info || chruby_prompt_info) +} diff --git a/oh-my-zsh/lib/spectrum.zsh b/oh-my-zsh/lib/spectrum.zsh new file mode 100644 index 0000000..97f5c36 --- /dev/null +++ b/oh-my-zsh/lib/spectrum.zsh @@ -0,0 +1,37 @@ +# A script to make using 256 colors in zsh less painful. +# P.C. Shyamshankar <sykora@lucentbeing.com> +# Copied from https://github.com/sykora/etc/blob/master/zsh/functions/spectrum/ + +typeset -AHg FX FG BG + +FX=( + reset "%{[00m%}" + bold "%{[01m%}" no-bold "%{[22m%}" + italic "%{[03m%}" no-italic "%{[23m%}" + underline "%{[04m%}" no-underline "%{[24m%}" + blink "%{[05m%}" no-blink "%{[25m%}" + reverse "%{[07m%}" no-reverse "%{[27m%}" +) + +for color in {000..255}; do + FG[$color]="%{[38;5;${color}m%}" + BG[$color]="%{[48;5;${color}m%}" +done + +# Show all 256 colors with color number +function spectrum_ls() { + setopt localoptions nopromptsubst + local ZSH_SPECTRUM_TEXT=${ZSH_SPECTRUM_TEXT:-Arma virumque cano Troiae qui primus ab oris} + for code in {000..255}; do + print -P -- "$code: ${FG[$code]}${ZSH_SPECTRUM_TEXT}%{$reset_color%}" + done +} + +# Show all 256 colors where the background is set to specific color +function spectrum_bls() { + setopt localoptions nopromptsubst + local ZSH_SPECTRUM_TEXT=${ZSH_SPECTRUM_TEXT:-Arma virumque cano Troiae qui primus ab oris} + for code in {000..255}; do + print -P -- "$code: ${BG[$code]}${ZSH_SPECTRUM_TEXT}%{$reset_color%}" + done +} diff --git a/oh-my-zsh/lib/termsupport.zsh b/oh-my-zsh/lib/termsupport.zsh new file mode 100644 index 0000000..80ca7ef --- /dev/null +++ b/oh-my-zsh/lib/termsupport.zsh @@ -0,0 +1,136 @@ +# Set terminal window and tab/icon title +# +# usage: title short_tab_title [long_window_title] +# +# See: http://www.faqs.org/docs/Linux-mini/Xterm-Title.html#ss3.1 +# Fully supports screen, iterm, and probably most modern xterm and rxvt +# (In screen, only short_tab_title is used) +# Limited support for Apple Terminal (Terminal can't set window and tab separately) +function title { + setopt localoptions nopromptsubst + + # 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|mlterm*|alacritty|st*|foot) + 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 + ;; + *) + 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 + else + # 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 + ;; + esac +} + +ZSH_THEME_TERM_TAB_TITLE_IDLE="%15<..<%~%<<" #15 char left truncated PWD +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" +fi + +# Runs before showing the prompt +function omz_termsupport_precmd { + [[ "${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 + + emulate -L zsh + setopt extended_glob + + # split command into array of arguments + local -a cmdargs + cmdargs=("${(z)2}") + # if running fg, extract the command from the job description + if [[ "${cmdargs[1]}" = fg ]]; then + # get the job id from the first argument passed to the fg command + local job_id jobspec="${cmdargs[2]#%}" + # logic based on jobs arguments: + # http://zsh.sourceforge.net/Doc/Release/Jobs-_0026-Signals.html#Jobs + # https://www.zsh.org/mla/users/2007/msg00704.html + case "$jobspec" in + <->) # %number argument: + # use the same <number> passed as an argument + job_id=${jobspec} ;; + ""|%|+) # empty, %% or %+ argument: + # use the current job, which appears with a + in $jobstates: + # suspended:+:5071=suspended (tty output) + job_id=${(k)jobstates[(r)*:+:*]} ;; + -) # %- argument: + # use the previous job, which appears with a - in $jobstates: + # suspended:-:6493=suspended (signal) + job_id=${(k)jobstates[(r)*:-:*]} ;; + [?]*) # %?string argument: + # use $jobtexts to match for a job whose command *contains* <string> + job_id=${(k)jobtexts[(r)*${(Q)jobspec}*]} ;; + *) # %string argument: + # use $jobtexts to match for a job whose command *starts with* <string> + job_id=${(k)jobtexts[(r)${(Q)jobspec}*]} ;; + esac + + # override preexec function arguments with job command + if [[ -n "${jobtexts[$job_id]}" ]]; then + 1="${jobtexts[$job_id]}" + 2="${jobtexts[$job_id]}" + fi + fi + + # cmd name only, or if this is sudo or ssh, the next cmd + local CMD="${1[(wr)^(*=*|sudo|ssh|mosh|rake|-*)]:gs/%/%%}" + local LINE="${2:gs/%/%%}" + + title "$CMD" "%100>...>${LINE}%<<" +} + +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 +# With extra fixes to handle multibyte chars and non-UTF-8 locales + +if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then + # Emits the control sequence to notify Terminal.app of the cwd + # Identifies the directory using a file: URI scheme, including + # the host name to disambiguate local vs. remote paths. + function update_terminalapp_cwd() { + emulate -L zsh + + # Percent-encode the host and path names. + local URL_HOST URL_PATH + URL_HOST="$(omz_urlencode -P $HOST)" || return 1 + URL_PATH="$(omz_urlencode -P $PWD)" || return 1 + + # Undocumented Terminal.app-specific control sequence + printf '\e]7;%s\a' "file://$URL_HOST$URL_PATH" + } + + # Use a precmd hook instead of a chpwd hook to avoid contaminating output + add-zsh-hook precmd update_terminalapp_cwd + # Run once to get initial cwd set + update_terminalapp_cwd +fi diff --git a/oh-my-zsh/lib/theme-and-appearance.zsh b/oh-my-zsh/lib/theme-and-appearance.zsh new file mode 100644 index 0000000..00947f7 --- /dev/null +++ b/oh-my-zsh/lib/theme-and-appearance.zsh @@ -0,0 +1,59 @@ +# ls colors +autoload -U colors && colors + +# Enable ls colors +export LSCOLORS="Gxfxcxdxbxegedabagacad" + +# TODO organise this chaotic logic + +if [[ "$DISABLE_LS_COLORS" != "true" ]]; then + # Find the option for using colors in ls, depending on the version + if [[ "$OSTYPE" == netbsd* ]]; then + # On NetBSD, test if "gls" (GNU ls) is installed (this one supports colors); + # otherwise, leave ls as is, because NetBSD's ls doesn't support -G + gls --color -d . &>/dev/null && alias ls='gls --color=tty' + elif [[ "$OSTYPE" == openbsd* ]]; then + # On OpenBSD, "gls" (ls from GNU coreutils) and "colorls" (ls from base, + # with color and multibyte support) are available from ports. "colorls" + # will be installed on purpose and can't be pulled in by installing + # coreutils, so prefer it to "gls". + gls --color -d . &>/dev/null && alias ls='gls --color=tty' + colorls -G -d . &>/dev/null && alias ls='colorls -G' + elif [[ "$OSTYPE" == (darwin|freebsd)* ]]; then + # this is a good alias, it works by default just using $LSCOLORS + ls -G . &>/dev/null && alias ls='ls -G' + + # only use coreutils ls if there is a dircolors customization present ($LS_COLORS or .dircolors file) + # otherwise, gls will use the default color scheme which is ugly af + [[ -n "$LS_COLORS" || -f "$HOME/.dircolors" ]] && gls --color -d . &>/dev/null && alias ls='gls --color=tty' + else + # For GNU ls, we use the default ls color theme. They can later be overwritten by themes. + if [[ -z "$LS_COLORS" ]]; then + (( $+commands[dircolors] )) && eval "$(dircolors -b)" + fi + + ls --color -d . &>/dev/null && alias ls='ls --color=tty' || { ls -G . &>/dev/null && alias ls='ls -G' } + + # Take advantage of $LS_COLORS for completion as well. + zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" + 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 + +[[ -n "$WINDOW" ]] && SCREEN_NO="%B$WINDOW%b " || SCREEN_NO="" + +# git theming default: Variables for theming the git info prompt +ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Prefix at the very beginning of the prompt, before the branch name +ZSH_THEME_GIT_PROMPT_SUFFIX=")" # At the very end of the prompt +ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty +ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean +ZSH_THEME_RUBY_PROMPT_PREFIX="(" +ZSH_THEME_RUBY_PROMPT_SUFFIX=")" diff --git a/oh-my-zsh/lib/vcs_info.zsh b/oh-my-zsh/lib/vcs_info.zsh new file mode 100644 index 0000000..e60938c --- /dev/null +++ b/oh-my-zsh/lib/vcs_info.zsh @@ -0,0 +1,53 @@ +# Don't skip this file until a Zsh release does the necessary quoting. +# This is because even though 5.8.1 undid recursive prompt_subst inside +# prompt sequences, % characters in relevant fields will still be rendered +# incorrectly in vcs_info, on all Zsh releases up to writing this. +# +# There is no release yet that does this right, since it requires changing +# how what vcs_info hooks expect to receive. Even so, I'd rather be correct +# and break custom vcs_info hooks than have a broken prompt. + +# Quote necessary $hook_com[<field>] items just before they are used +# in the line "VCS_INFO_hook 'post-backend'" of the VCS_INFO_formats +# function, where <field> is: +# +# base: the full path of the repository's root directory. +# base-name: the name of the repository's root directory. +# branch: the name of the currently checked out branch. +# misc: a string that may contain anything the vcs_info backend wants. +# revision: an identifier of the currently checked out revision. +# subdir: the path of the current directory relative to the +# repository's root directory. +# +# This patch %-quotes these fields previous to their use in vcs_info hooks and +# the zformat call and, eventually, when they get expanded in the prompt. +# It's important to quote these here, and not later after hooks have modified the +# fields, because then we could be quoting % characters from valid prompt sequences, +# like %F{color}, %B, etc. +# +# 32 │ hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})" +# 33 │ hook_com[subdir_orig]="${hook_com[subdir]}" +# 34 │ +# 35 + │ for tmp in base base-name branch misc revision subdir; do +# 36 + │ hook_com[$tmp]="${hook_com[$tmp]//\%/%%}" +# 37 + │ done +# 38 + │ +# 39 │ VCS_INFO_hook 'post-backend' +# +# This is especially important so that no command substitution is performed +# due to malicious input as a consequence of CVE-2021-45444, which affects +# zsh versions from 5.0.3 to 5.8. +# +autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return + +# We use $tmp here because it's already a local variable in VCS_INFO_formats +typeset PATCH='for tmp (base base-name branch misc revision subdir) hook_com[$tmp]="${hook_com[$tmp]//\%/%%}"' +# Unique string to avoid reapplying the patch if this code gets called twice +typeset PATCH_ID=vcs_info-patch-9b9840f2-91e5-4471-af84-9e9a0dc68c1b +# Only patch the VCS_INFO_formats function if not already patched +if [[ "$functions[VCS_INFO_formats]" != *$PATCH_ID* ]]; then + regexp-replace 'functions[VCS_INFO_formats]' \ + "VCS_INFO_hook 'post-backend'" \ + ': ${PATCH_ID}; ${PATCH}; ${MATCH}' +fi +unset PATCH PATCH_ID |