Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autoload and emulate zsh #758

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions _zsh_highlight_internal
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Update ZLE buffer syntax highlighting.
#
# Invokes each highlighter that needs updating.
# This function is supposed to be called whenever the ZLE state changes.
_zsh_highlight_internal()
{
emulate -L zsh
setopt localoptions warncreateglobal nobashrematch
local REPLY # don't leak $REPLY into global scope

# Do not highlight if there are more than 300 chars in the buffer. It's most
# likely a pasted command or a huge list of files in that case..
[[ -n ${ZSH_HIGHLIGHT_MAXLENGTH:-} ]] && [[ $#BUFFER -gt $ZSH_HIGHLIGHT_MAXLENGTH ]] && return

# Do not highlight if there are pending inputs (copy/paste).
[[ $PENDING -gt 0 ]] && return

{
local cache_place
local -a region_highlight_copy

# Select which highlighters in ZSH_HIGHLIGHT_HIGHLIGHTERS need to be invoked.
local highlighter; for highlighter in $ZSH_HIGHLIGHT_HIGHLIGHTERS; do

# eval cache place for current highlighter and prepare it
cache_place="_zsh_highlight__highlighter_${highlighter}_cache"
typeset -ga ${cache_place}

# If highlighter needs to be invoked
if ! type "_zsh_highlight_highlighter_${highlighter}_predicate" >&/dev/null; then
echo "zsh-syntax-highlighting: warning: disabling the ${(qq)highlighter} highlighter as it has not been loaded" >&2
# TODO: use ${(b)} rather than ${(q)} if supported
ZSH_HIGHLIGHT_HIGHLIGHTERS=( ${ZSH_HIGHLIGHT_HIGHLIGHTERS:#${highlighter}} )
elif "_zsh_highlight_highlighter_${highlighter}_predicate"; then

# save a copy, and cleanup region_highlight
region_highlight_copy=("${region_highlight[@]}")
region_highlight=()

# Execute highlighter and save result
{
"_zsh_highlight_highlighter_${highlighter}_paint"
} always {
: ${(AP)cache_place::="${region_highlight[@]}"}
}

# Restore saved region_highlight
region_highlight=("${region_highlight_copy[@]}")

fi

# Use value form cache if any cached
region_highlight+=("${(@P)cache_place}")

done

# Re-apply zle_highlight settings

# region
() {
(( REGION_ACTIVE )) || return
integer min max
if (( MARK > CURSOR )) ; then
min=$CURSOR max=$MARK
else
min=$MARK max=$CURSOR
fi
if (( REGION_ACTIVE == 1 )); then
[[ $KEYMAP = vicmd ]] && (( max++ ))
elif (( REGION_ACTIVE == 2 )); then
local needle=$'\n'
# CURSOR and MARK are 0 indexed between letters like region_highlight
# Do not include the newline in the highlight
(( min = ${BUFFER[(Ib:min:)$needle]} ))
(( max = ${BUFFER[(ib:max:)$needle]} - 1 ))
fi
_zsh_highlight_apply_zle_highlight region standout "$min" "$max"
}

# yank / paste (zsh-5.1.1 and newer)
(( $+YANK_ACTIVE )) && (( YANK_ACTIVE )) && _zsh_highlight_apply_zle_highlight paste standout "$YANK_START" "$YANK_END"

# isearch
(( $+ISEARCHMATCH_ACTIVE )) && (( ISEARCHMATCH_ACTIVE )) && _zsh_highlight_apply_zle_highlight isearch underline "$ISEARCHMATCH_START" "$ISEARCHMATCH_END"

# suffix
(( $+SUFFIX_ACTIVE )) && (( SUFFIX_ACTIVE )) && _zsh_highlight_apply_zle_highlight suffix bold "$SUFFIX_START" "$SUFFIX_END"

} always {
typeset -g _ZSH_HIGHLIGHT_PRIOR_BUFFER="$BUFFER"
typeset -gi _ZSH_HIGHLIGHT_PRIOR_CURSOR=$CURSOR
}
}

# Apply highlighting based on entries in the zle_highlight array.
# This function takes four arguments:
# 1. The exact entry (no patterns) in the zle_highlight array:
# region, paste, isearch, or suffix
# 2. The default highlighting that should be applied if the entry is unset
# 3. and 4. Two integer values describing the beginning and end of the
# range. The order does not matter.
_zsh_highlight_apply_zle_highlight() {
local entry="$1" default="$2"
integer first="$3" second="$4"

# read the relevant entry from zle_highlight
#
# ### In zsh≥5.0.8 we'd use ${(b)entry}, but we support older zsh's, so we don't
# ### add (b). The only effect is on the failure mode for callers that violate
# ### the precondition.
local region="${zle_highlight[(r)${entry}:*]-}"

if [[ -z "$region" ]]; then
# entry not specified at all, use default value
region=$default
else
# strip prefix
region="${region#${entry}:}"

# no highlighting when set to the empty string or to 'none'
if [[ -z "$region" ]] || [[ "$region" == none ]]; then
return
fi
fi

integer start end
if (( first < second )); then
start=$first end=$second
else
start=$second end=$first
fi
region_highlight+=("$start $end $region, memo=zsh-syntax-highlighting")
}

_zsh_highlight_internal "$@"
Loading