# -*- 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