Perf: speed up _zsh_highlight_highlighter_main_paint

This commit is contained in:
Roman Perepelitsa 2020-08-16 15:01:07 +02:00
parent 5ac6f101fd
commit 818e2f2290
2 changed files with 246 additions and 203 deletions

View File

@ -73,29 +73,20 @@ _zsh_highlight_highlighter_main_predicate()
# Helper to deal with tokens crossing line boundaries.
_zsh_highlight_main_add_region_highlight() {
integer start=$1 end=$2
shift 2
if (( in_alias )); then
[[ $1 == unknown-token ]] && alias_style=unknown-token
[[ $3 == unknown-token ]] && alias_style=unknown-token
return
fi
if (( in_param )); then
if [[ $1 == unknown-token ]]; then
param_style=unknown-token
if [[ -z $param_style || $3 == unknown-token ]]; then
param_style=$3
fi
if [[ -n $param_style ]]; then
return
fi
param_style=$1
return
fi
# The calculation was relative to $buf but region_highlight is relative to $BUFFER.
(( start += buf_offset ))
(( end += buf_offset ))
list_highlights+=($start $end $1)
list_highlights+=($(( $1 + buf_offset )) $(( $2 + buf_offset )) $3)
}
_zsh_highlight_main_add_many_region_highlights() {
@ -104,45 +95,30 @@ _zsh_highlight_main_add_many_region_highlights() {
done
}
_zsh_highlight_main_calculate_styles() {
local config="${(pj:\0:)${(@kv)ZSH_HIGHLIGHT_STYLES}}".
[[ $config == $_zsh_highlight_main__config ]] && return
_zsh_highlight_main__config=$config
typeset -gA _zsh_highlight_main__styles=("${(@kv)ZSH_HIGHLIGHT_STYLES}")
integer finished
local key val
while (( !finished )); do
finished=1
for key val in ${(@kv)_zsh_highlight_main__fallback_of}; do
[[ -n $_zsh_highlight_main__styles[$key] ]] && continue
if [[ -z $_zsh_highlight_main__styles[$key] &&
-n ${_zsh_highlight_main__styles[$key]::=${_zsh_highlight_main__styles[$val]}} ]]; then
finished=0
fi
done
done
}
_zsh_highlight_main_calculate_fallback() {
local -A fallback_of; fallback_of=(
alias arg0
suffix-alias arg0
global-alias dollar-double-quoted-argument
builtin arg0
function arg0
command arg0
precommand arg0
hashed-command arg0
autodirectory arg0
arg0_\* arg0
# TODO: Maybe these? —
# named-fd file-descriptor
# numeric-fd file-descriptor
path_prefix path
# The path separator fallback won't ever be used, due to the optimisation
# in _zsh_highlight_main_highlighter_highlight_path_separators().
path_pathseparator path
path_prefix_pathseparator path_prefix
single-quoted-argument{-unclosed,}
double-quoted-argument{-unclosed,}
dollar-quoted-argument{-unclosed,}
back-quoted-argument{-unclosed,}
command-substitution{-quoted,,-unquoted,}
command-substitution-delimiter{-quoted,,-unquoted,}
command-substitution{-delimiter,}
process-substitution{-delimiter,}
back-quoted-argument{-delimiter,}
)
local needle=$1 value
reply=($1)
while [[ -n ${value::=$fallback_of[(k)$needle]} ]]; do
unset "fallback_of[$needle]" # paranoia against infinite loops
while [[ -n ${value::=$_zsh_highlight_main__fallback_of[(k)$needle]} ]]; do
reply+=($value)
needle=$value
done
@ -283,8 +259,8 @@ _zsh_highlight_main__resolve_alias() {
# Return true iff $1 is a global alias
_zsh_highlight_main__is_global_alias() {
if zmodload -e zsh/parameter; then
(( ${+galiases[$arg]} ))
elif [[ $arg == '='* ]]; then
(( ${+galiases[$1]} ))
elif [[ $1 == '='* ]]; then
# avoid running into «alias -L '=foo'» erroring out with 'bad assignment'
return 1
else
@ -325,8 +301,6 @@ _zsh_highlight_highlighter_main_paint()
return
fi
typeset -a ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR
typeset -a ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW
local -a options_to_set reply # used in callees
local REPLY
@ -338,90 +312,25 @@ _zsh_highlight_highlighter_main_paint()
local flags_sans_argument
# $flags_solo is a set of letters, corresponding to option letters that, if
# present, mean the precommand will not be acting as a precommand, i.e., will
# not be followed by a :start: word.
# not be followed by an 's' (start) word.
local flags_solo
# $precommand_options maps precommand name to values of $flags_with_argument,
# $flags_sans_argument, and flags_solo for that precommand, joined by a
# colon. (The value is NOT a getopt(3) spec, although it resembles one.)
# $_zsh_highlight_main__precommand_options maps precommand name to values of
# $flags_with_argument, $flags_sans_argument, and flags_solo for that precommand,
# joined by a colon. (The value is NOT a getopt(3) spec, although it resembles one.)
#
# Currently, setting $flags_sans_argument is only important for commands that
# have a non-empty $flags_with_argument; see test-data/precommand4.zsh.
local -A precommand_options
precommand_options=(
# Precommand modifiers as of zsh 5.6.2 cf. zshmisc(1).
'-' ''
'builtin' ''
'command' :pvV
'exec' a:cl
'noglob' ''
# 'time' and 'nocorrect' shouldn't be added here; they're reserved words, not precommands.
'doas' aCu:Lns # as of OpenBSD's doas(1) dated September 4, 2016
'nice' n: # as of current POSIX spec
'pkexec' '' # doesn't take short options; immune to #121 because it's usually not passed --option flags
# Not listed: -h, which has two different meanings.
'sudo' Cgprtu:AEHPSbilns:eKkVv # as of sudo 1.8.21p2
'stdbuf' ioe:
'eatmydata' ''
'catchsegv' ''
'nohup' ''
'setsid' :wc
'env' u:i
'ionice' cn:t:pPu # util-linux 2.33.1-0.1
'strace' IbeaosXPpEuOS:ACdfhikqrtTvVxyDc # strace 4.26-0.2
# As of OpenSSH 8.1p1
'ssh-agent' aEPt:csDd:k
# suckless-tools v44
# Argumentless flags that can't be followed by a command: -v
'tabbed' gnprtTuU:cdfhs
# moreutils 0.62-1
'chronic' :ev
'ifne' :n
)
# Commands that would need to skip one positional argument:
# flock
# ssh
if [[ $zsyh_user_options[ignorebraces] == on || ${zsyh_user_options[ignoreclosebraces]:-off} == on ]]; then
local right_brace_is_recognised_everywhere=false
if [[ $zsyh_user_options[ignorebraces] == on || $zsyh_user_options[ignoreclosebraces] == on ]]; then
local -i right_brace_is_recognised_everywhere=0
else
local right_brace_is_recognised_everywhere=true
local -i right_brace_is_recognised_everywhere=1
fi
if [[ $zsyh_user_options[pathdirs] == on ]]; then
options_to_set+=( PATH_DIRS )
fi
ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR=(
'|' '||' ';' '&' '&&'
$'\n' # ${(z)} returns ';' but we convert it to $'\n'
'|&'
'&!' '&|'
# ### 'case' syntax, but followed by a pattern, not by a command
# ';;' ';&' ';|'
)
# Tokens that, at (naively-determined) "command position", are followed by
# a de jure command position. All of these are reserved words.
ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW=(
$'\x7b' # block
$'\x28' # subshell
'()' # anonymous function
'while'
'until'
'if'
'then'
'elif'
'else'
'do'
'time'
'coproc'
'!' # reserved word; unrelated to $histchars[1]
)
if (( $+X_ZSH_HIGHLIGHT_DIRS_BLACKLIST )); then
print >&2 'zsh-syntax-highlighting: X_ZSH_HIGHLIGHT_DIRS_BLACKLIST is deprecated. Please use ZSH_HIGHLIGHT_DIRS_BLACKLIST.'
ZSH_HIGHLIGHT_DIRS_BLACKLIST=($X_ZSH_HIGHLIGHT_DIRS_BLACKLIST)
@ -431,13 +340,19 @@ _zsh_highlight_highlighter_main_paint()
_zsh_highlight_main_highlighter_highlight_list -$#PREBUFFER '' 1 "$PREBUFFER$BUFFER"
# end is a reserved word
local start end_ style
integer start end_
local style
for start end_ style in $reply; do
(( start >= end_ )) && { print -r -- >&2 "zsh-syntax-highlighting: BUG: _zsh_highlight_highlighter_main_paint: start($start) >= end($end_)"; return }
(( end_ <= 0 )) && continue
(( start < 0 )) && start=0 # having start<0 is normal with e.g. multiline strings
if (( $+_zsh_highlight_main__styles )); then
style=$_zsh_highlight_main__styles[$style]
[[ -n $style ]] && region_highlight+=("$start $end_ $style, memo=zsh-syntax-highlighting")
else
_zsh_highlight_main_calculate_fallback $style
_zsh_highlight_add_highlight $start $end_ $reply
fi
done
}
@ -536,25 +451,25 @@ _zsh_highlight_main_highlighter_highlight_list()
# State machine
#
# The states are:
# - :start: Command word
# - :start_of_pipeline: Start of a 'pipeline' as defined in zshmisc(1).
# Only valid when :start: is present
# - :sudo_opt: A leading-dash option to a precommand, whether it takes an
# - s Command word
# - p Start of a 'pipeline' as defined in zshmisc(1).
# Only valid when 's' is present
# - o A leading-dash option to a precommand, whether it takes an
# argument or not. (Example: sudo's "-u" or "-i".)
# - :sudo_arg: The argument to a precommand's leading-dash option,
# - a The argument to a precommand's leading-dash option,
# when given as a separate word; i.e., "foo" in "-u foo" (two
# words) but not in "-ufoo" (one word).
# Note: :sudo_opt: and :sudo_arg: are used for any precommand
# declared in ${precommand_options}, not just for sudo(8).
# The naming is historical.
# - :regular: "Not a command word", and command delimiters are permitted.
# Note: 'o' and 'a' are used for any precommand
# declared in ${_zsh_highlight_main__precommand_options}, not just
# for sudo(8). The naming is historical.
# - r "Not a command word", and command delimiters are permitted.
# Mainly used to detect premature termination of commands.
# - :always: The word 'always' in the «{ foo } always { bar }» syntax.
# - w The word 'always' in the «{ foo } always { bar }» syntax.
#
# When the kind of a word is not yet known, $this_word / $next_word may contain
# multiple states. For example, after "sudo -i", the next word may be either
# another --flag or a command name, hence the state would include both ':start:'
# and ':sudo_opt:'.
# another --flag or a command name, hence the state would include both 's'
# and 'o'.
#
# The tokens are always added with both leading and trailing colons to serve as
# word delimiters (an improvised array); [[ $x == *':foo:'* ]] and x=${x//:foo:/}
@ -582,7 +497,7 @@ _zsh_highlight_main_highlighter_highlight_list()
# - parameter elision in command position
# - 'repeat' loops
#
local this_word next_word=':start::start_of_pipeline:'
local this_word next_word='sp'
integer in_redirection
# Processing buffer
local proc_buf="$buf"
@ -623,7 +538,7 @@ _zsh_highlight_main_highlighter_highlight_list()
# Initialize this_word and next_word.
if (( in_redirection == 0 )); then
this_word=$next_word
next_word=':regular:'
next_word='r'
elif (( !in_param )); then
# Stall $next_word.
(( --in_redirection ))
@ -637,7 +552,7 @@ _zsh_highlight_main_highlighter_highlight_list()
# $saw_assignment boolean flag for "was preceded by an assignment"
#
style=unknown-token
if [[ $this_word == *':start:'* ]]; then
if [[ $this_word == *'s'* ]]; then
in_array_assignment=false
if [[ $arg == 'noglob' ]]; then
highlight_glob=false
@ -681,7 +596,7 @@ _zsh_highlight_main_highlighter_highlight_list()
#
# We use the (Z+c+) flag so the entire comment is presented as one token in $arg.
if [[ $zsyh_user_options[interactivecomments] == on && $arg[1] == $histchars[3] ]]; then
if [[ $this_word == *(':regular:'|':start:')* ]]; then
if [[ $this_word == *('r'|'s')* ]]; then
style=comment
else
style=unknown-token # prematurely terminated
@ -692,7 +607,7 @@ _zsh_highlight_main_highlighter_highlight_list()
continue
fi
if [[ $this_word == *':start:'* ]] && ! (( in_redirection )); then
if [[ $this_word == *'s'* ]] && ! (( in_redirection )); then
# Expand aliases.
# An alias is ineligible for expansion while it's being expanded (see #652/#653).
_zsh_highlight_main__type "$arg" "$(( ! ${+seen_alias[$arg]} ))"
@ -775,7 +690,7 @@ _zsh_highlight_main_highlighter_highlight_list()
# Parse the sudo command line
if (( ! in_redirection )); then
if [[ $this_word == *':sudo_opt:'* ]]; then
if [[ $this_word == *'o'* ]]; then
if [[ -n $flags_with_argument ]] &&
{
# Trenary
@ -785,8 +700,8 @@ _zsh_highlight_main_highlighter_highlight_list()
fi
} then
# Flag that requires an argument
this_word=${this_word//:start:/}
next_word=':sudo_arg:'
this_word=${this_word//s/}
next_word='a'
elif [[ -n $flags_with_argument ]] &&
{
# Trenary
@ -796,15 +711,15 @@ _zsh_highlight_main_highlighter_highlight_list()
fi
} then
# Argument attached in the same word
this_word=${this_word//:start:/}
next_word+=':start:'
next_word+=':sudo_opt:'
this_word=${this_word//s/}
next_word+='s'
next_word+='o'
elif [[ -n $flags_sans_argument ]] &&
[[ $arg == '-'[$flags_sans_argument]# ]]; then
# Flag that requires no argument
this_word=':sudo_opt:'
next_word+=':start:'
next_word+=':sudo_opt:'
this_word='o'
next_word+='s'
next_word+='o'
elif [[ -n $flags_solo ]] &&
{
# Trenary
@ -814,8 +729,8 @@ _zsh_highlight_main_highlighter_highlight_list()
fi
} then
# Solo flags
this_word=':sudo_opt:'
next_word=':regular:' # no :start:, nor :sudo_opt: since we don't know whether the solo flag takes an argument or not
this_word='o'
next_word='r' # no 's', nor 'o' since we don't know whether the solo flag takes an argument or not
elif [[ $arg == '-'* ]]; then
# Unknown flag. We don't know whether it takes an argument or not,
# so modify $next_word as we do for flags that require no argument.
@ -824,23 +739,23 @@ _zsh_highlight_main_highlighter_highlight_list()
# argument we'll highlight the command word correctly if the argument
# was given in the same shell word as the flag (as in '-uphy1729' or
# '--user=phy1729' without spaces).
this_word=':sudo_opt:'
next_word+=':start:'
next_word+=':sudo_opt:'
this_word='o'
next_word+='s'
next_word+='o'
else
# Not an option flag; nothing to do. (If the command line is
# syntactically valid, ${this_word//:sudo_opt:/} should be
# syntactically valid, ${this_word//o/} should be
# non-empty now.)
this_word=${this_word//:sudo_opt:/}
this_word=${this_word//o/}
fi
elif [[ $this_word == *':sudo_arg:'* ]]; then
next_word+=':sudo_opt:'
next_word+=':start:'
elif [[ $this_word == *'a'* ]]; then
next_word+='o'
next_word+='s'
fi
fi
# The Great Fork: is this a command word? Is this a non-command word?
if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]] &&
if [[ -n ${(M)_zsh_highlight_main__tokens_commandseparator:#"$arg"} ]] &&
[[ $braces_stack != *T* || $arg != ('||'|'&&') ]]; then
# First, determine the style of the command separator itself.
@ -858,11 +773,11 @@ _zsh_highlight_main_highlighter_highlight_list()
# Other command separators aren't allowed.
(*) style=unknown-token;;
esac
elif [[ $this_word == *':regular:'* ]]; then
elif [[ $this_word == *'r'* ]]; then
style=commandseparator
elif [[ $this_word == *':start:'* ]] && [[ $arg == $'\n' ]]; then
elif [[ $this_word == *'s'* ]] && [[ $arg == $'\n' ]]; then
style=commandseparator
elif [[ $this_word == *':start:'* ]] && [[ $arg == ';' ]] && (( in_alias )); then
elif [[ $this_word == *'s'* ]] && [[ $arg == ';' ]] && (( in_alias )); then
style=commandseparator
else
# Empty commands (semicolon follows nothing) are valid syntax.
@ -879,40 +794,40 @@ _zsh_highlight_main_highlighter_highlight_list()
# Second, determine the style of next_word.
if [[ $arg == $'\n' ]] && $in_array_assignment; then
# literal newline inside an array assignment
next_word=':regular:'
next_word='r'
elif [[ $arg == ';' ]] && $in_array_assignment; then
# literal semicolon inside an array assignment
next_word=':regular:'
next_word='r'
else
next_word=':start:'
next_word='s'
highlight_glob=true
saw_assignment=false
if [[ $arg != '|' && $arg != '|&' ]]; then
next_word+=':start_of_pipeline:'
next_word+='p'
fi
fi
elif ! (( in_redirection)) && [[ $this_word == *':always:'* && $arg == 'always' ]]; then
elif ! (( in_redirection)) && [[ $this_word == *'w'* && $arg == 'always' ]]; then
# try-always construct
style=reserved-word # de facto a reserved word, although not de jure
highlight_glob=true
saw_assignment=false
next_word=':start::start_of_pipeline:' # only left brace is allowed, apparently
elif ! (( in_redirection)) && [[ $this_word == *':start:'* ]]; then # $arg is the command word
if (( ${+precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then
next_word='sp' # only left brace is allowed, apparently
elif ! (( in_redirection)) && [[ $this_word == *'s'* ]]; then # $arg is the command word
if (( ${+_zsh_highlight_main__precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then
style=precommand
() {
set -- "${(@s.:.)precommand_options[$arg]}"
set -- "${(@s.:.)_zsh_highlight_main__precommand_options[$arg]}"
flags_with_argument=$1
flags_sans_argument=$2
flags_solo=$3
}
next_word=${next_word//:regular:/}
next_word+=':sudo_opt:'
next_word+=':start:'
next_word=${next_word//r/}
next_word+='o'
next_word+='s'
if [[ $arg == 'exec' ]]; then
# To allow "exec 2>&1;" where there's no command word
next_word+=':regular:'
next_word+='r'
fi
else
case $res in
@ -921,17 +836,17 @@ _zsh_highlight_main_highlighter_highlight_list()
# Match braces and handle special cases.
case $arg in
(time|nocorrect)
next_word=${next_word//:regular:/}
next_word+=':start:'
next_word=${next_word//r/}
next_word+='s'
;;
($'\x7b')
braces_stack='Y'"$braces_stack"
;;
($'\x7d')
# We're at command word, so no need to check $right_brace_is_recognised_everywhere
# We're at command word, so no need to check right_brace_is_recognised_everywhere
_zsh_highlight_main__stack_pop 'Y' reserved-word
if [[ $style == reserved-word ]]; then
next_word+=':always:'
next_word+='w'
fi
;;
($'\x5b\x5b')
@ -982,10 +897,10 @@ _zsh_highlight_main_highlighter_highlight_list()
# or a command separator (`repeat 2; ls` or `repeat 2; do ls; done`).
#
# The repeat-count word will be handled like a redirection target.
this_word=':start::regular:'
this_word='sr'
;;
('!')
if [[ $this_word != *':start_of_pipeline:'* ]]; then
if [[ $this_word != *'p'* ]]; then
style=unknown-token
else
# '!' reserved word at start of pipeline; style already set above
@ -1020,9 +935,9 @@ _zsh_highlight_main_highlighter_highlight_list()
# assignment to a scalar parameter.
# (For array assignments, the command doesn't start until the ")" token.)
#
# Discard :start_of_pipeline:, if present, as '!' is not valid
# Discard 'p', if present, as '!' is not valid
# after assignments.
next_word+=':start:'
next_word+='s'
if (( i <= $#arg )); then
() {
local highlight_glob=false
@ -1087,8 +1002,8 @@ _zsh_highlight_main_highlighter_highlight_list()
;;
esac
fi
if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW:#"$arg"} ]]; then
next_word=':start::start_of_pipeline:'
if [[ -n ${(M)_zsh_highlight_main__tokens_control_flow:#"$arg"} ]]; then
next_word='sp'
fi
elif _zsh_highlight_main__is_global_alias "$arg"; then # $arg is a global alias that isn't in command position
style=global-alias
@ -1100,7 +1015,7 @@ _zsh_highlight_main_highlighter_highlight_list()
_zsh_highlight_main_add_region_highlight $start_pos $end_pos assign
_zsh_highlight_main_add_region_highlight $start_pos $end_pos reserved-word
in_array_assignment=false
next_word+=':start:'
next_word+='s'
continue
elif (( in_redirection )); then
style=unknown-token
@ -1120,13 +1035,13 @@ _zsh_highlight_main_highlighter_highlight_list()
else
if [[ $zsyh_user_options[multifuncdef] == on ]] || false # TODO: or if the previous word was a command word
then
next_word+=':start::start_of_pipeline:'
next_word+='sp'
fi
style=reserved-word
fi
;;
(*) if false; then
elif [[ $arg = $'\x7d' ]] && $right_brace_is_recognised_everywhere; then
elif [[ $arg = $'\x7d' ]] && (( right_brace_is_recognised_everywhere )); then
# Parsing rule: {
#
# Additionally, `tt(})' is recognized in any position if neither the
@ -1136,7 +1051,7 @@ _zsh_highlight_main_highlighter_highlight_list()
else
_zsh_highlight_main__stack_pop 'Y' reserved-word
if [[ $style == reserved-word ]]; then
next_word+=':always:'
next_word+='w'
fi
fi
elif [[ $arg[0,1] = $histchars[0,1] ]] && (( $#arg[0,2] == 2 )); then
@ -1310,10 +1225,23 @@ _zsh_highlight_main_highlighter_check_path()
# This function currently assumes it's never called for the command word.
_zsh_highlight_main_highlighter_highlight_argument()
{
if (( $+_zsh_highlight_main__arg_cache )); then
local cache_key=$1$'\0'$2$'\0'$arg$'\0'$last_arg$'\0'$has_end$'\0'$highlight_glob$'\0'$in_redirection$'\0'$zsyh_user_options[multios]
local -a cache_val=(${(@0)_zsh_highlight_main__arg_cache[$cache_key]})
if (( $#cache_val )); then
integer offset=$(( start_pos - $cache_val[-1] ))
local start end_ style
for start end_ style in $cache_val[1,-2]; do
_zsh_highlight_main_add_region_highlight $(( start + offset )) $(( end_ + offset )) $style
done
return
fi
fi
local base_style=default i=$1 option_eligible=${2:-1} path_eligible=1 ret start style
local -a highlights
local -a match mbegin mend
local -a match mbegin mend reply
local MATCH; integer MBEGIN MEND
case "$arg[i]" in
@ -1457,6 +1385,11 @@ _zsh_highlight_main_highlighter_highlight_argument()
highlights=($(( start_pos + $1 - 1 )) $end_pos $base_style $highlights)
_zsh_highlight_main_add_many_region_highlights $highlights
if (( $+_zsh_highlight_main__arg_cache )); then
highlights+=($start_pos)
_zsh_highlight_main__arg_cache[$cache_key]=${(pj:\0:)highlights}
fi
}
# Quote Helper Functions
@ -1837,15 +1770,120 @@ _zsh_highlight_main__precmd_hook() {
_zsh_highlight_main__command_type_cache=()
_zsh_highlight_main__path_cache=()
_zsh_highlight_main__arg_cache=()
if [[ $ZSH_VERSION != (5.<9->*|<6->.*) ]]; then
_zsh_highlight_main_calculate_styles
fi
}
autoload -Uz add-zsh-hook
if add-zsh-hook precmd _zsh_highlight_main__precmd_hook 2>/dev/null; then
# Initialize caches
typeset -gA _zsh_highlight_main__command_type_cache _zsh_highlight_main__path_cache
typeset -gA _zsh_highlight_main__command_type_cache _zsh_highlight_main__path_cache _zsh_highlight_main__arg_cache
else
print -r -- >&2 'zsh-syntax-highlighting: Failed to load add-zsh-hook. Some speed optimizations will not be used.'
# Make sure the caches are unset
unset _zsh_highlight_main__command_type_cache _zsh_highlight_main__path_cache
unset _zsh_highlight_main__command_type_cache _zsh_highlight_main__path_cache _zsh_highlight_main__arg_cache
fi
typeset -ga ZSH_HIGHLIGHT_DIRS_BLACKLIST
typeset -gA _zsh_highlight_main__precommand_options=(
# Precommand modifiers as of zsh 5.6.2 cf. zshmisc(1).
'-' ''
'builtin' ''
'command' :pvV
'exec' a:cl
'noglob' ''
# 'time' and 'nocorrect' shouldn't be added here; they're reserved words, not precommands.
'doas' aCu:Lns # as of OpenBSD's doas(1) dated September 4, 2016
'nice' n: # as of current POSIX spec
'pkexec' '' # doesn't take short options; immune to #121 because it's usually not passed --option flags
# Not listed: -h, which has two different meanings.
'sudo' Cgprtu:AEHPSbilns:eKkVv # as of sudo 1.8.21p2
'stdbuf' ioe:
'eatmydata' ''
'catchsegv' ''
'nohup' ''
'setsid' :wc
'env' u:i
'ionice' cn:t:pPu # util-linux 2.33.1-0.1
'strace' IbeaosXPpEuOS:ACdfhikqrtTvVxyDc # strace 4.26-0.2
# As of OpenSSH 8.1p1
'ssh-agent' aEPt:csDd:k
# suckless-tools v44
# Argumentless flags that can't be followed by a command: -v
'tabbed' gnprtTuU:cdfhs
# moreutils 0.62-1
'chronic' :ev
'ifne' :n
)
# Commands that would need to skip one positional argument:
# flock
# ssh
typeset -ga _zsh_highlight_main__tokens_commandseparator=(
'|' '||' ';' '&' '&&'
$'\n' # ${(z)} returns ';' but we convert it to $'\n'
'|&'
'&!' '&|'
# ### 'case' syntax, but followed by a pattern, not by a command
# ';;' ';&' ';|'
)
# Tokens that, at (naively-determined) "command position", are followed by
# a de jure command position. All of these are reserved words.
typeset -ga _zsh_highlight_main__tokens_control_flow=(
$'\x7b' # block
$'\x28' # subshell
'()' # anonymous function
'while'
'until'
'if'
'then'
'elif'
'else'
'do'
'time'
'coproc'
'!' # reserved word; unrelated to $histchars[1]
)
typeset -gA _zsh_highlight_main__fallback_of=(
alias arg0
suffix-alias arg0
global-alias dollar-double-quoted-argument
builtin arg0
function arg0
command arg0
precommand arg0
hashed-command arg0
autodirectory arg0
arg0_\* arg0
# TODO: Maybe these? —
# named-fd file-descriptor
# numeric-fd file-descriptor
path_prefix path
# The path separator fallback won't ever be used, due to the optimisation
# in _zsh_highlight_main_highlighter_highlight_path_separators().
path_pathseparator path
path_prefix_pathseparator path_prefix
single-quoted-argument{-unclosed,}
double-quoted-argument{-unclosed,}
dollar-quoted-argument{-unclosed,}
back-quoted-argument{-unclosed,}
command-substitution{-quoted,,-unquoted,}
command-substitution-delimiter{-quoted,,-unquoted,}
command-substitution{-delimiter,}
process-substitution{-delimiter,}
back-quoted-argument{-delimiter,}
)

View File

@ -91,6 +91,11 @@ _zsh_highlight_add_highlight()
region_highlight+=("$1 $2 $3")
}
_zsh_highlight_main_calculate_styles()
{
# Do nothing
}
# Activate the highlighter.
ZSH_HIGHLIGHT_HIGHLIGHTERS=($1)