summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/async_prompt.zsh145
-rw-r--r--lib/bzr.zsh20
-rw-r--r--lib/cli.zsh165
-rw-r--r--lib/clipboard.zsh4
-rw-r--r--lib/compfix.zsh2
-rw-r--r--lib/completion.zsh4
-rw-r--r--lib/diagnostics.zsh24
-rw-r--r--lib/functions.zsh17
-rw-r--r--lib/git.zsh287
-rw-r--r--lib/grep.zsh6
-rw-r--r--lib/history.zsh26
-rw-r--r--lib/key-bindings.zsh23
-rw-r--r--lib/misc.zsh2
-rw-r--r--lib/prompt_info_functions.zsh3
-rw-r--r--lib/spectrum.zsh1
-rw-r--r--lib/termsupport.zsh9
-rw-r--r--lib/tests/cli.test.zsh169
17 files changed, 734 insertions, 173 deletions
diff --git a/lib/async_prompt.zsh b/lib/async_prompt.zsh
new file mode 100644
index 000000000..151e24b8c
--- /dev/null
+++ b/lib/async_prompt.zsh
@@ -0,0 +1,145 @@
+# The async code is taken from
+# https://github.com/zsh-users/zsh-autosuggestions/blob/master/src/async.zsh
+# https://github.com/woefe/git-prompt.zsh/blob/master/git-prompt.zsh
+
+zmodload zsh/system
+autoload -Uz is-at-least
+
+# For now, async prompt function handlers are set up like so:
+# First, define the async function handler and register the handler
+# with _omz_register_handler:
+#
+# function _git_prompt_status_async {
+# # Do some expensive operation that outputs to stdout
+# }
+# _omz_register_handler _git_prompt_status_async
+#
+# Then add a stub prompt function in `$PROMPT` or similar prompt variables,
+# which will show the output of "$_OMZ_ASYNC_OUTPUT[handler_name]":
+#
+# function git_prompt_status {
+# echo -n $_OMZ_ASYNC_OUTPUT[_git_prompt_status_async]
+# }
+#
+# RPROMPT='$(git_prompt_status)'
+#
+# This API is subject to change and optimization. Rely on it at your own risk.
+
+function _omz_register_handler {
+ setopt localoptions noksharrays unset
+ typeset -ga _omz_async_functions
+ # we want to do nothing if there's no $1 function or we already set it up
+ if [[ -z "$1" ]] || (( ! ${+functions[$1]} )) \
+ || (( ${_omz_async_functions[(Ie)$1]} )); then
+ return
+ fi
+ _omz_async_functions+=("$1")
+ # let's add the hook to async_request if it's not there yet
+ if (( ! ${precmd_functions[(Ie)_omz_async_request]} )) \
+ && (( ${+functions[_omz_async_request]})); then
+ autoload -Uz add-zsh-hook
+ add-zsh-hook precmd _omz_async_request
+ fi
+}
+
+# Set up async handlers and callbacks
+function _omz_async_request {
+ setopt localoptions noksharrays unset
+ local -i ret=$?
+ typeset -gA _OMZ_ASYNC_FDS _OMZ_ASYNC_PIDS _OMZ_ASYNC_OUTPUT
+
+ # executor runs a subshell for all async requests based on key
+ local handler
+ for handler in ${_omz_async_functions}; do
+ (( ${+functions[$handler]} )) || continue
+
+ local fd=${_OMZ_ASYNC_FDS[$handler]:--1}
+ local pid=${_OMZ_ASYNC_PIDS[$handler]:--1}
+
+ # If we've got a pending request, cancel it
+ if (( fd != -1 && pid != -1 )) && { true <&$fd } 2>/dev/null; then
+ # Close the file descriptor and remove the handler
+ exec {fd}<&-
+ zle -F $fd
+
+ # Zsh will make a new process group for the child process only if job
+ # control is enabled (MONITOR option)
+ if [[ -o MONITOR ]]; then
+ # Send the signal to the process group to kill any processes that may
+ # have been forked by the async function handler
+ kill -TERM -$pid 2>/dev/null
+ else
+ # Kill just the child process since it wasn't placed in a new process
+ # group. If the async function handler forked any child processes they may
+ # be orphaned and left behind.
+ kill -TERM $pid 2>/dev/null
+ fi
+ fi
+
+ # Define global variables to store the file descriptor, PID and output
+ _OMZ_ASYNC_FDS[$handler]=-1
+ _OMZ_ASYNC_PIDS[$handler]=-1
+
+ # Fork a process to fetch the git status and open a pipe to read from it
+ exec {fd}< <(
+ # Tell parent process our PID
+ builtin echo ${sysparams[pid]}
+ # Set exit code for the handler if used
+ () { return $ret }
+ # Run the async function handler
+ $handler
+ )
+
+ # Save FD for handler
+ _OMZ_ASYNC_FDS[$handler]=$fd
+
+ # There's a weird bug here where ^C stops working unless we force a fork
+ # See https://github.com/zsh-users/zsh-autosuggestions/issues/364
+ # and https://github.com/zsh-users/zsh-autosuggestions/pull/612
+ is-at-least 5.8 || command true
+
+ # Save the PID from the handler child process
+ read -u $fd "_OMZ_ASYNC_PIDS[$handler]"
+
+ # When the fd is readable, call the response handler
+ zle -F "$fd" _omz_async_callback
+ done
+}
+
+# Called when new data is ready to be read from the pipe
+function _omz_async_callback() {
+ emulate -L zsh
+
+ local fd=$1 # First arg will be fd ready for reading
+ local err=$2 # Second arg will be passed in case of error
+
+ if [[ -z "$err" || "$err" == "hup" ]]; then
+ # Get handler name from fd
+ local handler="${(k)_OMZ_ASYNC_FDS[(r)$fd]}"
+
+ # Store old output which is supposed to be already printed
+ local old_output="${_OMZ_ASYNC_OUTPUT[$handler]}"
+
+ # Read output from fd
+ IFS= read -r -u $fd -d '' "_OMZ_ASYNC_OUTPUT[$handler]"
+
+ # Repaint prompt if output has changed
+ if [[ "$old_output" != "${_OMZ_ASYNC_OUTPUT[$handler]}" ]]; then
+ zle .reset-prompt
+ zle -R
+ fi
+
+ # Close the fd
+ exec {fd}<&-
+ fi
+
+ # Always remove the handler
+ zle -F "$fd"
+
+ # Unset global FD variable to prevent closing user created FDs in the precmd hook
+ _OMZ_ASYNC_FDS[$handler]=-1
+ _OMZ_ASYNC_PIDS[$handler]=-1
+}
+
+autoload -Uz add-zsh-hook
+add-zsh-hook precmd _omz_async_request
diff --git a/lib/bzr.zsh b/lib/bzr.zsh
index 005a16500..78273d578 100644
--- a/lib/bzr.zsh
+++ b/lib/bzr.zsh
@@ -1,10 +1,14 @@
## Bazaar integration
-## Just works with the GIT integration just add $(bzr_prompt_info) to the PROMPT
+## Just works with the GIT integration. 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
+ local bzr_branch
+ bzr_branch=$(bzr nick 2>/dev/null) || return
+
+ if [[ -n "$bzr_branch" ]]; then
+ local bzr_dirty=""
+ if [[ -n $(bzr status 2>/dev/null) ]]; then
+ bzr_dirty=" %{$fg[red]%}*%{$reset_color%}"
+ fi
+ printf "%s%s%s%s" "$ZSH_THEME_SCM_PROMPT_PREFIX" "bzr::${bzr_branch##*:}" "$bzr_dirty" "$ZSH_THEME_GIT_PROMPT_SUFFIX"
+ fi
+}
diff --git a/lib/cli.zsh b/lib/cli.zsh
index 561c1b98b..55938ba8a 100644
--- a/lib/cli.zsh
+++ b/lib/cli.zsh
@@ -1,6 +1,7 @@
#!/usr/bin/env zsh
function omz {
+ setopt localoptions noksharrays
[[ $# -gt 0 ]] || {
_omz::help
return 1
@@ -27,6 +28,7 @@ function _omz {
'plugin:Manage plugins'
'pr:Manage Oh My Zsh Pull Requests'
'reload:Reload the current zsh session'
+ 'shop:Open the Oh My Zsh shop'
'theme:Manage themes'
'update:Update Oh My Zsh'
'version:Show the version'
@@ -71,6 +73,10 @@ function _omz {
local -aU plugins
plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t))
_describe 'plugin' plugins ;;
+ plugin::list)
+ local -a opts
+ opts=('--enabled:List enabled plugins only')
+ _describe -o 'options' opts ;;
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"/:::))
@@ -168,6 +174,7 @@ Available commands:
plugin <command> Manage plugins
pr <command> Manage Oh My Zsh Pull Requests
reload Reload the current zsh session
+ shop Open the Oh My Zsh shop
theme <command> Manage themes
update Update Oh My Zsh
version Show the version
@@ -192,7 +199,7 @@ EOF
return 1
fi
- "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format"
+ ZSH="$ZSH" command zsh -f "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format"
}
function _omz::plugin {
@@ -205,7 +212,7 @@ 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
+ list [--enabled] List Oh My Zsh plugins
load <plugin> Load plugin(s)
EOF
@@ -241,10 +248,18 @@ function _omz::plugin::disable {
# 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)
+ gsub(/[ \t]+(${(j:|:)dis_plugins})[ \t]+/, \" \") # with spaces before or after
+ gsub(/[ \t]+(${(j:|:)dis_plugins})$/, \"\") # with spaces before and EOL
+ gsub(/^(${(j:|:)dis_plugins})[ \t]+/, \"\") # with BOL and spaces after
+
+ gsub(/\((${(j:|:)dis_plugins})[ \t]+/, \"(\") # with parenthesis before and spaces after
+ gsub(/[ \t]+(${(j:|:)dis_plugins})\)/, \")\") # with spaces before or parenthesis after
+ gsub(/\((${(j:|:)dis_plugins})\)/, \"()\") # with only parentheses
+
+ gsub(/^(${(j:|:)dis_plugins})\)/, \")\") # with BOL and closing parenthesis
+ gsub(/\((${(j:|:)dis_plugins})$/, \"(\") # with opening parenthesis and EOL
"
+
# Disable plugins awk script
local awk_script="
# if plugins=() is in oneline form, substitute disabled plugins and go to next line
@@ -336,20 +351,40 @@ function _omz::plugin::enable {
next
}
-# if plugins=() is in multiline form, enable multi flag
+# if plugins=() is in multiline form, enable multi flag and indent by default with 2 spaces
/^[ \t]*plugins=\(/ {
multi=1
+ indent=\" \"
+ print \$0
+ next
}
# if multi flag is enabled and we find a valid closing parenthesis,
-# add new plugins and disable multi flag
+# add new plugins with proper indent and disable multi flag
multi == 1 && /^[^#]*\)/ {
multi=0
- sub(/\)/, \" $add_plugins&\")
+ split(\"$add_plugins\",p,\" \")
+ for (i in p) {
+ print indent p[i]
+ }
print \$0
next
}
+# if multi flag is enabled and we didnt find a closing parenthesis,
+# get the indentation level to match when adding plugins
+multi == 1 && /^[^#]*/ {
+ indent=\"\"
+ for (i = 1; i <= length(\$0); i++) {
+ char=substr(\$0, i, 1)
+ if (char == \" \" || char == \"\t\") {
+ indent = indent char
+ } else {
+ break
+ }
+ }
+}
+
{ print \$0 }
"
@@ -389,8 +424,23 @@ function _omz::plugin::info {
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
+ # If being piped, just cat the README
+ if [[ ! -t 1 ]]; then
+ cat "$readme"
+ return $?
+ fi
+
+ # Enrich the README display depending on the tools we have
+ # - glow: https://github.com/charmbracelet/glow
+ # - bat: https://github.com/sharkdp/bat
+ # - less: typical pager command
+ case 1 in
+ ${+commands[glow]}) glow -p "$readme" ;;
+ ${+commands[bat]}) bat -l md --style plain "$readme" ;;
+ ${+commands[less]}) less "$readme" ;;
+ *) cat "$readme" ;;
+ esac
+ return $?
fi
done
@@ -405,8 +455,21 @@ function _omz::plugin::info {
function _omz::plugin::list {
local -a custom_plugins builtin_plugins
- custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t))
- builtin_plugins=("$ZSH"/plugins/*(-/N:t))
+
+ # If --enabled is provided, only list what's enabled
+ if [[ "$1" == "--enabled" ]]; then
+ local plugin
+ for plugin in "${plugins[@]}"; do
+ if [[ -d "${ZSH_CUSTOM}/plugins/${plugin}" ]]; then
+ custom_plugins+=("${plugin}")
+ elif [[ -d "${ZSH}/plugins/${plugin}" ]]; then
+ builtin_plugins+=("${plugin}")
+ fi
+ done
+ else
+ custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t))
+ builtin_plugins=("$ZSH"/plugins/*(-/N:t))
+ fi
# If the command is being piped, print all found line by line
if [[ ! -t 1 ]]; then
@@ -448,7 +511,7 @@ function _omz::plugin::load {
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
+ # It is a valid plugin, add its directory to $fpath unless it is already there
elif (( ! ${fpath[(Ie)$base]} )); then
fpath=("$base" $fpath)
fi
@@ -560,10 +623,48 @@ function _omz::pr::test {
done
(( $found )) || {
- _omz::log error "could not found the ohmyzsh git remote. Aborting..."
+ _omz::log error "could not find the ohmyzsh git remote. Aborting..."
return 1
}
+ # Check if Pull Request has the "testers needed" label
+ _omz::log info "checking if PR #$1 has the 'testers needed' label..."
+ local pr_json label label_id="MDU6TGFiZWw4NzY1NTkwNA=="
+ pr_json=$(
+ curl -fsSL \
+ -H "Accept: application/vnd.github+json" \
+ -H "X-GitHub-Api-Version: 2022-11-28" \
+ "https://api.github.com/repos/ohmyzsh/ohmyzsh/pulls/$1"
+ )
+
+ if [[ $? -gt 0 || -z "$pr_json" ]]; then
+ _omz::log error "error when trying to fetch PR #$1 from GitHub."
+ return 1
+ fi
+
+ # Check if the label is present with jq or grep
+ if (( $+commands[jq] )); then
+ label="$(command jq ".labels.[] | select(.node_id == \"$label_id\")" <<< "$pr_json")"
+ else
+ label="$(command grep "\"$label_id\"" <<< "$pr_json" 2>/dev/null)"
+ fi
+
+ # If a maintainer hasn't labeled the PR to test, explain the security risk
+ if [[ -z "$label" ]]; then
+ _omz::log warn "PR #$1 does not have the 'testers needed' label. This means that the PR"
+ _omz::log warn "has not been reviewed by a maintainer and may contain malicious code."
+
+ # Ask for explicit confirmation: user needs to type "yes" to continue
+ _omz::log prompt "Do you want to continue testing it? [yes/N] "
+ builtin read -r
+ if [[ "${REPLY:l}" != yes ]]; then
+ _omz::log error "PR test canceled. Please ask a maintainer to review and label the PR."
+ return 1
+ else
+ _omz::log warn "Continuing to check out and test PR #$1. Be careful!"
+ fi
+ 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 || {
@@ -622,6 +723,15 @@ function _omz::pr::test {
)
}
+function _omz::shop {
+ local shop_url="https://commitgoods.com/collections/oh-my-zsh"
+
+ _omz::log info "Opening Oh My Zsh shop in your browser..."
+ _omz::log info "$shop_url"
+
+ open_command "$shop_url"
+}
+
function _omz::reload {
# Delete current completion cache
command rm -f $_comp_dumpfile $ZSH_COMPDUMP
@@ -773,15 +883,28 @@ function _omz::theme::use {
}
function _omz::update {
- local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD)
+ # Check if git command is available
+ (( $+commands[git] )) || {
+ _omz::log error "git is not installed. Aborting..."
+ return 1
+ }
+
+ # Check if --unattended was passed
+ [[ "$1" != --unattended ]] || {
+ _omz::log error "the \`\e[2m--unattended\e[0m\` flag is no longer supported, use the \`\e[2mupgrade.sh\e[0m\` script instead."
+ _omz::log error "for more information see https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#how-do-i-update-oh-my-zsh"
+ return 1
+ }
+
+ local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD 2>/dev/null)
+ [[ $? -eq 0 ]] || {
+ _omz::log error "\`$ZSH\` is not a git directory. Aborting..."
+ return 1
+ }
# Run update script
zstyle -s ':omz:update' verbose verbose_mode || verbose_mode=default
- if [[ "$1" != --unattended ]]; then
- ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -i -v $verbose_mode || return $?
- else
- ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -v $verbose_mode || return $?
- fi
+ ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -i -v $verbose_mode || return $?
# Update last updated file
zmodload zsh/datetime
@@ -790,7 +913,7 @@ function _omz::update {
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
+ if [[ "$(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
diff --git a/lib/clipboard.zsh b/lib/clipboard.zsh
index 4b37abc9b..27e81525a 100644
--- a/lib/clipboard.zsh
+++ b/lib/clipboard.zsh
@@ -62,7 +62,7 @@ function detect-clipboard() {
function clippaste() { powershell.exe -noprofile -command Get-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; }
+ function clippaste() { wl-paste --no-newline; }
elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xsel]} )); then
function clipcopy() { cat "${1:-/dev/stdin}" | xsel --clipboard --input; }
function clippaste() { xsel --clipboard --output; }
@@ -82,7 +82,7 @@ function detect-clipboard() {
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 clipcopy() { tmux load-buffer -w "${1:--}"; }
function clippaste() { tmux save-buffer -; }
else
function _retry_clipboard_detection_or_fail() {
diff --git a/lib/compfix.zsh b/lib/compfix.zsh
index b09b283f2..2fe9d9e64 100644
--- a/lib/compfix.zsh
+++ b/lib/compfix.zsh
@@ -13,7 +13,7 @@ function handle_completion_insecurities() {
# /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.
+ # stderr is squelched to prevent this output from leaking to the user.
local -aU insecure_dirs
insecure_dirs=( ${(f@):-"$(compaudit 2>/dev/null)"} )
diff --git a/lib/completion.zsh b/lib/completion.zsh
index 63379b53f..3823c2544 100644
--- a/lib/completion.zsh
+++ b/lib/completion.zsh
@@ -40,7 +40,7 @@ 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
+# Use caching so that commands like apt and dpkg complete are usable
zstyle ':completion:*' use-cache yes
zstyle ':completion:*' cache-path $ZSH_CACHE_DIR
@@ -49,7 +49,7 @@ 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 \
+ 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 \
diff --git a/lib/diagnostics.zsh b/lib/diagnostics.zsh
index eaeba7d23..d67e6fab4 100644
--- a/lib/diagnostics.zsh
+++ b/lib/diagnostics.zsh
@@ -30,7 +30,7 @@
#
# 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
+# everything is invoked with "builtin" or "command", to work in the face of user
# redefinitions.
#
# OPTIONS
@@ -59,7 +59,7 @@ 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
@@ -90,7 +90,7 @@ function omz_diagnostic_dump() {
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 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,"
@@ -105,8 +105,8 @@ function _omz_diag_dump_one_big_text() {
builtin echo oh-my-zsh diagnostic dump
builtin echo
builtin echo $outfile
- builtin echo
-
+ builtin echo
+
# Basic system and zsh information
command date
command uname -a
@@ -151,7 +151,7 @@ function _omz_diag_dump_one_big_text() {
# Core command definitions
_omz_diag_dump_check_core_commands || return 1
- builtin echo
+ builtin echo
# ZSH Process state
builtin echo Process state:
@@ -167,7 +167,7 @@ function _omz_diag_dump_one_big_text() {
#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
builtin echo Locale:
command locale
builtin echo
@@ -181,7 +181,7 @@ function _omz_diag_dump_one_big_text() {
builtin echo
builtin echo 'compaudit output:'
compaudit
- builtin echo
+ builtin echo
builtin echo '$fpath directories:'
command ls -lad $fpath
builtin echo
@@ -224,7 +224,7 @@ function _omz_diag_dump_one_big_text() {
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
+ 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 )
@@ -258,8 +258,8 @@ function _omz_diag_dump_check_core_commands() {
# (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 '!' '[[' '{' '}'
+ 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
@@ -331,7 +331,7 @@ function _omz_diag_dump_os_specific_version() {
case "$OSTYPE" in
darwin*)
osname=$(command sw_vers -productName)
- osver=$(command sw_vers -productVersion)
+ osver=$(command sw_vers -productVersion)
builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)"
;;
cygwin)
diff --git a/lib/functions.zsh b/lib/functions.zsh
index f5c671f9c..330b0e3e9 100644
--- a/lib/functions.zsh
+++ b/lib/functions.zsh
@@ -23,6 +23,9 @@ function open_command() {
linux*) [[ "$(uname -r)" != *icrosoft* ]] && open_cmd='nohup xdg-open' || {
open_cmd='cmd.exe /c start ""'
[[ -e "$1" ]] && { 1="$(wslpath -w "${1:a}")" || return 1 }
+ [[ "$1" = (http|https)://* ]] && {
+ 1="$(echo "$1" | sed -E 's/([&|()<>^])/^\1/g')" || return 1
+ }
} ;;
msys*) open_cmd='start ""' ;;
*) echo "Platform $OSTYPE not supported"
@@ -57,6 +60,16 @@ function takeurl() {
cd "$thedir"
}
+function takezip() {
+ local data thedir
+ data="$(mktemp)"
+ curl -L "$1" > "$data"
+ unzip "$data" -d "./"
+ thedir="$(unzip -l "$data" | awk 'NR==4 {print $4}' | sed 's/\/.*//')"
+ rm "$data"
+ cd "$thedir"
+}
+
function takegit() {
git clone "$1"
cd "$(basename ${1%%.git})"
@@ -65,6 +78,8 @@ function takegit() {
function take() {
if [[ $1 =~ ^(https?|ftp).*\.(tar\.(gz|bz2|xz)|tgz)$ ]]; then
takeurl "$1"
+ elif [[ $1 =~ ^(https?|ftp).*\.(zip)$ ]]; then
+ takezip "$1"
elif [[ $1 =~ ^([A-Za-z0-9]\+@|https?|git|ssh|ftps?|rsync).*\.git/?$ ]]; then
takegit "$1"
else
@@ -160,6 +175,8 @@ zmodload zsh/langinfo
# -P causes spaces to be encoded as '%20' instead of '+'
function omz_urlencode() {
emulate -L zsh
+ setopt norematchpcre
+
local -a opts
zparseopts -D -E -a opts r m P
diff --git a/lib/git.zsh b/lib/git.zsh
index f049f73c2..8d38f3268 100644
--- a/lib/git.zsh
+++ b/lib/git.zsh
@@ -1,3 +1,5 @@
+autoload -Uz is-at-least
+
# 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.
@@ -9,14 +11,18 @@ function __git_prompt_git() {
GIT_OPTIONAL_LOCKS=0 command git "$@"
}
-function git_prompt_info() {
+function _omz_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
+ || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then
return 0
fi
+ # Get either:
+ # - the current branch name
+ # - the tag name if we are on a tag
+ # - the short SHA of the current commit
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) \
@@ -33,6 +39,172 @@ function git_prompt_info() {
echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}"
}
+function _omz_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 ' 'MODIFIED'
+ '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
+}
+
+# Use async version if setting is enabled, or unset but zsh version is at least 5.0.6.
+# This avoids async prompt issues caused by previous zsh versions:
+# - https://github.com/ohmyzsh/ohmyzsh/issues/12331
+# - https://github.com/ohmyzsh/ohmyzsh/issues/12360
+# TODO(2024-06-12): @mcornella remove workaround when CentOS 7 reaches EOL
+local _style
+if zstyle -t ':omz:alpha:lib:git' async-prompt \
+ || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then
+ function git_prompt_info() {
+ if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then
+ echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}"
+ fi
+ }
+
+ function git_prompt_status() {
+ if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then
+ echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}"
+ fi
+ }
+
+ # Conditionally register the async handler, only if it's needed in $PROMPT
+ # or any of the other prompt variables
+ function _defer_async_git_register() {
+ # Check if git_prompt_info is used in a prompt variable
+ case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in
+ *(\$\(git_prompt_info\)|\`git_prompt_info\`)*)
+ _omz_register_handler _omz_git_prompt_info
+ ;;
+ esac
+
+ case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in
+ *(\$\(git_prompt_status\)|\`git_prompt_status\`)*)
+ _omz_register_handler _omz_git_prompt_status
+ ;;
+ esac
+
+ add-zsh-hook -d precmd _defer_async_git_register
+ unset -f _defer_async_git_register
+ }
+
+ # Register the async handler first. This needs to be done before
+ # the async request prompt is run
+ precmd_functions=(_defer_async_git_register $precmd_functions)
+elif zstyle -s ':omz:alpha:lib:git' async-prompt _style && [[ $_style == "force" ]]; then
+ function git_prompt_info() {
+ if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then
+ echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}"
+ fi
+ }
+
+ function git_prompt_status() {
+ if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then
+ echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}"
+ fi
+ }
+
+ _omz_register_handler _omz_git_prompt_info
+ _omz_register_handler _omz_git_prompt_status
+else
+ function git_prompt_info() {
+ _omz_git_prompt_info
+ }
+ function git_prompt_status() {
+ _omz_git_prompt_status
+ }
+fi
+
# Checks if working tree is dirty
function parse_git_dirty() {
local STATUS
@@ -105,6 +277,18 @@ function git_current_branch() {
echo ${ref#refs/heads/}
}
+# Outputs the name of the previously checked out branch
+# Usage example: git pull origin $(git_previous_branch)
+# rev-parse --symbolic-full-name @{-1} only prints if it is a branch
+function git_previous_branch() {
+ local ref
+ ref=$(__git_prompt_git rev-parse --quiet --symbolic-full-name @{-1} 2> /dev/null)
+ local ret=$?
+ if [[ $ret != 0 ]] || [[ -z $ref ]]; then
+ return # no git repo or non-branch previous ref
+ fi
+ echo ${ref#refs/heads/}
+}
# Gets the number of commits ahead from remote
function git_commits_ahead() {
@@ -161,105 +345,6 @@ function git_prompt_long_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() {
diff --git a/lib/grep.zsh b/lib/grep.zsh
index 54e0f694e..1a70de7e5 100644
--- a/lib/grep.zsh
+++ b/lib/grep.zsh
@@ -10,7 +10,7 @@ else
}
# Ignore these folders (if the necessary grep flags are available)
- EXC_FOLDERS="{.bzr,CVS,.git,.hg,.svn,.idea,.tox}"
+ EXC_FOLDERS="{.bzr,CVS,.git,.hg,.svn,.idea,.tox,.venv,venv}"
# Check for --exclude-dir, otherwise check for --exclude. If --exclude
# isn't available, --color won't be either (they were released at the same
@@ -24,8 +24,8 @@ else
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"
+ alias egrep="grep -E"
+ alias fgrep="grep -F"
# write to cache file if cache directory is writable
if [[ -w "$ZSH_CACHE_DIR" ]]; then
diff --git a/lib/history.zsh b/lib/history.zsh
index 794076904..781a0e9de 100644
--- a/lib/history.zsh
+++ b/lib/history.zsh
@@ -1,19 +1,27 @@
## History wrapper
function omz_history {
- local clear list
- zparseopts -E c=clear l=list
+ # parse arguments and remove from $@
+ local clear list stamp REPLY
+ zparseopts -E -D c=clear l=list f=stamp E=stamp i=stamp t:=stamp
if [[ -n "$clear" ]]; then
# if -c provided, clobber the history file
- echo -n >| "$HISTFILE"
+
+ # confirm action before deleting history
+ print -nu2 "This action will irreversibly delete your command history. Are you sure? [y/N] "
+ builtin read -E
+ [[ "$REPLY" = [yY] ]] || return 0
+
+ print -nu2 >| "$HISTFILE"
fc -p "$HISTFILE"
- echo >&2 History file deleted.
- elif [[ -n "$list" ]]; then
- # if -l provided, run as if calling `fc' directly
- builtin fc "$@"
+
+ print -u2 History file deleted.
+ elif [[ $# -eq 0 ]]; then
+ # if no arguments provided, show full history starting from 1
+ builtin fc "${stamp[@]}" -l 1
else
- # unless a number is provided, show all history events (starting from 1)
- [[ ${@[-1]-} = *[0-9]* ]] && builtin fc -l "$@" || builtin fc -l "$@" 1
+ # otherwise, run `fc -l` with a custom format
+ builtin fc "${stamp[@]}" -l "$@"
fi
}
diff --git a/lib/key-bindings.zsh b/lib/key-bindings.zsh
index aaa73046e..0d2cecb6a 100644
--- a/lib/key-bindings.zsh
+++ b/lib/key-bindings.zsh
@@ -32,19 +32,26 @@ if [[ -n "${terminfo[knp]}" ]]; then
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
+autoload -U up-line-or-beginning-search
+zle -N up-line-or-beginning-search
+bindkey -M emacs "^[[A" up-line-or-beginning-search
+bindkey -M viins "^[[A" up-line-or-beginning-search
+bindkey -M vicmd "^[[A" up-line-or-beginning-search
+if [[ -n "${terminfo[kcuu1]}" ]]; then
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
+autoload -U down-line-or-beginning-search
+zle -N down-line-or-beginning-search
+bindkey -M emacs "^[[B" down-line-or-beginning-search
+bindkey -M viins "^[[B" down-line-or-beginning-search
+bindkey -M vicmd "^[[B" down-line-or-beginning-search
+if [[ -n "${terminfo[kcud1]}" ]]; then
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
@@ -105,12 +112,12 @@ 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 -s '\el' '^q 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
+# Edit the current command line in $VISUAL (or $EDITOR / `vi` if not set)
autoload -U edit-command-line
zle -N edit-command-line
bindkey '\C-x\C-e' edit-command-line
diff --git a/lib/misc.zsh b/lib/misc.zsh
index ff2017713..054485f5a 100644
--- a/lib/misc.zsh
+++ b/lib/misc.zsh
@@ -19,7 +19,7 @@ setopt multios # enable redirect to multiple streams: echo >file1 >
setopt long_list_jobs # show long list format job notifications
setopt interactivecomments # recognize comments
-# define pager dependant on what is available (less or more)
+# define pager depending on what is available (less or more)
if (( ${+commands[less]} )); then
env_default 'PAGER' 'less'
env_default 'LESS' '-R'
diff --git a/lib/prompt_info_functions.zsh b/lib/prompt_info_functions.zsh
index 3dc9b6d10..722ae58c0 100644
--- a/lib/prompt_info_functions.zsh
+++ b/lib/prompt_info_functions.zsh
@@ -20,6 +20,7 @@ function chruby_prompt_info \
jenv_prompt_info \
azure_prompt_info \
tf_prompt_info \
+ conda_prompt_info \
{
return 1
}
@@ -40,5 +41,5 @@ 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)
+ echo "$(rvm_prompt_info || rbenv_prompt_info || chruby_prompt_info)"
}
diff --git a/lib/spectrum.zsh b/lib/spectrum.zsh
index 97f5c360a..31e37792c 100644
--- a/lib/spectrum.zsh
+++ b/lib/spectrum.zsh
@@ -7,6 +7,7 @@ typeset -AHg FX FG BG
FX=(
reset "%{%}"
bold "%{%}" no-bold "%{%}"
+ dim "%{%}" no-dim "%{%}"
italic "%{%}" no-italic "%{%}"
underline "%{%}" no-underline "%{%}"
blink "%{%}" no-blink "%{%}"
diff --git a/lib/termsupport.zsh b/lib/termsupport.zsh
index d170ffcbf..852a543c5 100644
--- a/lib/termsupport.zsh
+++ b/lib/termsupport.zsh
@@ -17,7 +17,7 @@ function title {
: ${2=$1}
case "$TERM" in
- cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty|st*|foot*|contour*)
+ cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty*|st*|foot*|contour*|wezterm*)
print -Pn "\e]2;${2:q}\a" # set window name
print -Pn "\e]1;${1:q}\a" # set tab name
;;
@@ -47,13 +47,13 @@ fi
# Runs before showing the prompt
function omz_termsupport_precmd {
- [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return
+ [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return 0
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 0
emulate -L zsh
setopt extended_glob
@@ -129,7 +129,7 @@ fi
# Don't define the function if we're in an unsupported terminal
case "$TERM" in
# all of these either process OSC 7 correctly or ignore entirely
- xterm*|putty*|rxvt*|konsole*|mlterm*|alacritty|screen*|tmux*) ;;
+ xterm*|putty*|rxvt*|konsole*|mlterm*|alacritty*|screen*|tmux*) ;;
contour*|foot*) ;;
*)
# Terminal.app and iTerm2 process OSC 7 correctly
@@ -145,6 +145,7 @@ esac
# Identifies the directory using a file: URI scheme, including
# the host name to disambiguate local vs. remote paths.
function omz_termsupport_cwd {
+ setopt localoptions unset
# Percent-encode the host and path names.
local URL_HOST URL_PATH
URL_HOST="$(omz_urlencode -P $HOST)" || return 1
diff --git a/lib/tests/cli.test.zsh b/lib/tests/cli.test.zsh
new file mode 100644
index 000000000..9ee5cd219
--- /dev/null
+++ b/lib/tests/cli.test.zsh
@@ -0,0 +1,169 @@
+#!/usr/bin/zsh -df
+
+run_awk() {
+ local -a dis_plugins=(${=1})
+ local input_text="$2"
+
+ (( ! DEBUG )) || set -xv
+
+ local awk_subst_plugins="\
+ gsub(/[ \t]+(${(j:|:)dis_plugins})[ \t]+/, \" \") # with spaces before or after
+ gsub(/[ \t]+(${(j:|:)dis_plugins})$/, \"\") # with spaces before and EOL
+ gsub(/^(${(j:|:)dis_plugins})[ \t]+/, \"\") # with BOL and spaces after
+
+ gsub(/\((${(j:|:)dis_plugins})[ \t]+/, \"(\") # with parenthesis before and spaces after
+ gsub(/[ \t]+(${(j:|:)dis_plugins})\)/, \")\") # with spaces before or parenthesis after
+ gsub(/\((${(j:|:)dis_plugins})\)/, \"()\") # with only parentheses
+
+ gsub(/^(${(j:|:)dis_plugins})\)/, \")\") # with BOL and closing parenthesis
+ gsub(/\((${(j:|:)dis_plugins})$/, \"(\") # with opening parenthesis and EOL
+ "
+ # 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 }
+ "
+
+ command awk "$awk_script" <<< "$input_text"
+
+ (( ! DEBUG )) || set +xv
+}
+
+# runs awk against stdin, checks if the resulting file is not empty and then checks if the file has valid zsh syntax
+run_awk_and_test() {
+ local description="$1"
+ local plugins_to_disable="$2"
+ local input_text="$3"
+ local expected_output="$4"
+
+ local tmpfile==(:)
+
+ {
+ print -u2 "Test: $description"
+ DEBUG=0 run_awk "$plugins_to_disable" "$input_text" >| $tmpfile
+
+ if [[ ! -s "$tmpfile" ]]; then
+ print -u2 "\e[31mError\e[0m: output file empty"
+ return 1
+ fi
+
+ if ! zsh -n $tmpfile; then
+ print -u2 "\e[31mError\e[0m: zsh syntax error"
+ diff -u $tmpfile <(echo "$expected_output")
+ return 1
+ fi
+
+ if ! diff -u --color=always $tmpfile <(echo "$expected_output"); then
+ if (( DEBUG )); then
+ print -u2 ""
+ DEBUG=1 run_awk "$plugins_to_disable" "$input_text"
+ print -u2 ""
+ fi
+ print -u2 "\e[31mError\e[0m: output file does not match expected output"
+ return 1
+ fi
+
+ print -u2 "\e[32mSuccess\e[0m"
+ } always {
+ print -u2 ""
+ command rm -f "$tmpfile"
+ }
+}
+
+# These tests are for the `omz plugin disable` command
+run_awk_and_test \
+ "it should delete a single plugin in oneline format" \
+ "git" \
+ "plugins=(git)" \
+ "plugins=()"
+
+run_awk_and_test \
+ "it should delete a single plugin in multiline format" \
+ "github" \
+"plugins=(
+ github
+)" \
+"plugins=(
+)"
+
+run_awk_and_test \
+ "it should delete multiple plugins in oneline format" \
+ "github git z" \
+ "plugins=(github git z)" \
+ "plugins=()"
+
+run_awk_and_test \
+ "it should delete multiple plugins in multiline format" \
+ "github git z" \
+"plugins=(
+ github
+ git
+ z
+)" \
+"plugins=(
+)"
+
+run_awk_and_test \
+ "it should delete a single plugin among multiple in oneline format" \
+ "git" \
+ "plugins=(github git z)" \
+ "plugins=(github z)"
+
+run_awk_and_test \
+ "it should delete a single plugin among multiple in multiline format" \
+ "git" \
+"plugins=(
+ github
+ git
+ z
+)" \
+"plugins=(
+ github
+ z
+)"
+
+run_awk_and_test \
+ "it should delete multiple plugins in mixed format" \
+ "git z" \
+"plugins=(github
+git z)" \
+"plugins=(github
+)"
+
+run_awk_and_test \
+ "it should delete multiple plugins in mixed format 2" \
+ "github z" \
+"plugins=(github
+ git
+z)" \
+"plugins=(
+ git
+)"