diff --git a/.github/dependencies.yml b/.github/dependencies.yml index 12beaecbb..d60ab2c92 100644 --- a/.github/dependencies.yml +++ b/.github/dependencies.yml @@ -2,7 +2,7 @@ dependencies: plugins/gitfast: repo: felipec/git-completion branch: master - version: tag:v2.0 + version: tag:v2.1 postcopy: | set -e rm -rf git-completion.plugin.zsh Makefile README.adoc t tools diff --git a/README.md b/README.md index 98743432d..b3561a833 100644 --- a/README.md +++ b/README.md @@ -449,6 +449,10 @@ Oh My Zsh has a vibrant community of happy users and delightful contributors. Wi Thank you so much! + + + + ## Follow Us We're on social media: diff --git a/lib/async_prompt.zsh b/lib/async_prompt.zsh new file mode 100644 index 000000000..384e49d33 --- /dev/null +++ b/lib/async_prompt.zsh @@ -0,0 +1,146 @@ +# 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 + +# 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 + 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 { + 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]} + # Store handler name for callback + builtin echo $handler + # Set exit code for the handler if used + (exit $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 + command true + + # Save the PID from the handler child process + read pid <&$fd + _OMZ_ASYNC_PIDS[$handler]=$pid + + # 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 first line + local handler + read handler <&$fd + + # Store old output which is supposed to be already printed + local old_output="${_OMZ_ASYNC_OUTPUT[$handler]}" + + # Read output from fd + _OMZ_ASYNC_OUTPUT[$handler]="$(cat <&$fd)" + + # 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/git.zsh b/lib/git.zsh index f049f73c2..96df5589d 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -9,14 +9,18 @@ function __git_prompt_git() { GIT_OPTIONAL_LOCKS=0 command git "$@" } -function git_prompt_info() { +function _omz_git_prompt_status() { # 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 +37,38 @@ function git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } +# Enable async prompt by default unless the setting is at false / no +if zstyle -t ':omz:alpha:lib:git' async-prompt; then + function git_prompt_info() { + 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}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + *(\$\(git_prompt_info\)|\`git_prompt_info\`)*) + _omz_register_handler _omz_git_prompt_status + return + ;; + 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) +else + function git_prompt_info() { + _omz_git_prompt_status + } +fi + # Checks if working tree is dirty function parse_git_dirty() { local STATUS diff --git a/plugins/extract/extract.plugin.zsh b/plugins/extract/extract.plugin.zsh index 88d8b0740..80ca50c50 100644 --- a/plugins/extract/extract.plugin.zsh +++ b/plugins/extract/extract.plugin.zsh @@ -70,7 +70,7 @@ EOF (*.tar.lz4) lz4 -c -d "$full_path" | tar xvf - ;; (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$full_path" ;; (*.gz) (( $+commands[pigz] )) && pigz -cdk "$full_path" > "${file:t:r}" || gunzip -ck "$full_path" > "${file:t:r}" ;; - (*.bz2) bunzip2 "$full_path" ;; + (*.bz2) (( $+commands[pbzip2] )) && pbzip2 -d "$full_path" || bunzip2 "$full_path" ;; (*.xz) unxz "$full_path" ;; (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$full_path" ;; (*.lz4) lz4 -d "$full_path" ;; diff --git a/plugins/fzf/fzf.plugin.zsh b/plugins/fzf/fzf.plugin.zsh index b253a23d2..7312e3d26 100644 --- a/plugins/fzf/fzf.plugin.zsh +++ b/plugins/fzf/fzf.plugin.zsh @@ -8,6 +8,7 @@ function fzf_setup_using_base_dir() { "${HOME}/.fzf" "${HOME}/.nix-profile/share/fzf" "${XDG_DATA_HOME:-$HOME/.local/share}/fzf" + "${MSYSTEM_PREFIX}/share/fzf" "/usr/local/opt/fzf" "/opt/homebrew/opt/fzf" "/usr/share/fzf" diff --git a/plugins/gitfast/README.md b/plugins/gitfast/README.md index fed4b120a..60b84a23c 100644 --- a/plugins/gitfast/README.md +++ b/plugins/gitfast/README.md @@ -7,9 +7,3 @@ To use it, add `gitfast` to the plugins array in your zshrc file: ```zsh plugins=(... gitfast) ``` - -## Aliases - -An earlier version of the plugin also loaded the git plugin. If you want to keep those -aliases enable the [git plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git) -as well. diff --git a/plugins/gitfast/gitfast.plugin.zsh b/plugins/gitfast/gitfast.plugin.zsh index a6db0c6bd..c456eff7f 100644 --- a/plugins/gitfast/gitfast.plugin.zsh +++ b/plugins/gitfast/gitfast.plugin.zsh @@ -1,6 +1,6 @@ # Handle $0 according to the standard: # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html -0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" +0="${ZERO:-${${0:#$ZSH_ARGZERO}:-${(%):-%N}}}" 0="${${(M)0:#/*}:-$PWD/$0}" source "${0:A:h}/git-prompt.sh" diff --git a/plugins/gitfast/update b/plugins/gitfast/update deleted file mode 100755 index feb13ff7e..000000000 --- a/plugins/gitfast/update +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -url="https://raw.githubusercontent.com/felipec/git-completion" -version="1.3.7" - -curl -s -o _git "${url}/v${version}/git-completion.zsh" && -curl -s -o git-completion.bash "${url}/v${version}/git-completion.bash" && -curl -s -o git-prompt.sh "${url}/v${version}/git-prompt.sh" diff --git a/tools/changelog.sh b/tools/changelog.sh index 3ad8fe786..c4b26079e 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -221,11 +221,16 @@ supports_hyperlinks() { # If $TERM_PROGRAM is set, these terminals support hyperlinks case "$TERM_PROGRAM" in - Hyper|iTerm.app|terminology|WezTerm) return 0 ;; + Hyper|iTerm.app|terminology|WezTerm|vscode) return 0 ;; esac - # kitty supports hyperlinks - if [ "$TERM" = xterm-kitty ]; then + # These termcap entries support hyperlinks + case "$TERM" in + xterm-kitty|alacritty|alacritty-direct) return 0 ;; + esac + + # xfce4-terminal supports hyperlinks + if [ "$COLORTERM" = "xfce4-terminal" ]; then return 0 fi diff --git a/tools/install.sh b/tools/install.sh index 508fc2f77..e3613a28b 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -166,11 +166,16 @@ supports_hyperlinks() { # If $TERM_PROGRAM is set, these terminals support hyperlinks case "$TERM_PROGRAM" in - Hyper|iTerm.app|terminology|WezTerm) return 0 ;; + Hyper|iTerm.app|terminology|WezTerm|vscode) return 0 ;; esac - # kitty supports hyperlinks - if [ "$TERM" = xterm-kitty ]; then + # These termcap entries support hyperlinks + case "$TERM" in + xterm-kitty|alacritty|alacritty-direct) return 0 ;; + esac + + # xfce4-terminal supports hyperlinks + if [ "$COLORTERM" = "xfce4-terminal" ]; then return 0 fi diff --git a/tools/upgrade.sh b/tools/upgrade.sh index f7a263d66..d7016aa44 100755 --- a/tools/upgrade.sh +++ b/tools/upgrade.sh @@ -90,11 +90,16 @@ supports_hyperlinks() { # If $TERM_PROGRAM is set, these terminals support hyperlinks case "$TERM_PROGRAM" in - Hyper|iTerm.app|terminology|WezTerm) return 0 ;; + Hyper|iTerm.app|terminology|WezTerm|vscode) return 0 ;; esac - # kitty supports hyperlinks - if [ "$TERM" = xterm-kitty ]; then + # These termcap entries support hyperlinks + case "$TERM" in + xterm-kitty|alacritty|alacritty-direct) return 0 ;; + esac + + # xfce4-terminal supports hyperlinks + if [ "$COLORTERM" = "xfce4-terminal" ]; then return 0 fi