zdharma-continuum.fast-synt.../fast-highlight

987 lines
46 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -------------------------------------------------------------------------------------------------
# Copyright (c) 2010-2016 zsh-syntax-highlighting contributors
# Copyright (c) 2016-2018 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
# 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_BASE_DIR"/current_theme.zsh ]]; then
source "$FAST_BASE_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[alias]:=fg=green}
: ${FAST_HIGHLIGHT_STYLES[suffix-alias]:=fg=green}
: ${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_pathseparator]:=}
: ${FAST_HIGHLIGHT_STYLES[globbing]:=fg=blue,bold}
: ${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-word]:=bg=blue}
fi
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
# ';;' ';&' ';|'
# Assign-capability starters
typeset 4
declare 4
local 4
float 4
integer 4
export 4
readonly 4
)
# A hash instead of multiple globals
typeset -gA FAST_HIGHLIGHT
# 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 (( $+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" ]] && {
[[ -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 noksharrays
[[ $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 cdpath_dir cur_cmd alias_target _was_double_hyphen=0 __nul=$'\0'
# 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} already_added offset __idx _end_idx this_word=1 next_word=0 insane_alias __pos __asize
local -a match mbegin mend __inputs
# 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
# 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=()
[[ -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.
#
# $already_added (see next paragraph)
# $__style how to highlight $__arg
# $in_array_assignment boolean flag for "between '(' and ')' of array assignment"
# $highlight_glob boolean flag for "'noglob' is in effect"
#
already_added=0
__style=${FAST_THEME_NAME}unknown-token
if (( this_word & 1 )); then
in_array_assignment=0
[[ $__arg == 'noglob' ]] && highlight_glob=0
fi
__asize=${#__arg}
# Compute the new $_start_pos and $_end_pos, skipping over whitespace in $__buf.
if [[ $__arg == ';' ]] ; then
[[ "${braces_stack[1]}" = 'T' ]] && braces_stack[1]=""
# We're looking for either a semicolon or a newline, whichever comes
# first. Both of these are rendered as a ";" (SEPER) by the ${(z)..}
# flag.
#
# We can't use the (Z+n+) flag because that elides the __end-of-command
# token altogether, so 'echo foo\necho bar' (two commands) becomes
# indistinguishable from 'echo foo echo bar' (one command with three
# words for arguments).
needle=$'[;\n]'
offset=$(( ${proc_buf[(i)$needle]} - 1 ))
(( _start_pos += offset ))
(( _end_pos = _start_pos + __asize ))
# Do not run default code for case when there is a new line
# It shouldn't be treated as ';', i.e. shouldn't be highlighted
# as unknown-token when appears after command-starting __arg like "{"
if [[ "${proc_buf[offset+1]}" = $'\n' ]]; then
(( in_array_assignment )) && (( this_word = 2 )) || { (( this_word = 1 )); highlight_glob=1; }
in_redirection=0
proc_buf="${proc_buf[offset + __asize + 1,__len]}"
_start_pos=$_end_pos
continue
else
# One more short path  for ';' command separator
(( in_array_assignment )) && (( this_word = 2 )) || { (( this_word = 1 )); highlight_glob=1; }
in_redirection=0
[[ "${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}commandseparator]}" != "none" ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __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
fi
arg_type=3
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[1] == $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-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
_start_pos=$_end_pos
continue
fi
# Analyse the current word.
if [[ $__arg == (<0-9>|)(\<|\>)* ]] && [[ $__arg != (\<|\>)$'\x28'* ]] && [[ "$__arg" != "<<<" ]]; then
# A '<' or '>', possibly followed by a digit
in_redirection=2
fi
# Special-case the first word after 'sudo'.
if (( ! in_redirection )); then
if (( this_word & 4 )) && [[ $__arg != -* ]]; then
(( this_word = this_word ^ 4 ))
fi
# 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 prevents misbehavior with sudo -u -otherargument
'-'*)
(( this_word = this_word & ~1 ))
(( next_word = next_word | 1 ))
(( next_word = next_word | 4 ))
;;
*) ;;
esac
elif (( this_word & 8 )); then
(( next_word = next_word | 4 ))
(( next_word = next_word | 1 ))
elif (( this_word & 64 )); then
[[ "$__arg" = -[pvV-]## && "$cur_cmd" = "command" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
[[ "$__arg" = -[cla-]## && "$cur_cmd" = "exec" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
[[ "$__arg" = \{[a-zA-Z][a-zA-Z0-9]#\} && "$cur_cmd" = "exec" ]] && {
# Highlight {descriptor} passed to exec
(( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}exec-descriptor]}")
already_added=1
}
fi
fi
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 ))
elif (( this_word & 1 )) && (( in_redirection == 0 )) || [[ "${braces_stack[1]}" = 'T' ]]; then
cur_cmd="$__arg"
if (( arg_type == 1 )); then
__style=${FAST_THEME_NAME}precommand
[[ "$__arg" = "command" || "$__arg" = "exec" ]] && (( next_word = next_word | 64 ))
elif [[ "$__arg" = "sudo" ]]; then
__style=${FAST_THEME_NAME}precommand
(( next_word = next_word & ~2 ))
(( next_word = next_word | 4 ))
(( next_word = next_word | 1 ))
else
# Special-case: command word is '$foo', like that, without braces or anything.
#
# That's not entirely correct --- if the parameter's value happens to be a reserved
# word, the parameter expansion will be highlighted as a reserved word --- but that
# incorrectness is outweighed by the usability improvement of permitting the use of
# parameters that refer to commands, functions, and builtins.
if [[ ${__arg[1]} == \$ ]] && (( ${+parameters} )) && \
[[ ${__arg:1} = (#b)([a-zA-Z_][a-zA-Z0-9_]#|[0-9]##) || ${__arg:1} = (#b)\{([a-zA-Z_][a-zA-Z0-9_]#|[0-9]##)\} ]] && \
(( ${+parameters[${match[1]}]} )); then
-fast-highlight-main-type ${(P)match[1]}
elif [[ "${braces_stack[1]}" = 'T' ]]; then
REPLY=none
else
: ${expanded_path::=${(Q)~__arg}}
-fast-highlight-main-type $expanded_path
fi
case $REPLY in
reserved) # reserved word
[[ "$__arg" = "[[" ]] && __style=${FAST_THEME_NAME}builtin || __style=${FAST_THEME_NAME}reserved-word
if [[ $__arg == $'\x7b' ]]; then # {
braces_stack='Y'"$braces_stack"
elif [[ $__arg == $'\x7d' && $braces_stack[1] == "Y" ]]; then # }
# We're at command word, so no need to check right_brace_is_recognised_everywhere
braces_stack[1]=""
__style=${FAST_THEME_NAME}reserved-word
(( next_word = next_word | 16 ))
elif [[ $__arg == "[[" ]]; then
braces_stack='A'"$braces_stack"
elif [[ $__arg == "for" ]]; then
(( next_word = next_word | 32 )) # BIT_for
fi
;;
'suffix alias') __style=${FAST_THEME_NAME}suffix-alias;;
alias)
insane_alias=0
case $__arg in
# Issue #263: aliases with '=' on their LHS.
#
# There are three cases:
#
# - Unsupported, breaks 'alias -L' output, but invokable:
('='*) :;;
# - Unsupported, not invokable:
(*'='*) insane_alias=1;;
# - The common case:
(*) :;;
esac
if (( insane_alias )); then
__style=${FAST_THEME_NAME}unknown-token
else
__style=${FAST_THEME_NAME}alias
zmodload -e zsh/parameter && 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) __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;;
none) # Assign?
if [[ $__arg == [a-zA-Z_][a-zA-Z0-9_]#(|\[[^\]]#\])(|[^\]]#\])(|[+])=* || $__arg == [0-9]##(|[+])=* || "${braces_stack[1]}" = 'T' ]]; then
__style=${FAST_THEME_NAME}assign
[[ "$__arg" = *[=]* ]] && FAST_ASSIGNS_SEEN[${__arg%%=*}]=1
# Handle array assignment
integer itmp=${__arg[(i)=\(]}-1+1 iitmp=${__arg[(i)\)]}-1
(( itmp <= __asize - 1 )) && {
(( __start=_start_pos-${#PREBUFFER}+itmp, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
(( iitmp <= __asize - 1 )) && (( __start=_start_pos-${#PREBUFFER}+iitmp, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}") || 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-${#PREBUFFER}+itmp, __end=_start_pos-${#PREBUFFER}+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-${#PREBUFFER}+iitmp, __end=_start_pos-${#PREBUFFER}+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-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$(( __start + 2 )) $(( __start + 4 )) ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
(( jtmp = ${__arg[(I)\)\)]}-1, jtmp > 0 )) && (( __start=_start_pos-${#PREBUFFER}+jtmp, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
} || -fast-highlight-string;
(( _start_pos = _start_pos - itmp + 1, 1 > 0 ))
}
elif [[ $__arg[1] = $histchars[1] && -n "${__arg[2]}" ]]; then
__style=${FAST_THEME_NAME}history-expansion
elif [[ $__arg[1] == $histchars[2] ]]; then
__style=${FAST_THEME_NAME}history-expansion
elif (( arg_type == 3 )); then
# This highlights empty commands (semicolon follows nothing) as an error.
# Zsh accepts them, though.
(( this_word & 2 )) && __style=${FAST_THEME_NAME}commandseparator
elif [[ $__arg[1,2] == '((' ]]; then
# 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-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $(( __start + 2 )) ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
already_added=1
-fast-highlight-math-string
# ADD
[[ $__arg[-2,-1] == '))' ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$(( __end - 2 )) $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
elif [[ $__arg == '()' ]]; then
# anonymous function
__style=${FAST_THEME_NAME}reserved-word
elif [[ $__arg == $'\x28' ]]; then
# subshell (
__style=${FAST_THEME_NAME}reserved-word
braces_stack='R'"$braces_stack"
elif [[ $__arg == $'\x29' ]]; then
# )
[[ $braces_stack[1] == "R" ]] && { braces_stack[1]=""; __style=${FAST_THEME_NAME}reserved-word; }
elif (( this_word & 14 )); then
__style=${FAST_THEME_NAME}default
fi
;;
*)
# ADD
# (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __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
']]')
__style=${FAST_THEME_NAME}builtin
[[ $braces_stack[1] == "A" ]] && braces_stack[1]=""
;;
']')
__style=${FAST_THEME_NAME}builtin
;;
$'\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
__style=${FAST_THEME_NAME}assign
in_array_assignment=0
(( next_word = next_word | 1 ))
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
elif [[ $braces_stack[1] == "R" ]]; then
braces_stack[1]=""
__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[1]}" = "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
# Remove possible annoying unknown-token __style, or misleading function __style
reply[-1]=()
;;
'--'*) [[ "$__arg" == "--" ]] && { _was_double_hyphen=1; __style=${FAST_THEME_NAME}double-hyphen-option; } || { (( !_was_double_hyphen )) && __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;;
'"'*|"'"*)
if (( this_word & 256 )); then
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]}"
(( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source "$FAST_BASE_DIR/secondary_theme.zsh"
else
__idx=0
fi
-fast-highlight-process "$PREBUFFER" "${__arg[2,__asize]%[\'\"]}" "$(( _start_pos + 1 ))"
(( __idx )) && FAST_THEME_NAME="$_mybuf"
already_added=1
else
if [[ "$__arg" = "'"* ]]; then
__style=${FAST_THEME_NAME}single-quoted-argument
else
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}")
-fast-highlight-string
already_added=1
fi
fi
;;
[^\"\\]##([\\][\\])#\"*)
# ADD
local ctmp="\""
integer itmp=${__arg[(i)$ctmp]}-1
integer jtmp=${__arg[(b:itmp+2:i)$ctmp]}
(( __start=_start_pos-${#PREBUFFER}+itmp, __end=_start_pos-${#PREBUFFER}+jtmp, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}")
-fast-highlight-string
already_added=1
;;
[^\'\\]##([\\][\\])#\'*)
# ADD
local ctmp="'"
integer itmp=${__arg[(i)$ctmp]}-1
integer jtmp=${__arg[(b:itmp+2:i)$ctmp]}
(( __start=_start_pos-${#PREBUFFER}+itmp, __end=_start_pos-${#PREBUFFER}+jtmp, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}")
already_added=1
;;
\$\'*)
# ADD
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}dollar-quoted-argument]}")
-fast-highlight-dollar-string
already_added=1
;;
\$\(\(*)
already_added=1
-fast-highlight-math-string
# ADD
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$(( __start + 1 )) $(( __start + 3 )) ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
# ADD
[[ $__arg[-2,-1] == '))' ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$(( __end - 2 )) $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}reserved-word]}")
;;
'`'*) __style=${FAST_THEME_NAME}back-quoted-argument;;
'((') # 'F' - (( after for
(( this_word & 32 )) && braces_stack='F'"$braces_stack" && __style=${FAST_THEME_NAME}builtin
;;
'))') # 'F' - (( after for
[[ "${braces_stack[1]}" = "F" ]] && braces_stack[1]="" && __style=${FAST_THEME_NAME}builtin
;;
'<<<')
(( next_word = 128 ))
[[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-tri]} != "none" ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-tri]}")
already_added=1
;;
*) if [[ "${braces_stack[1]}" = "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-${#PREBUFFER}+${mbegin[1]}-1, __end=__idx-${#PREBUFFER}+${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-${#PREBUFFER}+${mbegin[1]}-1, __end=__idx-${#PREBUFFER}+${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-${#PREBUFFER}+${mbegin[1]}-1, __end=__idx-${#PREBUFFER}+${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-${#PREBUFFER}+${mbegin[1]}-1, __end=_start_pos-${#PREBUFFER}+${mend[1]}+1-1, __start >= 0 )) && \
reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-separator]}")
fi
already_added=1
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[1] == "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[1]=""
__style=${FAST_THEME_NAME}reserved-word
(( next_word = next_word | 16 ))
elif [[ $__arg[1] = $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
else
if [[ -z "${FAST_HIGHLIGHT[no_check_paths]}" ]] && -fast-highlight-check-path; then
# ADD
(( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path]}")
already_added=1
[[ -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-${#PREBUFFER}, __start >= 0 )) && reply+=("$(( __start - 1 )) $__start ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]}")
done
}
else
__style=${FAST_THEME_NAME}default
fi
fi
;;
esac
elif (( this_word & 128 ))
then
(( next_word = 2 ))
[[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-word]} != "none" ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-word]}")
-fast-highlight-string "${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-word]:#none}"
already_added=1
fi
# ADD
(( already_added == 0 )) && [[ "${FAST_HIGHLIGHT_STYLES[$__style]}" != "none" ]] && (( __start=_start_pos-${#PREBUFFER}, __end=_end_pos-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
if (( arg_type == 3 )); then
if [[ $__arg == ';' ]] && (( in_array_assignment )); then
# literal newline inside an array assignment
(( next_word = 2 ))
elif [[ -n "${braces_stack[(r)A]}" ]]; then
(( next_word = 2 ))
else
(( next_word = 1 ))
highlight_glob=1
fi
elif (( (arg_type & 3) * (this_word & 1) )); then # (( arg_type == 1 || arg_type == 2 )) && (( this_word & 1 ))
(( next_word = 1 | (next_word & 64) ))
elif [[ $__arg == "repeat" ]] && (( this_word & 1 )); then
# 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
__inputs=( ${(0)${(S)__buf[1,110]//(#b)*\$\((?#)([^\\\"]\)|(#e))/${mbegin[1]};${match[1]}${match[2]%\)}${__nul}}%$__nul*} )
if [[ "${__inputs[1]}" != "${__buf[1,110]}" ]]; then
if [[ -n "${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}" ]]; then
__idx=1
__buf="$FAST_THEME_NAME"
FAST_THEME_NAME="${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}"
(( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source "$FAST_BASE_DIR/secondary_theme.zsh"
else
__idx=0
fi
for _mybuf in $__inputs; do
# Also replace last not-\) with not-\, because above solution
# (${match[2]%\)}) frankly doesn't always work
-fast-highlight-process "$PREBUFFER" "${${_mybuf#*;}/(#b)([^\\\"])\)(#e)/${match[1]}}" "$(( ${_mybuf%%;*} - 1 ))"
done
(( __idx )) && FAST_THEME_NAME="$__buf"
fi
return 0
}
# Check if $__arg is a path.
# If yes, return 0 and in $REPLY the __style to use.
# Else, return non-zero (and the contents of $REPLY is undefined).
-fast-highlight-check-path()
{
: ${expanded_path:=${(Q)~__arg}}
[[ -n "${FAST_BLIST_PATTERNS[(k)$expanded_path]}" ]] && return 1
[[ -z $expanded_path ]] && return 1
[[ -e $expanded_path ]] && return 0
# Search the path in CDPATH, only for CD command
[[ "$cur_cmd" = "cd" ]] && for cdpath_dir in $cdpath ; do
[[ -e "$cdpath_dir/$expanded_path" ]] && return 0
done
# It's not a path.
return 1
}
# 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()
{
_mybuf="$__arg"
__idx=_start_pos
# 7 8
while [[ "$_mybuf" = (#b)[^\$\\]#((\$(#B)([a-zA-Z_:][a-zA-Z0-9_:]#|[0-9]##)(#b)(\[[^\]]#\])(#c0,1))|(\$[{](\([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-${#PREBUFFER}, __end=_end_idx-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-or-dollar-double-quoted-argument]}${1:+,$1}")
__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)
-fast-highlight-math-string()
{
_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][1]}" = [0-9] ]] && __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}mathnum]} || {
[[ "${match[1][1]}" = [a-zA-Z] ]] && {
[[ -n "${(P)match[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][1]}" = "$" ]] && {
match[1]="${match[1]//[\{\}\+]/}"
[[ "${match[1]}" = "$" || -n "${(P)${match[1]:1}}" || ${FAST_ASSIGNS_SEEN[${match[1]:1}]} = 1 ]] && __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-or-dollar-double-quoted-argument]} || __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}matherr]}
}
}
}
# ADD
[[ "$__style" != "none" ]] && (( __start=__idx-${#PREBUFFER}, __end=_end_idx-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end $__style")
__idx=_end_idx
done
}
# Highlight special chars inside dollar-quoted strings
-fast-highlight-dollar-string()
{
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" =~ "^(x|X)[0-9a-fA-F]{1,2}"
|| "$AA" =~ "^[0-7]{1,3}"
|| "$AA" =~ "^u[0-9a-fA-F]{1,4}"
|| "$AA" =~ "^U[0-9a-fA-F]{1,8}"
]]; then
(( k += $#MATCH ))
(( i += $#MATCH ))
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-${#PREBUFFER}, __end=k-${#PREBUFFER}, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
done
}
# -------------------------------------------------------------------------------------------------
# Main highlighter initialization
# -------------------------------------------------------------------------------------------------
-fast-highlight-init() {
__fast_highlight_main__command_type_cache=()
}
# vim:ft=zsh:sw=2:sts=2
# -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-