You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1463 lines
70 KiB

# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
# -------------------------------------------------------------------------------------------------
# Copyright (c) 2010-2016 zsh-syntax-highlighting contributors
# Copyright (c) 2016-2019 Sebastian Gniazdowski (modifications)
# All rights reserved.
#
# The only licensing for this file follows.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted
# provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this list of conditions
# and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice, this list of
# conditions and the following disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
# may be used to endorse or promote products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# -------------------------------------------------------------------------------------------------
typeset -gA __fast_highlight_main__command_type_cache FAST_BLIST_PATTERNS
typeset -g FAST_WORK_DIR
: ${FAST_WORK_DIR:=$FAST_BASE_DIR}
FAST_WORK_DIR=${~FAST_WORK_DIR}
() {
emulate -L zsh -o extendedglob
local -A map
map=( "XDG:" "${XDG_CONFIG_HOME:-$HOME/.config}/fsh/"
"LOCAL:" "/usr/local/share/fsh/"
"HOME:" "$HOME/.fsh/"
"OPT:" "/opt/local/share/fsh/"
)
FAST_WORK_DIR=${${FAST_WORK_DIR/(#m)(#s)(XDG|LOCAL|HOME|OPT):(#c0,1)/${map[${MATCH%:}:]}}%/}
}
# Define default styles. You can set this after loading the plugin in
# Zshrc and use 256 colors via numbers, like: fg=150
typeset -gA FAST_HIGHLIGHT_STYLES
if [[ -e $FAST_WORK_DIR/current_theme.zsh ]]; then
source $FAST_WORK_DIR/current_theme.zsh
else
# built-in theme
zstyle :plugin:fast-syntax-highlighting theme default
: ${FAST_HIGHLIGHT_STYLES[default]:=none}
: ${FAST_HIGHLIGHT_STYLES[unknown-token]:=fg=red,bold}
: ${FAST_HIGHLIGHT_STYLES[reserved-word]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[subcommand]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[alias]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[suffix-alias]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[global-alias]:=bg=blue}
: ${FAST_HIGHLIGHT_STYLES[builtin]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[function]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[command]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[precommand]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[commandseparator]:=none}
: ${FAST_HIGHLIGHT_STYLES[hashed-command]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[path]:=fg=magenta}
: ${FAST_HIGHLIGHT_STYLES[path-to-dir]:=fg=magenta,underline}
: ${FAST_HIGHLIGHT_STYLES[path_pathseparator]:=}
: ${FAST_HIGHLIGHT_STYLES[globbing]:=fg=blue,bold}
: ${FAST_HIGHLIGHT_STYLES[globbing-ext]:=fg=13}
: ${FAST_HIGHLIGHT_STYLES[history-expansion]:=fg=blue,bold}
: ${FAST_HIGHLIGHT_STYLES[single-hyphen-option]:=fg=cyan}
: ${FAST_HIGHLIGHT_STYLES[double-hyphen-option]:=fg=cyan}
: ${FAST_HIGHLIGHT_STYLES[back-quoted-argument]:=none}
: ${FAST_HIGHLIGHT_STYLES[single-quoted-argument]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[double-quoted-argument]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[dollar-quoted-argument]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[back-or-dollar-double-quoted-argument]:=fg=cyan}
: ${FAST_HIGHLIGHT_STYLES[back-dollar-quoted-argument]:=fg=cyan}
: ${FAST_HIGHLIGHT_STYLES[assign]:=none}
: ${FAST_HIGHLIGHT_STYLES[redirection]:=none}
: ${FAST_HIGHLIGHT_STYLES[comment]:=fg=black,bold}
: ${FAST_HIGHLIGHT_STYLES[variable]:=fg=113}
: ${FAST_HIGHLIGHT_STYLES[mathvar]:=fg=blue,bold}
: ${FAST_HIGHLIGHT_STYLES[mathnum]:=fg=magenta}
: ${FAST_HIGHLIGHT_STYLES[matherr]:=fg=red}
: ${FAST_HIGHLIGHT_STYLES[assign-array-bracket]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[for-loop-variable]:=none}
: ${FAST_HIGHLIGHT_STYLES[for-loop-operator]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[for-loop-number]:=fg=magenta}
: ${FAST_HIGHLIGHT_STYLES[for-loop-separator]:=fg=yellow,bold}
: ${FAST_HIGHLIGHT_STYLES[here-string-tri]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[here-string-text]:=bg=18}
: ${FAST_HIGHLIGHT_STYLES[here-string-var]:=fg=cyan,bg=18}
: ${FAST_HIGHLIGHT_STYLES[case-input]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[case-parentheses]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[case-condition]:=bg=blue}
: ${FAST_HIGHLIGHT_STYLES[paired-bracket]:=bg=blue}
: ${FAST_HIGHLIGHT_STYLES[bracket-level-1]:=fg=green,bold}
: ${FAST_HIGHLIGHT_STYLES[bracket-level-2]:=fg=yellow,bold}
: ${FAST_HIGHLIGHT_STYLES[bracket-level-3]:=fg=cyan,bold}
: ${FAST_HIGHLIGHT_STYLES[single-sq-bracket]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[double-sq-bracket]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[double-paren]:=fg=yellow}
: ${FAST_HIGHLIGHT_STYLES[correct-subtle]:=fg=12}
: ${FAST_HIGHLIGHT_STYLES[incorrect-subtle]:=fg=red}
: ${FAST_HIGHLIGHT_STYLES[subtle-separator]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[subtle-bg]:=bg=18}
: ${FAST_HIGHLIGHT_STYLES[secondary]:=free}
fi
# This can overwrite some of *_STYLES fields
[[ -r $FAST_WORK_DIR/theme_overlay.zsh ]] && source $FAST_WORK_DIR/theme_overlay.zsh
typeset -gA __FAST_HIGHLIGHT_TOKEN_TYPES
__FAST_HIGHLIGHT_TOKEN_TYPES=(
# Precommand
'builtin' 1
'command' 1
'exec' 1
'nocorrect' 1
'noglob' 1
'pkexec' 1 # immune to #121 because it's usually not passed --option flags
# Control flow
# Tokens that, at (naively-determined) "command position", are followed by
# a de jure command position. All of these are reserved words.
$'\x7b' 2 # block '{'
$'\x28' 2 # subshell '('
'()' 2 # anonymous function
'while' 2
'until' 2
'if' 2
'then' 2
'elif' 2
'else' 2
'do' 2
'time' 2
'coproc' 2
'!' 2 # reserved word; unrelated to $histchars[1]
# Command separators
'|' 3
'||' 3
';' 3
'&' 3
'&&' 3
'|&' 3
'&!' 3
'&|' 3
# ### 'case' syntax, but followed by a pattern, not by a command
# ';;' ';&' ';|'
)
# A hash instead of multiple globals
typeset -gA FAST_HIGHLIGHT
# Brackets highlighter active by default
: ${FAST_HIGHLIGHT[use_brackets]:=1}
FAST_HIGHLIGHT+=(
chroma-fast-theme →chroma/-fast-theme.ch
chroma-alias →chroma/-alias.ch
chroma-autoload →chroma/-autoload.ch
chroma-autorandr →chroma/-autorandr.ch
chroma-docker →chroma/-docker.ch
chroma-example →chroma/-example.ch
chroma-ionice →chroma/-ionice.ch
chroma-make →chroma/-make.ch
chroma-nice →chroma/-nice.ch
chroma-nmcli →chroma/-nmcli.ch
chroma-node →chroma/-node.ch
chroma-perl →chroma/-perl.ch
chroma-printf →chroma/-printf.ch
chroma-ruby →chroma/-ruby.ch
chroma-scp →chroma/-scp.ch
chroma-ssh →chroma/-ssh.ch
chroma-git →chroma/main-chroma.ch%git
chroma-hub →chroma/-hub.ch
chroma-lab →chroma/-lab.ch
chroma-svn →chroma/-subversion.ch
chroma-svnadmin →chroma/-subversion.ch
chroma-svndumpfilter →chroma/-subversion.ch
chroma-egrep →chroma/-grep.ch
chroma-fgrep →chroma/-grep.ch
chroma-grep →chroma/-grep.ch
chroma-awk →chroma/-awk.ch
chroma-gawk →chroma/-awk.ch
chroma-mawk →chroma/-awk.ch
chroma-source →chroma/-source.ch
chroma-. →chroma/-source.ch
chroma-bash →chroma/-sh.ch
chroma-fish →chroma/-sh.ch
chroma-sh →chroma/-sh.ch
chroma-zsh →chroma/-sh.ch
chroma-whatis →chroma/-whatis.ch
chroma-man →chroma/-whatis.ch
chroma-- →chroma/-precommand.ch
chroma-xargs →chroma/-precommand.ch
chroma-nohup →chroma/-precommand.ch
chroma-strace →chroma/-precommand.ch
chroma-ltrace →chroma/-precommand.ch
chroma-hg →chroma/-subcommand.ch
chroma-cvs →chroma/-subcommand.ch
chroma-pip →chroma/-subcommand.ch
chroma-pip2 →chroma/-subcommand.ch
chroma-pip3 →chroma/-subcommand.ch
chroma-gem →chroma/-subcommand.ch
chroma-bundle →chroma/-subcommand.ch
chroma-yard →chroma/-subcommand.ch
chroma-cabal →chroma/-subcommand.ch
chroma-npm →chroma/-subcommand.ch
chroma-nvm →chroma/-subcommand.ch
chroma-yarn →chroma/-subcommand.ch
chroma-brew →chroma/-subcommand.ch
chroma-port →chroma/-subcommand.ch
chroma-yum →chroma/-subcommand.ch
chroma-dnf →chroma/-subcommand.ch
chroma-tmux →chroma/-subcommand.ch
chroma-pass →chroma/-subcommand.ch
chroma-aws →chroma/-subcommand.ch
chroma-apt →chroma/-subcommand.ch
chroma-apt-get →chroma/-subcommand.ch
chroma-apt-cache →chroma/-subcommand.ch
chroma-aptitude →chroma/-subcommand.ch
chroma-keyctl →chroma/-subcommand.ch
chroma-systemctl →chroma/-subcommand.ch
chroma-asciinema →chroma/-subcommand.ch
chroma-ipfs →chroma/-subcommand.ch
chroma-zinit →chroma/main-chroma.ch%zinit
chroma-aspell →chroma/-subcommand.ch
chroma-bspc →chroma/-subcommand.ch
chroma-cryptsetup →chroma/-subcommand.ch
chroma-diskutil →chroma/-subcommand.ch
chroma-exercism →chroma/-subcommand.ch
chroma-gulp →chroma/-subcommand.ch
chroma-i3-msg →chroma/-subcommand.ch
chroma-openssl →chroma/-subcommand.ch
chroma-solargraph →chroma/-subcommand.ch
chroma-subliminal →chroma/-subcommand.ch
chroma-svnadmin →chroma/-subcommand.ch
chroma-travis →chroma/-subcommand.ch
chroma-udisksctl →chroma/-subcommand.ch
chroma-xdotool →chroma/-subcommand.ch
chroma-zmanage →chroma/-subcommand.ch
chroma-zsystem →chroma/-subcommand.ch
chroma-zypper →chroma/-subcommand.ch
chroma-fpath+=\( →chroma/-fpath_peq.ch
chroma-fpath=\( →chroma/-fpath_peq.ch
chroma-FPATH+= →chroma/-fpath_peq.ch
chroma-FPATH= →chroma/-fpath_peq.ch
#chroma-which →chroma/-which.ch
#chroma-vim →chroma/-vim.ch
)
if [[ $OSTYPE == darwin* ]] {
noglob unset FAST_HIGHLIGHT[chroma-man] FAST_HIGHLIGHT[chroma-whatis]
}
# Assignments seen, to know if math parameter exists
typeset -gA FAST_ASSIGNS_SEEN
# Exposing tokens found on command position,
# for other scripts to process
typeset -ga ZLAST_COMMANDS
# Get the type of a command.
#
# Uses the zsh/parameter module if available to avoid forks, and a
# wrapper around 'type -w' as fallback.
#
# Takes a single argument.
#
# The result will be stored in REPLY.
-fast-highlight-main-type() {
REPLY=$__fast_highlight_main__command_type_cache[(e)$1]
[[ -z $REPLY ]] && {
if zmodload -e zsh/parameter; then
if (( $+aliases[(e)$1] )); then
REPLY=alias
elif (( ${+galiases[(e)$1]} )); then
REPLY="global alias"
elif (( $+functions[(e)$1] )); then
REPLY=function
elif (( $+builtins[(e)$1] )); then
REPLY=builtin
elif (( $+commands[(e)$1] )); then
REPLY=command
elif (( $+saliases[(e)${1##*.}] )); then
REPLY='suffix alias'
elif (( $reswords[(Ie)$1] )); then
REPLY=reserved
# zsh 5.2 and older have a bug whereby running 'type -w ./sudo' implicitly
# runs 'hash ./sudo=/usr/local/bin/./sudo' (assuming /usr/local/bin/sudo
# exists and is in $PATH). Avoid triggering the bug, at the expense of
# falling through to the $() below, incurring a fork. (Issue #354.)
#
# The second disjunct mimics the isrelative() C call from the zsh bug.
elif [[ $1 != */* || ${+ZSH_ARGZERO} = "1" ]] && ! builtin type -w -- $1 >/dev/null 2>&1; then
REPLY=none
fi
fi
[[ -z $REPLY ]] && REPLY="${$(LC_ALL=C builtin type -w -- $1 2>/dev/null)##*: }"
[[ $REPLY = "none" ]] && {
[[ -n ${FAST_BLIST_PATTERNS[(k)${${(M)1:#/*}:-$PWD/$1}]} ]] || {
[[ -d $1 ]] && REPLY="dirpath" || {
for cdpath_dir in $cdpath; do
[[ -d $cdpath_dir/$1 ]] && { REPLY="dirpath"; break; }
done
}
}
}
__fast_highlight_main__command_type_cache[(e)$1]=$REPLY
}
}
# Below are variables that must be defined in outer
# scope so that they are reachable in *-process()
-fast-highlight-fill-option-variables() {
if [[ -o ignore_braces ]] || eval '[[ -o ignore_close_braces ]] 2>/dev/null'; then
FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]=0
else
FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]=1
fi
if [[ -o path_dirs ]]; then
FAST_HIGHLIGHT[path_dirs_was_set]=1
else
FAST_HIGHLIGHT[path_dirs_was_set]=0
fi
if [[ -o multi_func_def ]]; then
FAST_HIGHLIGHT[multi_func_def]=1
else
FAST_HIGHLIGHT[multi_func_def]=0
fi
if [[ -o interactive_comments ]]; then
FAST_HIGHLIGHT[ointeractive_comments]=1
else
FAST_HIGHLIGHT[ointeractive_comments]=0
fi
}
# Main syntax highlighting function.
-fast-highlight-process()
{
emulate -L zsh
setopt extendedglob bareglobqual nonomatch typesetsilent
[[ $CONTEXT == "select" ]] && return 0
(( FAST_HIGHLIGHT[path_dirs_was_set] )) && setopt PATH_DIRS
(( FAST_HIGHLIGHT[ointeractive_comments] )) && local interactive_comments= # _set_ to empty
# Variable declarations and initializations
# in_array_assignment true between 'a=(' and the matching ')'
# braces_stack: "R" for round, "Q" for square, "Y" for curly
# _mybuf, cdpath_dir are used in sub-functions
local _start_pos=$3 _end_pos __start __end highlight_glob=1 __arg __style in_array_assignment=0 MATCH expanded_path braces_stack __buf=$1$2 _mybuf __workbuf cdpath_dir active_command alias_target _was_double_hyphen=0 __nul=$'\0' __tmp
# __arg_type can be 0, 1, 2 or 3, i.e. precommand, control flow, command separator
# __idx and _end_idx are used in sub-functions
# for this_word and next_word look below at commented integers and at state machine description
integer __arg_type=0 MBEGIN MEND in_redirection __len=${#__buf} __PBUFLEN=${#1} already_added offset __idx _end_idx this_word=1 next_word=0 __pos __asize __delimited=0 itmp iitmp
local -a match mbegin mend __inputs __list
# This comment explains the numbers:
# BIT_for - word after reserved-word-recognized `for'
# BIT_afpcmd - word after a precommand that can take options, like `command' and `exec'
# integer BIT_start=1 BIT_regular=2 BIT_sudo_opt=4 BIT_sudo_arg=8 BIT_always=16 BIT_for=32 BIT_afpcmd=64
# integer BIT_chroma=8192
integer BIT_case_preamble=512 BIT_case_item=1024 BIT_case_nempty_item=2048 BIT_case_code=4096
# Braces stack
# T - typeset, local, etc.
# State machine
#
# The states are:
# - :__start: Command word
# - :sudo_opt: A leading-dash option to sudo (such as "-u" or "-i")
# - :sudo_arg: The argument to a sudo leading-dash option that takes one,
# when given as a separate word; i.e., "foo" in "-u foo" (two
# words) but not in "-ufoo" (one word).
# - :regular: "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.
#
# 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:.
#
# 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:/}
# will DTRT regardless of how many elements or repetitions $x has..
#
# Handling of redirections: upon seeing a redirection token, we must stall
# the current state --- that is, the value of $this_word --- for two iterations
# (one for the redirection operator, one for the word following it representing
# the redirection target). Therefore, we set $in_redirection to 2 upon seeing a
# redirection operator, decrement it each iteration, and stall the current state
# when it is non-zero. Thus, upon reaching the next word (the one that follows
# the redirection operator and target), $this_word will still contain values
# appropriate for the word immediately following the word that preceded the
# redirection operator.
#
# The "the previous word was a redirection operator" state is not communicated
# to the next iteration via $next_word/$this_word as usual, but via
# $in_redirection. The value of $next_word from the iteration that processed
# the operator is discarded.
#
# Command exposure for other scripts
ZLAST_COMMANDS=()
# Restart observing of assigns
FAST_ASSIGNS_SEEN=()
# Restart function's gathering
FAST_HIGHLIGHT[chroma-autoload-elements]=""
# Restart FPATH elements gathering
FAST_HIGHLIGHT[chroma-fpath_peq-elements]=""
# Restart svn zinit's ICE gathering
FAST_HIGHLIGHT[chroma-zinit-ice-elements-svn]=0
FAST_HIGHLIGHT[chroma-zinit-ice-elements-id-as]=""
[[ -n $ZCALC_ACTIVE ]] && {
_start_pos=0; _end_pos=__len; __arg=$__buf
-fast-highlight-math-string
return 0
}
# Processing buffer
local proc_buf=$__buf needle
for __arg in ${interactive_comments-${(z)__buf}} \
${interactive_comments+${(zZ+c+)__buf}}; do
# Initialize $next_word to its default value?
(( in_redirection = in_redirection > 0 ? in_redirection - 1 : in_redirection ));
(( next_word = (in_redirection == 0) ? 2 : next_word )) # else Stall $next_word.
(( next_word = next_word | (this_word & (BIT_case_code|8192)) ))
# If we have a good delimiting construct just ending, and '{'
# occurs, then respect this and go for alternate syntax, i.e.
# treat '{' (\x7b) as if it's on command position
[[ $__arg = '{' && $__delimited = 2 ]] && { (( this_word = (this_word & ~2) | 1 )); __delimited=0; }
__asize=${#__arg}
# Reset state of working variables
already_added=0
__style=${FAST_THEME_NAME}unknown-token
(( this_word & 1 )) && { in_array_assignment=0; [[ $__arg == 'noglob' ]] && highlight_glob=0; }
# Compute the new $_start_pos and $_end_pos, skipping over whitespace in $__buf.
if [[ $__arg == ';' ]] ; then
braces_stack=${braces_stack#T}
__delimited=0
# Both ; and \n are rendered as a ";" (SEPER) by the ${(z)..} flag.
needle=$';\n'
[[ $proc_buf = (#b)[^$needle]#([$needle]##)* ]] && offset=${mbegin[1]}-1
(( _start_pos += offset ))
(( _end_pos = _start_pos + __asize ))
# Prepare next loop cycle
(( this_word & BIT_case_item )) || { (( in_array_assignment )) && (( this_word = 2 | (this_word & BIT_case_code) )) || { (( this_word = 1 | (this_word & BIT_case_code) )); highlight_glob=1; }; }
in_redirection=0
# Chance to highlight ';'
[[ ${proc_buf[offset+1]} != $'\n' ]] && {
[[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}commandseparator]} != "none" ]] && \
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}commandseparator]}")
}
proc_buf=${proc_buf[offset + __asize + 1,__len]}
_start_pos=$_end_pos
continue
else
offset=0
if [[ $proc_buf = (#b)(#s)(([[:space:]]|\\[[:space:]])##)* ]]; then
# The first, outer parenthesis
offset=${mend[1]}
fi
(( _start_pos += offset ))
(( _end_pos = _start_pos + __asize ))
# No-hit will result in value 0
__arg_type=${__FAST_HIGHLIGHT_TOKEN_TYPES[$__arg]}
fi
(( this_word & 1 )) && ZLAST_COMMANDS+=( $__arg );
proc_buf=${proc_buf[offset + __asize + 1,__len]}
# Handle the INTERACTIVE_COMMENTS option.
#
# We use the (Z+c+) flag so the entire comment is presented as one token in $__arg.
if [[ -n ${interactive_comments+'set'} && $__arg == ${histchars[3]}* ]]; then
if (( this_word & 3 )); then
__style=${FAST_THEME_NAME}comment
else
__style=${FAST_THEME_NAME}unknown-token # prematurely terminated
fi
# ADD
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
_start_pos=$_end_pos
continue
fi
# Redirection?
[[ $__arg == (<0-9>|)(\<|\>)* && $__arg != (\<|\>)$'\x28'* && $__arg != "<<<" ]] && \
in_redirection=2
# Special-case the first word after 'sudo'.
if (( ! in_redirection )); then
(( this_word & 4 )) && [[ $__arg != -* ]] && (( this_word = this_word ^ 4 ))
# Parse the sudo command line
if (( this_word & 4 )); then
case $__arg in
# Flag that requires an argument
'-'[Cgprtu])
(( this_word = this_word & ~1 ))
(( next_word = 8 | (this_word & BIT_case_code) ))
;;
# This prevents misbehavior with sudo -u -otherargument
'-'*)
(( this_word = this_word & ~1 ))
(( next_word = next_word | 1 | 4 ))
;;
esac
elif (( this_word & 8 )); then
(( next_word = next_word | 4 | 1 ))
elif (( this_word & 64 )); then
[[ $__arg = -[pvV-]## && $active_command = "command" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
[[ $__arg = -[cla-]## && $active_command = "exec" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
[[ $__arg = \{[a-zA-Z_][a-zA-Z0-9_]#\} && $active_command = "exec" ]] && {
# Highlight {descriptor} passed to exec
(( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}exec-descriptor]}")
already_added=1
}
fi
fi
(( this_word & 8192 )) && {
__list=( ${(z@)${aliases[$active_command]:-${active_command##*/}}##[[:space:]]#(command|builtin|exec|noglob|nocorrect|pkexec)[[:space:]]#} )
${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 0 "$__arg" $_start_pos $_end_pos 2>/dev/null && continue
}
(( this_word & 1 )) && {
# !in_redirection needed particularly for exec {A}>b {C}>d
(( !in_redirection )) && active_command=$__arg
_mybuf=${${aliases[$active_command]:-${active_command##*/}}##[[:space:]]#(command|builtin|exec|noglob|nocorrect|pkexec)[[:space:]]#}
[[ "$_mybuf" = (#b)(FPATH+(#c0,1)=)* ]] && _mybuf="${match[1]} ${(j: :)${(s,:,)${_mybuf#FPATH+(#c0,1)=}}}"
[[ -n ${FAST_HIGHLIGHT[chroma-${_mybuf%% *}]} ]] && {
__list=( ${(z@)_mybuf} )
if (( ${#__list} > 1 )) || [[ $active_command != $_mybuf ]]; then
__style=${FAST_THEME_NAME}alias
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 1 "${__list[1]}" "-100000" $_end_pos 2>/dev/null || \
(( this_word = next_word, next_word = 2 ))
for _mybuf in "${(@)__list[2,-1]}"; do
(( next_word = next_word | (this_word & (BIT_case_code|8192)) ))
${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 0 "$_mybuf" "-100000" $_end_pos 2>/dev/null || \
(( this_word = next_word, next_word = 2 ))
done
# This might have been done multiple times in chroma, but
# as _end_pos doesn't change, it can be done one more time
_start_pos=$_end_pos
continue
else
${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 1 "$__arg" $_start_pos $_end_pos 2>/dev/null && continue
fi
} || (( 1 ))
}
expanded_path=""
# The Great Fork: is this a command word? Is this a non-command word?
if (( this_word & 16 )) && [[ $__arg == 'always' ]]; then
# try-always construct
__style=${FAST_THEME_NAME}reserved-word # de facto a reserved word, although not de jure
(( next_word = 1 | (this_word & BIT_case_code) ))
elif (( (this_word & 1) && (in_redirection == 0) )) || [[ $braces_stack = T* ]]; then # T - typedef, etc.
if (( __arg_type == 1 )); then
__style=${FAST_THEME_NAME}precommand
[[ $__arg = "command" || $__arg = "exec" ]] && (( next_word = next_word | 64 ))
elif [[ $__arg = (sudo|doas) ]]; then
__style=${FAST_THEME_NAME}precommand
(( next_word = (next_word & ~2) | 4 | 1 ))
else
_mybuf=${${(Q)__arg}#\"}
if (( ${+parameters} )) && \
[[ $_mybuf = (#b)(*)(*)\$([a-zA-Z_][a-zA-Z0-9_]#|[0-9]##)(*) || \
$_mybuf = (#b)(*)(*)\$\{([a-zA-Z_][a-zA-Z0-9_:-]#|[0-9]##)(*) ]] && \
(( ${+parameters[${match[3]%%:-*}]} ))
then
-fast-highlight-main-type ${match[1]}${match[2]}${(P)match[3]%%:-*}${match[4]#\}}
elif [[ $braces_stack = T* ]]; then # T - typedef, etc.
REPLY=none
else
: ${expanded_path::=${~_mybuf}}
-fast-highlight-main-type $expanded_path
fi
case $REPLY in
reserved) # reserved word
[[ $__arg = "[[" ]] && __style=${FAST_THEME_NAME}double-sq-bracket || __style=${FAST_THEME_NAME}reserved-word
if [[ $__arg == $'\x7b' ]]; then # Y - '{'
braces_stack='Y'$braces_stack
elif [[ $__arg == $'\x7d' && $braces_stack = Y* ]]; then # Y - '}'
# We're at command word, so no need to check right_brace_is_recognised_everywhere
braces_stack=${braces_stack#Y}
__style=${FAST_THEME_NAME}reserved-word
(( next_word = next_word | 16 ))
elif [[ $__arg == "[[" ]]; then # A - [[
braces_stack='A'$braces_stack
# Counting complex brackets (for brackets-highlighter): 1. [[ as command
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
elif [[ $__arg == "for" ]]; then
(( next_word = next_word | 32 )) # BIT_for
elif [[ $__arg == "case" ]]; then
(( next_word = BIT_case_preamble ))
elif [[ $__arg = (typeset|declare|local|float|integer|export|readonly) ]]; then
braces_stack='T'$braces_stack
fi
;;
'suffix alias') __style=${FAST_THEME_NAME}suffix-alias;;
'global alias') __style=${FAST_THEME_NAME}global-alias;;
alias)
if [[ $__arg = ?*'='* ]]; then
# The so called (by old code) "insane_alias"
__style=${FAST_THEME_NAME}unknown-token
else
__style=${FAST_THEME_NAME}alias
(( ${+aliases} )) && alias_target=${aliases[$__arg]} || alias_target="${"$(alias -- $__arg)"#*=}"
[[ ${__FAST_HIGHLIGHT_TOKEN_TYPES[$alias_target]} = "1" && $__arg_type != "1" ]] && __FAST_HIGHLIGHT_TOKEN_TYPES[$__arg]="1"
fi
;;
builtin) [[ $__arg = "[" ]] && {
__style=${FAST_THEME_NAME}single-sq-bracket
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
} || __style=${FAST_THEME_NAME}builtin
# T - typeset, etc. mode
[[ $__arg = (typeset|declare|local|float|integer|export|readonly) ]] && braces_stack='T'$braces_stack
[[ $__arg = eval ]] && (( next_word = next_word | 256 ))
;;
function) __style=${FAST_THEME_NAME}function;;
command) __style=${FAST_THEME_NAME}command;;
hashed) __style=${FAST_THEME_NAME}hashed-command;;
dirpath) __style=${FAST_THEME_NAME}path-to-dir;;
none) # Assign?
if [[ $__arg == [a-zA-Z_][a-zA-Z0-9_]#(|\[[^\]]#\])(|[^\]]#\])(|[+])=* || $__arg == [0-9]##(|[+])=* || ( $braces_stack = T* && ${__arg_type} != 3 ) ]] {
__style=${FAST_THEME_NAME}assign
FAST_ASSIGNS_SEEN[${__arg%%=*}]=1
# Handle array assignment
[[ $__arg = (#b)*=(\()*(\))* || $__arg = (#b)*=(\()* ]] && {
(( __start=_start_pos-__PBUFLEN+${mbegin[1]}-1, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
# Counting complex brackets (for brackets-highlighter): 2. ( in array assign
_FAST_COMPLEX_BRACKETS+=( $__start )
(( mbegin[2] >= 1 )) && {
(( __start=_start_pos-__PBUFLEN+${mbegin[2]}-1, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
# Counting complex brackets (for brackets-highlighter): 3a. ) in array assign
_FAST_COMPLEX_BRACKETS+=( $__start )
} || in_array_assignment=1
} || { [[ ${braces_stack[1]} != 'T' ]] && (( next_word = (next_word | 1) & ~2 )); }
# Handle no-string highlight, string "/' highlight, math mode highlight
local ctmp="\"" dtmp="'"
itmp=${__arg[(i)$ctmp]}-1 iitmp=${__arg[(i)$dtmp]}-1
integer jtmp=${__arg[(b:itmp+2:i)$ctmp]} jjtmp=${__arg[(b:iitmp+2:i)$dtmp]}
(( itmp < iitmp && itmp <= __asize - 1 )) && (( jtmp > __asize && (jtmp = __asize), 1 > 0 )) && \
(( __start=_start_pos-__PBUFLEN+itmp, __end=_start_pos-__PBUFLEN+jtmp, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}") && \
{ itmp=${__arg[(i)=]}; __arg=${__arg[itmp,__asize]}; (( _start_pos += itmp - 1 ));
-fast-highlight-string; (( _start_pos = _start_pos - itmp + 1, 1 > 0 )); } || \
{
(( iitmp <= __asize - 1 )) && (( jjtmp > __asize && (jjtmp = __asize), 1 > 0 )) && \
(( __start=_start_pos-__PBUFLEN+iitmp, __end=_start_pos-__PBUFLEN+jjtmp, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}single-quoted-argument]}")
} || \
{
itmp=${__arg[(i)=]}; __arg=${__arg[itmp,__asize]}; (( _start_pos += itmp - 1 ));
[[ ${__arg[2,4]} = '$((' ]] && { -fast-highlight-math-string;
(( __start=_start_pos-__PBUFLEN+2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
# Counting complex brackets (for brackets-highlighter): 4. $(( in assign argument
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
(( jtmp = ${__arg[(I)\)\)]}-1, jtmp > 0 )) && {
(( __start=_start_pos-__PBUFLEN+jtmp, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
# Counting complex brackets (for brackets-highlighter): 5. )) in assign argument
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
}
} || -fast-highlight-string;
(( _start_pos = _start_pos - itmp + 1, 1 > 0 ))
}
} elif [[ $__arg = ${histchars[1]}* && -n ${__arg[2]} ]] {
__style=${FAST_THEME_NAME}history-expansion
} elif [[ $__arg == ${histchars[2]}* ]] {
__style=${FAST_THEME_NAME}history-expansion
} elif (( __arg_type == 3 )) {
# This highlights empty commands (semicolon follows nothing) as an error.
# Zsh accepts them, though.
(( this_word & 3 )) && __style=${FAST_THEME_NAME}commandseparator
} elif [[ $__arg[1,2] == '((' ]] {
# Arithmetic evaluation.
#
# Note: prior to zsh-5.1.1-52-g4bed2cf (workers/36669), the ${(z)...}
# splitter would only output the '((' token if the matching '))' had
# been typed. Therefore, under those versions of zsh, BUFFER="(( 42"
# would be highlighted as an error until the matching "))" are typed.
#
# We highlight just the opening parentheses, as a reserved word; this
# is how [[ ... ]] is highlighted, too.
# ADD
(( __start=_start_pos-__PBUFLEN, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
already_added=1
# Counting complex brackets (for brackets-highlighter): 6. (( as command
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
-fast-highlight-math-string
# ADD
[[ $__arg[-2,-1] == '))' ]] && {
(( __start=_end_pos-__PBUFLEN-2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
(( __delimited = __delimited ? 2 : __delimited ))
# Counting complex brackets (for brackets-highlighter): 7. )) for as-command ((
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
}
} elif [[ $__arg == '()' ]] {
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
# anonymous function
__style=${FAST_THEME_NAME}reserved-word
} elif [[ $__arg == $'\x28' ]] {
# subshell '(', stack: letter 'R'
__style=${FAST_THEME_NAME}reserved-word
braces_stack='R'$braces_stack
} elif [[ $__arg == $'\x29' ]] {
# ')', stack: letter 'R' for subshell
[[ $braces_stack = R* ]] && { braces_stack=${braces_stack#R}; __style=${FAST_THEME_NAME}reserved-word; }
} elif (( this_word & 14 )) {
__style=${FAST_THEME_NAME}default
} elif [[ $__arg = (';;'|';&'|';|') ]] && (( this_word & BIT_case_code )) {
(( next_word = (next_word | BIT_case_item) & ~(BIT_case_code+3) ))
__style=${FAST_THEME_NAME}default
} elif [[ $__arg = \$\([^\(]* ]] {
already_added=1
}
;;
*)
# ADD
# (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end commandtypefromthefuture-$REPLY")
already_added=1
;;
esac
fi
# in_redirection || BIT_regular || BIT_sudo_opt || BIT_sudo_arg
elif (( in_redirection + this_word & 14 ))
then # $__arg is a non-command word
case $__arg in
']]')
# A - [[
[[ $braces_stack = A* ]] && {
__style=${FAST_THEME_NAME}double-sq-bracket
(( __delimited = __delimited ? 2 : __delimited ))
# Counting complex brackets (for brackets-highlighter): 8a. ]] for as-command [[
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
} || {
[[ $braces_stack = *A* ]] && {
__style=${FAST_THEME_NAME}unknown-token
# Counting complex brackets (for brackets-highlighter): 8b. ]] for as-command [[
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
} || __style=${FAST_THEME_NAME}default
}
braces_stack=${braces_stack#A}
;;
']')
__style=${FAST_THEME_NAME}single-sq-bracket
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
;;
$'\x28')
# '(' inside [[
__style=${FAST_THEME_NAME}reserved-word
braces_stack='R'$braces_stack
;;
$'\x29') # ')' - subshell or end of array assignment
if (( in_array_assignment )); then
in_array_assignment=0
(( next_word = next_word | 1 ))
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
already_added=1
# Counting complex brackets (for brackets-highlighter): 3b. ) in array assign
_FAST_COMPLEX_BRACKETS+=( $__start )
elif [[ $braces_stack = R* ]]; then
braces_stack=${braces_stack#R}
__style=${FAST_THEME_NAME}reserved-word
# Zsh doesn't tokenize final ) if it's just single ')',
# but logically what's below is correct, so it is kept
# in case Zsh will be changed / fixed, etc.
elif [[ $braces_stack = F* ]]; then
__style=${FAST_THEME_NAME}builtin
fi
;;
$'\x28\x29') # '()' - possibly a function definition
# || false # TODO: or if the previous word was a command word
(( FAST_HIGHLIGHT[multi_func_def] )) && (( next_word = next_word | 1 ))
__style=${FAST_THEME_NAME}reserved-word
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
# Remove possible annoying unknown-token __style, or misleading function __style
reply[-1]=()
__fast_highlight_main__command_type_cache[$active_command]="function"
;;
'--'*) [[ $__arg == "--" ]] && { _was_double_hyphen=1; __style=${FAST_THEME_NAME}double-hyphen-option; } || {
(( !_was_double_hyphen )) && {
[[ "$__arg" = (#b)(--[a-zA-Z0-9_]##)=(*) ]] && {
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-hyphen-option]}")
(( __start=_start_pos-__PBUFLEN+1+mend[1], __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}optarg-${${${(M)match[2]:#<->}:+number}:-string}]}")
already_added=1
} || __style=${FAST_THEME_NAME}double-hyphen-option
} || __style=${FAST_THEME_NAME}default
}
;;
'-'*) (( !_was_double_hyphen )) && __style=${FAST_THEME_NAME}single-hyphen-option || __style=${FAST_THEME_NAME}default;;
\$\'*)
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}dollar-quoted-argument]}")
-fast-highlight-dollar-string
already_added=1
;;
[\"\']*|[^\"\\]##([\\][\\])#\"*|[^\'\\]##([\\][\\])#\'*)
# 256 is eval-mode
if (( this_word & 256 )) && [[ $__arg = [\'\"]* ]]; then
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}recursive-base]}")
if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
__idx=1
_mybuf=$FAST_THEME_NAME
FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
(( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
else
__idx=0
fi
(( _start_pos-__PBUFLEN >= 0 )) && \
-fast-highlight-process "$PREBUFFER" "${${__arg%[\'\"]}#[\'\"]}" $(( _start_pos + 1 ))
(( __idx )) && FAST_THEME_NAME=$_mybuf
already_added=1
else
[[ $__arg = *([^\\][\#][\#]|"(#b)"|"(#B)"|"(#m)"|"(#c")* && $highlight_glob -ne 0 ]] && \
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}globbing-ext]}")
# Reusing existing vars, treat this code like C++ STL
# header, full of underscores and unhelpful var names
itmp=0 __workbuf=$__arg __tmp="" cdpath_dir=$__arg
while [[ $__workbuf = (#b)[^\"\'\\]#(([\"\'])|[\\](*))(*) ]]; do
[[ -n ${match[3]} ]] && {
itmp+=${mbegin[1]}
# Optionally skip 1 quoted char
[[ $__tmp = \' ]] && __workbuf=${match[3]} || { itmp+=1; __workbuf=${match[3]:1}; }
} || {
itmp+=${mbegin[1]}
__workbuf=${match[4]}
# Toggle quoting
[[ ( ${match[1]} = \" && $__tmp != \' ) || ( ${match[1]} = \' && $__tmp != \" ) ]] && {
[[ $__tmp = [\"\'] ]] && {
# End of quoting
(( __start=_start_pos-__PBUFLEN+iitmp-1, __end=_start_pos-__PBUFLEN+itmp, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}${${${__tmp#\'}:+double-quoted-argument}:-single-quoted-argument}]}")
already_added=1
[[ $__tmp = \" ]] && {
__arg=${cdpath_dir[iitmp+1,itmp-1]}
(( _start_pos += iitmp - 1 + 1 ))
-fast-highlight-string
(( _start_pos = _start_pos - iitmp + 1 - 1 ))
}
# The end-of-quoting proper algorithm action
__tmp=
} || {
# Beginning of quoting
iitmp=itmp
# The beginning-of-quoting proper algorithm action
__tmp=${match[1]}
}
}
}
done
[[ $__tmp = [\"\'] ]] && {
(( __start=_start_pos-__PBUFLEN+iitmp-1, __end=_start_pos-__PBUFLEN+__asize, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}${${${__tmp#\'}:+double-quoted-argument}:-single-quoted-argument}]}")
already_added=1
[[ $__tmp = \" ]] && {
__arg=${cdpath_dir[iitmp+1,__asize]}
(( _start_pos += iitmp - 1 + 1 ))
-fast-highlight-string
(( _start_pos = _start_pos - iitmp + 1 - 1 ))
}
}
fi
;;
\$\(\(*)
already_added=1
-fast-highlight-math-string
# ADD
(( __start=_start_pos-__PBUFLEN+1, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
# Counting complex brackets (for brackets-highlighter): 9. $(( as argument
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
# ADD
[[ $__arg[-2,-1] == '))' ]] && (( __start=_end_pos-__PBUFLEN-2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
# Counting complex brackets (for brackets-highlighter): 10. )) for as-argument $((
_FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
;;
'`'*)
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-quoted-argument]}")
if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
__idx=1
_mybuf=$FAST_THEME_NAME
FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
(( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
else
__idx=0
fi
(( _start_pos-__PBUFLEN >= 0 )) && \
-fast-highlight-process "$PREBUFFER" "${${__arg%[\`]}#[\`]}" $(( _start_pos + 1 ))
(( __idx )) && FAST_THEME_NAME=$_mybuf
already_added=1
;;
'((') # 'F' - (( after for
(( this_word & 32 )) && {
braces_stack='F'$braces_stack
__style=${FAST_THEME_NAME}double-paren
# Counting complex brackets (for brackets-highlighter): 11. (( as for-syntax
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
# This is set after __arg_type == 2, and also here,
# when another alternate-syntax capable command occurs
__delimited=1
}
;;
'))') # 'F' - (( after for
[[ $braces_stack = F* ]] && {
braces_stack=${braces_stack#F}
__style=${FAST_THEME_NAME}double-paren
# Counting complex brackets (for brackets-highlighter): 12. )) as for-syntax
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
(( __delimited = __delimited ? 2 : __delimited ))
}
;;
'<<<')
(( next_word = (next_word | 128) & ~3 ))
[[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-tri]} != "none" ]] && (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-tri]}")
already_added=1
;;
*) # F - (( after for
if [[ $braces_stack = F* ]]; then
-fast-highlight-string
_mybuf=$__arg
__idx=_start_pos
while [[ $_mybuf = (#b)[^a-zA-Z\{\$]#([a-zA-Z][a-zA-Z0-9]#)(*) ]]; do
(( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-variable]}")
__idx+=${mend[1]}
_mybuf=${match[2]}
done
_mybuf=$__arg
__idx=_start_pos
while [[ $_mybuf = (#b)[^+\<\>=:\*\|\&\^\~-]#([+\<\>=:\*\|\&\^\~-]##)(*) ]]; do
(( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-operator]}")
__idx+=${mend[1]}
_mybuf=${match[2]}
done
_mybuf=$__arg
__idx=_start_pos
while [[ $_mybuf = (#b)[^0-9]#([0-9]##)(*) ]]; do
(( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-number]}")
__idx+=${mend[1]}
_mybuf=${match[2]}
done
if [[ $__arg = (#b)[^\;]#(\;)[\ ]# ]]; then
(( __start=_start_pos-__PBUFLEN+${mbegin[1]}-1, __end=_start_pos-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-separator]}")
fi
already_added=1
elif [[ $__arg = *([^\\][\#][\#]|"(#b)"|"(#B)"|"(#m)"|"(#c")* ]]; then
(( highlight_glob )) && __style=${FAST_THEME_NAME}globbing-ext || __style=${FAST_THEME_NAME}default
elif [[ $__arg = ([*?]*|*[^\\][*?]*) ]]; then
(( highlight_glob )) && __style=${FAST_THEME_NAME}globbing || __style=${FAST_THEME_NAME}default
elif [[ $__arg = \$* ]]; then
__style=${FAST_THEME_NAME}variable
elif [[ $__arg = $'\x7d' && $braces_stack = Y* && ${FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]} = "1" ]]; then
# right brace, i.e. $'\x7d' == '}'
# Parsing rule: # {
#
# Additionally, `tt(})' is recognized in any position if neither the
# tt(IGNORE_BRACES) option nor the tt(IGNORE_CLOSE_BRACES) option is set."""
braces_stack=${braces_stack#Y}
__style=${FAST_THEME_NAME}reserved-word
(( next_word = next_word | 16 ))
elif [[ $__arg = (';;'|';&'|';|') ]] && (( this_word & BIT_case_code )); then
(( next_word = (next_word | BIT_case_item) & ~(BIT_case_code+3) ))
__style=${FAST_THEME_NAME}default
elif [[ $__arg = ${histchars[1]}* && -n ${__arg[2]} ]]; then
__style=${FAST_THEME_NAME}history-expansion
elif (( __arg_type == 3 )); then
__style=${FAST_THEME_NAME}commandseparator
elif (( in_redirection == 2 )); then
__style=${FAST_THEME_NAME}redirection
elif (( ${+galiases[(e)$__arg]} )); then
__style=${FAST_THEME_NAME}global-alias
else
if [[ ${FAST_HIGHLIGHT[no_check_paths]} != 1 ]]; then
if [[ ${FAST_HIGHLIGHT[use_async]} != 1 ]]; then
if -fast-highlight-check-path noasync; then
# ADD
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
already_added=1
# TODO: path separators, optimize and add to async code-path
[[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]} && ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path]} != ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]} ]] && {
for (( __pos = _start_pos; __pos <= _end_pos; __pos++ )) ; do
# ADD
[[ ${__buf[__pos]} == "/" ]] && (( __start=__pos-__PBUFLEN, __start >= 0 )) && reply+=("$(( __start - 1 )) $__start ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]}")
done
}
else
__style=${FAST_THEME_NAME}default
fi
else
if [[ -z ${FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}]} || $(( EPOCHSECONDS - FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}-born-at] )) -gt 8 ]]; then
if [[ $LASTWIDGET != *-or-beginning-search ]]; then
exec {PCFD}< <(-fast-highlight-check-path; sleep 5)
command sleep 0
FAST_HIGHLIGHT[path-queue]+=";$_start_pos $_end_pos;"
is-at-least 5.0.6 && __pos=1 || __pos=0
zle -F ${${__pos:#0}:+-w} $PCFD fast-highlight-check-path-handler
already_added=1
else
__style=${FAST_THEME_NAME}default
fi
elif [[ ${FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}]%D} -eq 1 ]]; then
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path${${(M)FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}]%D}:+-to-dir}]}")
already_added=1
else
__style=${FAST_THEME_NAME}default
fi
fi
else
__style=${FAST_THEME_NAME}default
fi
fi
;;
esac
elif (( this_word & 128 ))
then
(( next_word = (next_word | 2) & ~129 ))
[[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-text]} != "none" ]] && (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-text]}")
-fast-highlight-string ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-var]:#none}
already_added=1
elif (( this_word & (BIT_case_preamble + BIT_case_item) ))
then
if (( this_word & BIT_case_preamble )); then
[[ $__arg = "in" ]] && {
__style=${FAST_THEME_NAME}reserved-word
(( next_word = BIT_case_item ))
} || {
__style=${FAST_THEME_NAME}case-input
(( next_word = BIT_case_preamble ))
}
else
if (( this_word & BIT_case_nempty_item == 0 )) && [[ $__arg = "esac" ]]; then
(( next_word = 1 ))
__style=${FAST_THEME_NAME}reserved-word
elif [[ $__arg = (\(*\)|\)|\() ]]; then
[[ $__arg = *\) ]] && (( next_word = BIT_case_code | 1 )) || (( next_word = BIT_case_item | BIT_case_nempty_item ))
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
(( ${#__arg} > 1 )) && {
_FAST_COMPLEX_BRACKETS+=( $(( _start_pos+${#__arg}-1-__PBUFLEN )) )
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}case-parentheses]}")
(( __start=_start_pos+1-__PBUFLEN, __end=_end_pos-1-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}case-condition]}")
already_added=1
} || {
__style=${FAST_THEME_NAME}case-parentheses
}
else
(( next_word = BIT_case_item | BIT_case_nempty_item ))
__style=${FAST_THEME_NAME}case-condition
fi
fi
fi
if [[ $__arg = (#b)*'#'(([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])|([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F]))* || $__arg = (#b)*'rgb('(([0-9a-fA-F][0-9a-fA-F](#c0,1)),([0-9a-fA-F][0-9a-fA-F](#c0,1)),([0-9a-fA-F][0-9a-fA-F](#c0,1)))* ]]; then
if [[ -n $match[2] ]]; then
if [[ $match[2] = ?? || $match[3] = ?? || $match[4] = ?? ]]; then
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end bg=#${(l:2::0:)match[2]}${(l:2::0:)match[3]}${(l:2::0:)match[4]}")
else
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end bg=#$match[2]$match[3]$match[4]")
fi
else
(( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end bg=#$match[5]$match[6]$match[7]")
fi
already_added=1
fi
# ADD
(( already_added == 0 )) && [[ ${FAST_HIGHLIGHT_STYLES[$__style]} != "none" ]] && (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
if (( (__arg_type == 3) && ((this_word & (BIT_case_preamble|BIT_case_item)) == 0) )); then
if [[ $__arg == ';' ]] && (( in_array_assignment )); then
# literal newline inside an array assignment
(( next_word = 2 | (next_word & BIT_case_code) ))
elif [[ -n ${braces_stack[(r)A]} ]]; then
# 'A' in stack -> inside [[ ... ]]
(( next_word = 2 | (next_word & BIT_case_code) ))
else
braces_stack=${braces_stack#T}
(( next_word = 1 | (next_word & BIT_case_code) ))
highlight_glob=1
# A new command means that we should not expect that alternate
# syntax will occur (this is also in the ';' short-path), but
# || and && mean going down just 1 step, not all the way to 0
[[ $__arg != ("||"|"&&") ]] && __delimited=0 || (( __delimited = __delimited == 2 ? 1 : __delimited ))
fi
elif (( ( (__arg_type == 1) || (__arg_type == 2) ) && (this_word & 1) )); then # (( __arg_type == 1 || __arg_type == 2 )) && (( this_word & 1 ))
__delimited=1
(( next_word = 1 | (next_word & (64 | BIT_case_code)) ))
elif [[ $__arg == "repeat" ]] && (( this_word & 1 )); then
__delimited=1
# skip the repeat-count word
in_redirection=2
# The redirection mechanism assumes $this_word describes the word
# following the redirection. Make it so.
#
# That word can be a command word with shortloops (`repeat 2 ls`)
# 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 = 3 ))
fi
_start_pos=$_end_pos
# This is the default/common codepath.
(( this_word = in_redirection == 0 ? next_word : this_word )) #else # Stall $this_word.
done
# Do we have whole buffer? I.e. start at zero
[[ $3 != 0 ]] && return 0
# The loop overwrites ")" with "x", except those from $( ) substitution
#
# __pos: current nest level, starts from 0
# __workbuf: copy of __buf, with limit on 250 characters
# __idx: index in whole command line buffer
# __list: list of coordinates of ) which shouldn't be ovewritten
_mybuf=${__buf[1,250]} __workbuf=$_mybuf __idx=0 __pos=0 __list=()
while [[ $__workbuf = (#b)[^\(\)]#([\(\)])(*) ]]; do
if [[ ${match[1]} == \( ]]; then
__arg=${_mybuf[__idx+${mbegin[1]}-1,__idx+${mbegin[1]}-1+2]}
[[ $__arg = '$('[^\(] ]] && __list+=( $__pos )
[[ $__arg = '$((' ]] && _mybuf[__idx+${mbegin[1]}-1]=x
# Increase parenthesis level
__pos+=1
else
# Decrease parenthesis level
__pos=__pos-1
[[ -z ${__list[(r)$__pos]} ]] && [[ $__pos -gt 0 ]] && _mybuf[__idx+${mbegin[1]}]=x
fi
__idx+=${mbegin[2]}-1
__workbuf=${match[2]}
done
# Run on fake buffer with replaced parentheses: ")" into "x"
if [[ "$_mybuf" = *$__nul* ]]; then
# Try to avoid conflict with the \0, however
# we have to split at *some* character - \7
# is ^G, so one cannot have null and ^G at
# the same time on the command line
__nul=$'\7'
fi
__inputs=( ${(ps:$__nul:)${(S)_mybuf//(#b)*\$\(([^\)]#)(\)|(#e))/${mbegin[1]};${mend[1]}${__nul}}%$__nul*} )
if [[ "${__inputs[1]}" != "$_mybuf" && -n "${__inputs[1]}" ]]; then
if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
__idx=1
__tmp=$FAST_THEME_NAME
FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
(( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
else
__idx=0
fi
for _mybuf in $__inputs; do
(( __start=${_mybuf%%;*}-__PBUFLEN-1, __end=${_mybuf##*;}-__PBUFLEN, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${__tmp}recursive-base]}")
# Pass authentic buffer for recursive analysis
-fast-highlight-process "$PREBUFFER" "${__buf[${_mybuf%%;*},${_mybuf##*;}]}" $(( ${_mybuf%%;*} - 1 ))
done
# Restore theme
(( __idx )) && FAST_THEME_NAME=$__tmp
fi
return 0
}
-fast-highlight-check-path()
{
(( _start_pos-__PBUFLEN >= 0 )) || \
{ [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
[[ $1 != "noasync" ]] && {
print -r -- ${sysparams[pid]}
# This is to fill cache
print -r -- $__arg
}
: ${expanded_path:=${(Q)~__arg}}
[[ -n ${FAST_BLIST_PATTERNS[(k)${${(M)expanded_path:#/*}:-$PWD/$expanded_path}]} ]] && { [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
[[ -z $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
[[ -d $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos ${_end_pos}D" || __style=${FAST_THEME_NAME}path-to-dir; return 0; }
[[ -e $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos $_end_pos" || __style=${FAST_THEME_NAME}path; return 0; }
# Search the path in CDPATH, only for CD command
[[ $active_command = "cd" ]] && for cdpath_dir in $cdpath; do
[[ -d $cdpath_dir/$expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos ${_end_pos}D" || __style=${FAST_THEME_NAME}path-to-dir; return 0; }
[[ -e $cdpath_dir/$expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos $_end_pos" || __style=${FAST_THEME_NAME}path; return 0; }
done
# It's not a path.
[[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"
return 1
}
-fast-highlight-check-path-handler() {
local IFS=$'\n' pid PCFD=$1 line stripped val
integer idx
if read -r -u $PCFD pid; then
if read -r -u $PCFD val; then
if read -r -u $PCFD line; then
stripped=${${line#- }%D}
FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}-born-at]=$EPOCHSECONDS
idx=${${FAST_HIGHLIGHT[path-queue]}[(I)$stripped]}
(( idx > 0 )) && {
if [[ $line != -* ]]; then
FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]="1${(M)line%D}"
region_highlight+=("${line%% *} ${${line##* }%D} ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path${${(M)line%D}:+-to-dir}]}")
else
FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]=0
fi
val=${FAST_HIGHLIGHT[path-queue]}
val[idx-1,idx+${#stripped}]=""
FAST_HIGHLIGHT[path-queue]=$val
[[ ${FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]%D} = 1 && ${#val} -le 27 ]] && zle -R
}
fi
fi
kill -9 $pid 2>/dev/null
fi
zle -F -w ${PCFD}
exec {PCFD}<&-
}
zle -N -- fast-highlight-check-path-handler -fast-highlight-check-path-handler
# Highlight special blocks inside double-quoted strings
#
# The while [[ ... ]] pattern is logically ((A)|(B)|(C)|(D)|(E))(*), where:
# - A matches $var[abc]
# - B matches ${(...)var[abc]}
# - C matches $
# - D matches \$ or \" or \'
# - E matches \*
#
# and the first condition -n ${match[7] uses D to continue searching when
# backslash-something (not ['"$]) is occured.
#
# $1 - additional style to glue-in to added style
-fast-highlight-string()
{
(( _start_pos-__PBUFLEN >= 0 )) || return 0
_mybuf=$__arg
__idx=_start_pos
# 7 8
while [[ $_mybuf = (#b)[^\$\\]#((\$(#B)([#+^=~](#c1,2))(#c0,1)(#B)([a-zA-Z_:][a-zA-Z0-9_:]#|[0-9]##)(#b)(\[[^\]]#\])(#c0,1))|(\$[{](#B)([#+^=~](#c1,2))(#c0,1)(#b)(\([a-zA-Z0-9_:@%#]##\))(#c0,1)[a-zA-Z0-9_:#]##(\[[^\]]#\])(#c0,1)[}])|\$|[\\][\'\"\$]|[\\](*))(*) ]]; do
[[ -n ${match[7]} ]] && {
# Skip following char – it is quoted. Choice is
# made to not highlight such quoting
__idx+=${mbegin[1]}+1
_mybuf=${match[7]:1}
} || {
__idx+=${mbegin[1]}-1
_end_idx=__idx+${mend[1]}-${mbegin[1]}+1
_mybuf=${match[8]}
# ADD
(( __start=__idx-__PBUFLEN, __end=_end_idx-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${${1:+$1}:-${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-or-dollar-double-quoted-argument]}}")
__idx=_end_idx
}
done
return 0
}
# Highlight math and non-math context variables inside $(( )) and (( ))
#
# The while [[ ... ]] pattern is logically ((A)|(B)|(C)|(D))(*), where:
# - A matches $var[abc]
# - B matches ${(...)var[abc]}
# - C matches $
# - D matches words [a-zA-Z]## (variables)
#
# Parameters used: _mybuf, __idx, _end_idx, __style
-fast-highlight-math-string()
{
(( _start_pos-__PBUFLEN >= 0 )) || return 0
_mybuf=$__arg
__idx=_start_pos
# 7
while [[ $_mybuf = (#b)[^\$_a-zA-Z0-9]#((\$(#B)(+|)(#B)([a-zA-Z_:][a-zA-Z0-9_:]#|[0-9]##)(#b)(\[[^\]]##\])(#c0,1))|(\$[{](#B)(+|)(#b)(\([a-zA-Z0-9_:@%#]##\))(#c0,1)[a-zA-Z0-9_:#]##(\[[^\]]##\])(#c0,1)[}])|\$|[a-zA-Z_][a-zA-Z0-9_]#|[0-9]##)(*) ]]; do
__idx+=${mbegin[1]}-1
_end_idx=__idx+${mend[1]}-${mbegin[1]}+1
_mybuf=${match[7]}
[[ ${match[1]} = [0-9]* ]] && __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}mathnum]} || {
[[ ${match[1]} = [a-zA-Z_]* ]] && {
[[ ${+parameters[${match[1]}]} = 1 || ${FAST_ASSIGNS_SEEN[${match[1]}]} = 1 ]] && \
__style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}mathvar]} || \
__style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}matherr]}
} || {
[[ ${match[1]} = "$"* ]] && {
match[1]=${match[1]//[\{\}+]/}
if [[ ${match[1]} = "$" || ${FAST_ASSIGNS_SEEN[${match[1]:1}]} = 1 ]] || \
{ eval "[[ -n \${(P)\${match[1]:1}} ]]" } 2>> /dev/null; then
__style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-or-dollar-double-quoted-argument]}
else
__style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}matherr]}
fi
}
}
}
# ADD
[[ $__style != "none" && -n $__style ]] && (( __start=__idx-__PBUFLEN, __end=_end_idx-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end $__style")
__idx=_end_idx
done
}
# Highlight special chars inside dollar-quoted strings
-fast-highlight-dollar-string()
{
(( _start_pos-__PBUFLEN >= 0 )) || return 0
local i j k __style
local AA
integer c
# Starting dollar-quote is at 1:2, so __start parsing at offset 3 in the string.
for (( i = 3 ; i < _end_pos - _start_pos ; i += 1 )) ; do
(( j = i + _start_pos - 1 ))
(( k = j + 1 ))
case ${__arg[$i]} in
"\\") __style=${FAST_THEME_NAME}back-dollar-quoted-argument
for (( c = i + 1 ; c <= _end_pos - _start_pos ; c += 1 )); do
[[ ${__arg[$c]} != ([0-9xXuUa-fA-F]) ]] && break
done
AA=$__arg[$i+1,$c-1]
# Matching for HEX and OCT values like \0xA6, \xA6 or \012
if [[ "$AA" == (#m)(#s)(x|X)[0-9a-fA-F](#c1,2)
|| "$AA" == (#m)(#s)[0-7](#c1,3)
|| "$AA" == (#m)(#s)u[0-9a-fA-F](#c1,4)
|| "$AA" == (#m)(#s)U[0-9a-fA-F](#c1,8)
]]; then
(( k += MEND ))
(( i += MEND ))
else
if (( __asize > i+1 )) && [[ $__arg[i+1] == [xXuU] ]]; then
# \x not followed by hex digits is probably an error
__style=${FAST_THEME_NAME}unknown-token
fi
(( k += 1 )) # Color following char too.
(( i += 1 )) # Skip parsing the escaped char.
fi
;;
*) continue ;;
esac
# ADD
(( __start=j-__PBUFLEN, __end=k-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
done
}
-fast-highlight-init() {
_FAST_COMPLEX_BRACKETS=()
__fast_highlight_main__command_type_cache=()
}
typeset -ga FSH_LIST
-fsh_sy_h_shappend() {
FSH_LIST+=( "$(( $1 - 1 ));;$(( $2 ))" )
}
functions -M fsh_sy_h_append 2 2 -fsh_sy_h_shappend 2>/dev/null
# vim:ft=zsh:sw=2:sts=2