# 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 "$@"