1
0

fast-highlight 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  1. # -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
  2. # -------------------------------------------------------------------------------------------------
  3. # Copyright (c) 2010-2016 zsh-syntax-highlighting contributors
  4. # Copyright (c) 2016-2019 Sebastian Gniazdowski (modifications)
  5. # All rights reserved.
  6. #
  7. # The only licensing for this file follows.
  8. #
  9. # Redistribution and use in source and binary forms, with or without modification, are permitted
  10. # provided that the following conditions are met:
  11. #
  12. # * Redistributions of source code must retain the above copyright notice, this list of conditions
  13. # and the following disclaimer.
  14. # * Redistributions in binary form must reproduce the above copyright notice, this list of
  15. # conditions and the following disclaimer in the documentation and/or other materials provided
  16. # with the distribution.
  17. # * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
  18. # may be used to endorse or promote products derived from this software without specific prior
  19. # written permission.
  20. #
  21. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  22. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  23. # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  24. # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  28. # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. # -------------------------------------------------------------------------------------------------
  30. typeset -gA __fast_highlight_main__command_type_cache FAST_BLIST_PATTERNS
  31. typeset -g FAST_WORK_DIR
  32. : ${FAST_WORK_DIR:=$FAST_BASE_DIR}
  33. FAST_WORK_DIR=${~FAST_WORK_DIR}
  34. () {
  35. # We must not use emulate -o if we want to keep compatibility with Zsh < v.5.0
  36. # See https://github.com/zdharma-continuum/fast-syntax-highlighting/pull/7
  37. emulate -L zsh
  38. setopt extendedglob
  39. local -A map
  40. map=( "XDG:" "${XDG_CONFIG_HOME:-$HOME/.config}/fsh/"
  41. "LOCAL:" "/usr/local/share/fsh/"
  42. "HOME:" "$HOME/.fsh/"
  43. "OPT:" "/opt/local/share/fsh/"
  44. )
  45. FAST_WORK_DIR=${${FAST_WORK_DIR/(#m)(#s)(XDG|LOCAL|HOME|OPT):(#c0,1)/${map[${MATCH%:}:]}}%/}
  46. }
  47. # Define default styles. You can set this after loading the plugin in
  48. # Zshrc and use 256 colors via numbers, like: fg=150
  49. typeset -gA FAST_HIGHLIGHT_STYLES
  50. if [[ -e $FAST_WORK_DIR/current_theme.zsh ]]; then
  51. source $FAST_WORK_DIR/current_theme.zsh
  52. else
  53. # built-in theme
  54. zstyle :plugin:fast-syntax-highlighting theme default
  55. : ${FAST_HIGHLIGHT_STYLES[default]:=none}
  56. : ${FAST_HIGHLIGHT_STYLES[unknown-token]:=fg=red,bold}
  57. : ${FAST_HIGHLIGHT_STYLES[reserved-word]:=fg=yellow}
  58. : ${FAST_HIGHLIGHT_STYLES[subcommand]:=fg=yellow}
  59. : ${FAST_HIGHLIGHT_STYLES[alias]:=fg=green}
  60. : ${FAST_HIGHLIGHT_STYLES[suffix-alias]:=fg=green}
  61. : ${FAST_HIGHLIGHT_STYLES[global-alias]:=bg=blue}
  62. : ${FAST_HIGHLIGHT_STYLES[builtin]:=fg=green}
  63. : ${FAST_HIGHLIGHT_STYLES[function]:=fg=green}
  64. : ${FAST_HIGHLIGHT_STYLES[command]:=fg=green}
  65. : ${FAST_HIGHLIGHT_STYLES[precommand]:=fg=green}
  66. : ${FAST_HIGHLIGHT_STYLES[commandseparator]:=none}
  67. : ${FAST_HIGHLIGHT_STYLES[hashed-command]:=fg=green}
  68. : ${FAST_HIGHLIGHT_STYLES[path]:=fg=magenta}
  69. : ${FAST_HIGHLIGHT_STYLES[path-to-dir]:=fg=magenta,underline}
  70. : ${FAST_HIGHLIGHT_STYLES[path_pathseparator]:=}
  71. : ${FAST_HIGHLIGHT_STYLES[globbing]:=fg=blue,bold}
  72. : ${FAST_HIGHLIGHT_STYLES[globbing-ext]:=fg=13}
  73. : ${FAST_HIGHLIGHT_STYLES[history-expansion]:=fg=blue,bold}
  74. : ${FAST_HIGHLIGHT_STYLES[single-hyphen-option]:=fg=cyan}
  75. : ${FAST_HIGHLIGHT_STYLES[double-hyphen-option]:=fg=cyan}
  76. : ${FAST_HIGHLIGHT_STYLES[back-quoted-argument]:=none}
  77. : ${FAST_HIGHLIGHT_STYLES[single-quoted-argument]:=fg=yellow}
  78. : ${FAST_HIGHLIGHT_STYLES[double-quoted-argument]:=fg=yellow}
  79. : ${FAST_HIGHLIGHT_STYLES[dollar-quoted-argument]:=fg=yellow}
  80. : ${FAST_HIGHLIGHT_STYLES[back-or-dollar-double-quoted-argument]:=fg=cyan}
  81. : ${FAST_HIGHLIGHT_STYLES[back-dollar-quoted-argument]:=fg=cyan}
  82. : ${FAST_HIGHLIGHT_STYLES[assign]:=none}
  83. : ${FAST_HIGHLIGHT_STYLES[redirection]:=none}
  84. : ${FAST_HIGHLIGHT_STYLES[comment]:=fg=black,bold}
  85. : ${FAST_HIGHLIGHT_STYLES[variable]:=fg=113}
  86. : ${FAST_HIGHLIGHT_STYLES[mathvar]:=fg=blue,bold}
  87. : ${FAST_HIGHLIGHT_STYLES[mathnum]:=fg=magenta}
  88. : ${FAST_HIGHLIGHT_STYLES[matherr]:=fg=red}
  89. : ${FAST_HIGHLIGHT_STYLES[assign-array-bracket]:=fg=green}
  90. : ${FAST_HIGHLIGHT_STYLES[for-loop-variable]:=none}
  91. : ${FAST_HIGHLIGHT_STYLES[for-loop-operator]:=fg=yellow}
  92. : ${FAST_HIGHLIGHT_STYLES[for-loop-number]:=fg=magenta}
  93. : ${FAST_HIGHLIGHT_STYLES[for-loop-separator]:=fg=yellow,bold}
  94. : ${FAST_HIGHLIGHT_STYLES[here-string-tri]:=fg=yellow}
  95. : ${FAST_HIGHLIGHT_STYLES[here-string-text]:=bg=18}
  96. : ${FAST_HIGHLIGHT_STYLES[here-string-var]:=fg=cyan,bg=18}
  97. : ${FAST_HIGHLIGHT_STYLES[case-input]:=fg=green}
  98. : ${FAST_HIGHLIGHT_STYLES[case-parentheses]:=fg=yellow}
  99. : ${FAST_HIGHLIGHT_STYLES[case-condition]:=bg=blue}
  100. : ${FAST_HIGHLIGHT_STYLES[paired-bracket]:=bg=blue}
  101. : ${FAST_HIGHLIGHT_STYLES[bracket-level-1]:=fg=green,bold}
  102. : ${FAST_HIGHLIGHT_STYLES[bracket-level-2]:=fg=yellow,bold}
  103. : ${FAST_HIGHLIGHT_STYLES[bracket-level-3]:=fg=cyan,bold}
  104. : ${FAST_HIGHLIGHT_STYLES[single-sq-bracket]:=fg=green}
  105. : ${FAST_HIGHLIGHT_STYLES[double-sq-bracket]:=fg=green}
  106. : ${FAST_HIGHLIGHT_STYLES[double-paren]:=fg=yellow}
  107. : ${FAST_HIGHLIGHT_STYLES[correct-subtle]:=fg=12}
  108. : ${FAST_HIGHLIGHT_STYLES[incorrect-subtle]:=fg=red}
  109. : ${FAST_HIGHLIGHT_STYLES[subtle-separator]:=fg=green}
  110. : ${FAST_HIGHLIGHT_STYLES[subtle-bg]:=bg=18}
  111. : ${FAST_HIGHLIGHT_STYLES[secondary]:=free}
  112. fi
  113. # This can overwrite some of *_STYLES fields
  114. [[ -r $FAST_WORK_DIR/theme_overlay.zsh ]] && source $FAST_WORK_DIR/theme_overlay.zsh
  115. typeset -gA __FAST_HIGHLIGHT_TOKEN_TYPES
  116. __FAST_HIGHLIGHT_TOKEN_TYPES=(
  117. # Precommand
  118. 'builtin' 1
  119. 'command' 1
  120. 'exec' 1
  121. 'nocorrect' 1
  122. 'noglob' 1
  123. 'pkexec' 1 # immune to #121 because it's usually not passed --option flags
  124. # Control flow
  125. # Tokens that, at (naively-determined) "command position", are followed by
  126. # a de jure command position. All of these are reserved words.
  127. $'\x7b' 2 # block '{'
  128. $'\x28' 2 # subshell '('
  129. '()' 2 # anonymous function
  130. 'while' 2
  131. 'until' 2
  132. 'if' 2
  133. 'then' 2
  134. 'elif' 2
  135. 'else' 2
  136. 'do' 2
  137. 'time' 2
  138. 'coproc' 2
  139. '!' 2 # reserved word; unrelated to $histchars[1]
  140. # Command separators
  141. '|' 3
  142. '||' 3
  143. ';' 3
  144. '&' 3
  145. '&&' 3
  146. '|&' 3
  147. '&!' 3
  148. '&|' 3
  149. # ### 'case' syntax, but followed by a pattern, not by a command
  150. # ';;' ';&' ';|'
  151. )
  152. # A hash instead of multiple globals
  153. typeset -gA FAST_HIGHLIGHT
  154. # Brackets highlighter active by default
  155. : ${FAST_HIGHLIGHT[use_brackets]:=1}
  156. FAST_HIGHLIGHT+=(
  157. chroma-fast-theme →chroma/-fast-theme.ch
  158. chroma-alias →chroma/-alias.ch
  159. chroma-autoload →chroma/-autoload.ch
  160. chroma-autorandr →chroma/-autorandr.ch
  161. chroma-docker →chroma/-docker.ch
  162. chroma-example →chroma/-example.ch
  163. chroma-ionice →chroma/-ionice.ch
  164. chroma-make →chroma/-make.ch
  165. chroma-nice →chroma/-nice.ch
  166. chroma-nmcli →chroma/-nmcli.ch
  167. chroma-node →chroma/-node.ch
  168. chroma-perl →chroma/-perl.ch
  169. chroma-printf →chroma/-printf.ch
  170. chroma-ruby →chroma/-ruby.ch
  171. chroma-scp →chroma/-scp.ch
  172. chroma-ssh →chroma/-ssh.ch
  173. chroma-git →chroma/main-chroma.ch%git
  174. chroma-hub →chroma/-hub.ch
  175. chroma-lab →chroma/-lab.ch
  176. chroma-svn →chroma/-subversion.ch
  177. chroma-svnadmin →chroma/-subversion.ch
  178. chroma-svndumpfilter →chroma/-subversion.ch
  179. chroma-egrep →chroma/-grep.ch
  180. chroma-fgrep →chroma/-grep.ch
  181. chroma-grep →chroma/-grep.ch
  182. chroma-awk →chroma/-awk.ch
  183. chroma-gawk →chroma/-awk.ch
  184. chroma-goawk →chroma/-awk.ch
  185. chroma-mawk →chroma/-awk.ch
  186. chroma-source →chroma/-source.ch
  187. chroma-. →chroma/-source.ch
  188. chroma-bash →chroma/-sh.ch
  189. chroma-fish →chroma/-sh.ch
  190. chroma-sh →chroma/-sh.ch
  191. chroma-zsh →chroma/-sh.ch
  192. chroma-whatis →chroma/-whatis.ch
  193. chroma-man →chroma/-whatis.ch
  194. chroma-- →chroma/-precommand.ch
  195. chroma-xargs →chroma/-precommand.ch
  196. chroma-nohup →chroma/-precommand.ch
  197. chroma-strace →chroma/-precommand.ch
  198. chroma-ltrace →chroma/-precommand.ch
  199. chroma-hg →chroma/-subcommand.ch
  200. chroma-cvs →chroma/-subcommand.ch
  201. chroma-pip →chroma/-subcommand.ch
  202. chroma-pip2 →chroma/-subcommand.ch
  203. chroma-pip3 →chroma/-subcommand.ch
  204. chroma-gem →chroma/-subcommand.ch
  205. chroma-bundle →chroma/-subcommand.ch
  206. chroma-yard →chroma/-subcommand.ch
  207. chroma-cabal →chroma/-subcommand.ch
  208. chroma-npm →chroma/-subcommand.ch
  209. chroma-nvm →chroma/-subcommand.ch
  210. chroma-yarn →chroma/-subcommand.ch
  211. chroma-brew →chroma/-subcommand.ch
  212. chroma-port →chroma/-subcommand.ch
  213. chroma-yum →chroma/-subcommand.ch
  214. chroma-dnf →chroma/-subcommand.ch
  215. chroma-tmux →chroma/-subcommand.ch
  216. chroma-pass →chroma/-subcommand.ch
  217. chroma-aws →chroma/-subcommand.ch
  218. chroma-apt →chroma/-subcommand.ch
  219. chroma-apt-get →chroma/-subcommand.ch
  220. chroma-apt-cache →chroma/-subcommand.ch
  221. chroma-aptitude →chroma/-subcommand.ch
  222. chroma-keyctl →chroma/-subcommand.ch
  223. chroma-systemctl →chroma/-subcommand.ch
  224. chroma-asciinema →chroma/-subcommand.ch
  225. chroma-ipfs →chroma/-subcommand.ch
  226. chroma-zinit →chroma/main-chroma.ch%zinit
  227. chroma-aspell →chroma/-subcommand.ch
  228. chroma-bspc →chroma/-subcommand.ch
  229. chroma-cryptsetup →chroma/-subcommand.ch
  230. chroma-diskutil →chroma/-subcommand.ch
  231. chroma-exercism →chroma/-subcommand.ch
  232. chroma-gulp →chroma/-subcommand.ch
  233. chroma-i3-msg →chroma/-subcommand.ch
  234. chroma-openssl →chroma/-subcommand.ch
  235. chroma-solargraph →chroma/-subcommand.ch
  236. chroma-subliminal →chroma/-subcommand.ch
  237. chroma-svnadmin →chroma/-subcommand.ch
  238. chroma-travis →chroma/-subcommand.ch
  239. chroma-udisksctl →chroma/-subcommand.ch
  240. chroma-xdotool →chroma/-subcommand.ch
  241. chroma-zmanage →chroma/-subcommand.ch
  242. chroma-zsystem →chroma/-subcommand.ch
  243. chroma-zypper →chroma/-subcommand.ch
  244. chroma-fpath+=\( →chroma/-fpath_peq.ch
  245. chroma-fpath=\( →chroma/-fpath_peq.ch
  246. chroma-FPATH+= →chroma/-fpath_peq.ch
  247. chroma-FPATH= →chroma/-fpath_peq.ch
  248. #chroma-which →chroma/-which.ch
  249. #chroma-vim →chroma/-vim.ch
  250. )
  251. if [[ $OSTYPE == darwin* ]] {
  252. noglob unset FAST_HIGHLIGHT[chroma-man] FAST_HIGHLIGHT[chroma-whatis]
  253. }
  254. # Assignments seen, to know if math parameter exists
  255. typeset -gA FAST_ASSIGNS_SEEN
  256. # Exposing tokens found on command position,
  257. # for other scripts to process
  258. typeset -ga ZLAST_COMMANDS
  259. # Get the type of a command.
  260. #
  261. # Uses the zsh/parameter module if available to avoid forks, and a
  262. # wrapper around 'type -w' as fallback.
  263. #
  264. # Takes a single argument.
  265. #
  266. # The result will be stored in REPLY.
  267. -fast-highlight-main-type() {
  268. REPLY=$__fast_highlight_main__command_type_cache[(e)$1]
  269. [[ -z $REPLY ]] && {
  270. if zmodload -e zsh/parameter; then
  271. if (( $+aliases[(e)$1] )); then
  272. REPLY=alias
  273. elif (( ${+galiases[(e)${(Q)1}]} )); then
  274. REPLY="global alias"
  275. elif (( $+functions[(e)$1] )); then
  276. REPLY=function
  277. elif (( $+builtins[(e)$1] )); then
  278. REPLY=builtin
  279. elif (( $+commands[(e)$1] )); then
  280. REPLY=command
  281. elif (( $+saliases[(e)${1##*.}] )); then
  282. REPLY='suffix alias'
  283. elif (( $reswords[(Ie)$1] )); then
  284. REPLY=reserved
  285. # zsh 5.2 and older have a bug whereby running 'type -w ./sudo' implicitly
  286. # runs 'hash ./sudo=/usr/local/bin/./sudo' (assuming /usr/local/bin/sudo
  287. # exists and is in $PATH). Avoid triggering the bug, at the expense of
  288. # falling through to the $() below, incurring a fork. (Issue #354.)
  289. #
  290. # The second disjunct mimics the isrelative() C call from the zsh bug.
  291. elif [[ $1 != */* || ${+ZSH_ARGZERO} = "1" ]] && ! builtin type -w -- $1 >/dev/null 2>&1; then
  292. REPLY=none
  293. fi
  294. fi
  295. [[ -z $REPLY ]] && REPLY="${$(LC_ALL=C builtin type -w -- $1 2>/dev/null)##*: }"
  296. [[ $REPLY = "none" ]] && {
  297. [[ -n ${FAST_BLIST_PATTERNS[(k)${${(M)1:#/*}:-$PWD/$1}]} ]] || {
  298. [[ -d $1 ]] && REPLY="dirpath" || {
  299. for cdpath_dir in $cdpath; do
  300. [[ -d $cdpath_dir/$1 ]] && { REPLY="dirpath"; break; }
  301. done
  302. }
  303. }
  304. }
  305. __fast_highlight_main__command_type_cache[(e)$1]=$REPLY
  306. }
  307. }
  308. # Below are variables that must be defined in outer
  309. # scope so that they are reachable in *-process()
  310. -fast-highlight-fill-option-variables() {
  311. if [[ -o ignore_braces ]] || eval '[[ -o ignore_close_braces ]] 2>/dev/null'; then
  312. FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]=0
  313. else
  314. FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]=1
  315. fi
  316. if [[ -o path_dirs ]]; then
  317. FAST_HIGHLIGHT[path_dirs_was_set]=1
  318. else
  319. FAST_HIGHLIGHT[path_dirs_was_set]=0
  320. fi
  321. if [[ -o multi_func_def ]]; then
  322. FAST_HIGHLIGHT[multi_func_def]=1
  323. else
  324. FAST_HIGHLIGHT[multi_func_def]=0
  325. fi
  326. if [[ -o interactive_comments ]]; then
  327. FAST_HIGHLIGHT[ointeractive_comments]=1
  328. else
  329. FAST_HIGHLIGHT[ointeractive_comments]=0
  330. fi
  331. }
  332. # Main syntax highlighting function.
  333. -fast-highlight-process()
  334. {
  335. emulate -L zsh
  336. setopt extendedglob bareglobqual nonomatch typesetsilent
  337. [[ $CONTEXT == "select" ]] && return 0
  338. (( FAST_HIGHLIGHT[path_dirs_was_set] )) && setopt PATH_DIRS
  339. (( FAST_HIGHLIGHT[ointeractive_comments] )) && local interactive_comments= # _set_ to empty
  340. # Variable declarations and initializations
  341. # in_array_assignment true between 'a=(' and the matching ')'
  342. # braces_stack: "R" for round, "Q" for square, "Y" for curly
  343. # _mybuf, cdpath_dir are used in sub-functions
  344. 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
  345. # __arg_type can be 0, 1, 2 or 3, i.e. precommand, control flow, command separator
  346. # __idx and _end_idx are used in sub-functions
  347. # for this_word and next_word look below at commented integers and at state machine description
  348. 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
  349. local -a match mbegin mend __inputs __list
  350. # This comment explains the numbers:
  351. # BIT_for - word after reserved-word-recognized `for'
  352. # BIT_afpcmd - word after a precommand that can take options, like `command' and `exec'
  353. # integer BIT_start=1 BIT_regular=2 BIT_sudo_opt=4 BIT_sudo_arg=8 BIT_always=16 BIT_for=32 BIT_afpcmd=64
  354. # integer BIT_chroma=8192
  355. integer BIT_case_preamble=512 BIT_case_item=1024 BIT_case_nempty_item=2048 BIT_case_code=4096
  356. # Braces stack
  357. # T - typeset, local, etc.
  358. # State machine
  359. #
  360. # The states are:
  361. # - :__start: Command word
  362. # - :sudo_opt: A leading-dash option to sudo (such as "-u" or "-i")
  363. # - :sudo_arg: The argument to a sudo leading-dash option that takes one,
  364. # when given as a separate word; i.e., "foo" in "-u foo" (two
  365. # words) but not in "-ufoo" (one word).
  366. # - :regular: "Not a command word", and command delimiters are permitted.
  367. # Mainly used to detect premature termination of commands.
  368. # - :always: The word 'always' in the «{ foo } always { bar }» syntax.
  369. #
  370. # When the kind of a word is not yet known, $this_word / $next_word may contain
  371. # multiple states. For example, after "sudo -i", the next word may be either
  372. # another --flag or a command name, hence the state would include both :__start:
  373. # and :sudo_opt:.
  374. #
  375. # The tokens are always added with both leading and trailing colons to serve as
  376. # word delimiters (an improvised array); [[ $x == *:foo:* ]] and x=${x//:foo:/}
  377. # will DTRT regardless of how many elements or repetitions $x has..
  378. #
  379. # Handling of redirections: upon seeing a redirection token, we must stall
  380. # the current state --- that is, the value of $this_word --- for two iterations
  381. # (one for the redirection operator, one for the word following it representing
  382. # the redirection target). Therefore, we set $in_redirection to 2 upon seeing a
  383. # redirection operator, decrement it each iteration, and stall the current state
  384. # when it is non-zero. Thus, upon reaching the next word (the one that follows
  385. # the redirection operator and target), $this_word will still contain values
  386. # appropriate for the word immediately following the word that preceded the
  387. # redirection operator.
  388. #
  389. # The "the previous word was a redirection operator" state is not communicated
  390. # to the next iteration via $next_word/$this_word as usual, but via
  391. # $in_redirection. The value of $next_word from the iteration that processed
  392. # the operator is discarded.
  393. #
  394. # Command exposure for other scripts
  395. ZLAST_COMMANDS=()
  396. # Restart observing of assigns
  397. FAST_ASSIGNS_SEEN=()
  398. # Restart function's gathering
  399. FAST_HIGHLIGHT[chroma-autoload-elements]=""
  400. # Restart FPATH elements gathering
  401. FAST_HIGHLIGHT[chroma-fpath_peq-elements]=""
  402. # Restart svn zinit's ICE gathering
  403. FAST_HIGHLIGHT[chroma-zinit-ice-elements-svn]=0
  404. FAST_HIGHLIGHT[chroma-zinit-ice-elements-id-as]=""
  405. [[ -n $ZCALC_ACTIVE ]] && {
  406. _start_pos=0; _end_pos=__len; __arg=$__buf
  407. -fast-highlight-math-string
  408. return 0
  409. }
  410. # Processing buffer
  411. local proc_buf=$__buf needle
  412. for __arg in ${interactive_comments-${(z)__buf}} \
  413. ${interactive_comments+${(zZ+c+)__buf}}; do
  414. # Initialize $next_word to its default value?
  415. (( in_redirection = in_redirection > 0 ? in_redirection - 1 : in_redirection ));
  416. (( next_word = (in_redirection == 0) ? 2 : next_word )) # else Stall $next_word.
  417. (( next_word = next_word | (this_word & (BIT_case_code|8192)) ))
  418. # If we have a good delimiting construct just ending, and '{'
  419. # occurs, then respect this and go for alternate syntax, i.e.
  420. # treat '{' (\x7b) as if it's on command position
  421. [[ $__arg = '{' && $__delimited = 2 ]] && { (( this_word = (this_word & ~2) | 1 )); __delimited=0; }
  422. __asize=${#__arg}
  423. # Reset state of working variables
  424. already_added=0
  425. __style=${FAST_THEME_NAME}unknown-token
  426. (( this_word & 1 )) && { in_array_assignment=0; [[ $__arg == 'noglob' ]] && highlight_glob=0; }
  427. # Compute the new $_start_pos and $_end_pos, skipping over whitespace in $__buf.
  428. if [[ $__arg == ';' ]] ; then
  429. braces_stack=${braces_stack#T}
  430. __delimited=0
  431. # Both ; and \n are rendered as a ";" (SEPER) by the ${(z)..} flag.
  432. needle=$';\n'
  433. [[ $proc_buf = (#b)[^$needle]#([$needle]##)* ]] && offset=${mbegin[1]}-1
  434. (( _start_pos += offset ))
  435. (( _end_pos = _start_pos + __asize ))
  436. # Prepare next loop cycle
  437. (( 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; }; }
  438. in_redirection=0
  439. # Chance to highlight ';'
  440. [[ ${proc_buf[offset+1]} != $'\n' ]] && {
  441. [[ ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}commandseparator]} != "none" ]] && \
  442. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  443. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}commandseparator]}")
  444. }
  445. proc_buf=${proc_buf[offset + __asize + 1,__len]}
  446. _start_pos=$_end_pos
  447. continue
  448. else
  449. offset=0
  450. if [[ $proc_buf = (#b)(#s)(([[:space:]]|\\[[:space:]])##)* ]]; then
  451. # The first, outer parenthesis
  452. offset=${mend[1]}
  453. fi
  454. (( _start_pos += offset ))
  455. (( _end_pos = _start_pos + __asize ))
  456. # No-hit will result in value 0
  457. __arg_type=${__FAST_HIGHLIGHT_TOKEN_TYPES[$__arg]}
  458. fi
  459. (( this_word & 1 )) && ZLAST_COMMANDS+=( $__arg );
  460. proc_buf=${proc_buf[offset + __asize + 1,__len]}
  461. # Handle the INTERACTIVE_COMMENTS option.
  462. #
  463. # We use the (Z+c+) flag so the entire comment is presented as one token in $__arg.
  464. if [[ -n ${interactive_comments+'set'} && $__arg == ${histchars[3]}* ]]; then
  465. if (( this_word & 3 )); then
  466. __style=${FAST_THEME_NAME}comment
  467. else
  468. __style=${FAST_THEME_NAME}unknown-token # prematurely terminated
  469. fi
  470. # ADD
  471. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  472. _start_pos=$_end_pos
  473. continue
  474. fi
  475. # Redirection?
  476. [[ $__arg == (<0-9>|)(\<|\>)* && $__arg != (\<|\>)$'\x28'* && $__arg != "<<<" ]] && \
  477. in_redirection=2
  478. # Special-case the first word after 'sudo'.
  479. if (( ! in_redirection )); then
  480. (( this_word & 4 )) && [[ $__arg != -* ]] && (( this_word = this_word ^ 4 ))
  481. # Parse the sudo command line
  482. if (( this_word & 4 )); then
  483. case $__arg in
  484. # Flag that requires an argument
  485. '-'[Cgprtu])
  486. (( this_word = this_word & ~1 ))
  487. (( next_word = 8 | (this_word & BIT_case_code) ))
  488. ;;
  489. # This prevents misbehavior with sudo -u -otherargument
  490. '-'*)
  491. (( this_word = this_word & ~1 ))
  492. (( next_word = next_word | 1 | 4 ))
  493. ;;
  494. esac
  495. elif (( this_word & 8 )); then
  496. (( next_word = next_word | 4 | 1 ))
  497. elif (( this_word & 64 )); then
  498. [[ $__arg = -[pvV-]## && $active_command = "command" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
  499. [[ $__arg = -[cla-]## && $active_command = "exec" ]] && (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
  500. [[ $__arg = \{[a-zA-Z_][a-zA-Z0-9_]#\} && $active_command = "exec" ]] && {
  501. # Highlight {descriptor} passed to exec
  502. (( this_word = (this_word & ~1) | 2, next_word = (next_word | 65) & ~2 ))
  503. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}exec-descriptor]}")
  504. already_added=1
  505. }
  506. fi
  507. fi
  508. (( this_word & 8192 )) && {
  509. __list=( ${(z@)${aliases[$active_command]:-${active_command##*/}}##[[:space:]]#(command|builtin|exec|noglob|nocorrect|pkexec)[[:space:]]#} )
  510. ${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 0 "$__arg" $_start_pos $_end_pos 2>/dev/null && continue
  511. }
  512. (( this_word & 1 )) && {
  513. # !in_redirection needed particularly for exec {A}>b {C}>d
  514. (( !in_redirection )) && active_command=$__arg
  515. _mybuf=${${aliases[$active_command]:-${active_command##*/}}##[[:space:]]#(command|builtin|exec|noglob|nocorrect|pkexec)[[:space:]]#}
  516. [[ "$_mybuf" = (#b)(FPATH+(#c0,1)=)* ]] && _mybuf="${match[1]} ${(j: :)${(s,:,)${_mybuf#FPATH+(#c0,1)=}}}"
  517. [[ -n ${FAST_HIGHLIGHT[chroma-${_mybuf%% *}]} ]] && {
  518. __list=( ${(z@)_mybuf} )
  519. if (( ${#__list} > 1 )) || [[ $active_command != $_mybuf ]]; then
  520. __style=${FAST_THEME_NAME}alias
  521. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  522. ${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 1 "${__list[1]}" "-100000" $_end_pos 2>/dev/null || \
  523. (( this_word = next_word, next_word = 2 ))
  524. for _mybuf in "${(@)__list[2,-1]}"; do
  525. (( next_word = next_word | (this_word & (BIT_case_code|8192)) ))
  526. ${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 0 "$_mybuf" "-100000" $_end_pos 2>/dev/null || \
  527. (( this_word = next_word, next_word = 2 ))
  528. done
  529. # This might have been done multiple times in chroma, but
  530. # as _end_pos doesn't change, it can be done one more time
  531. _start_pos=$_end_pos
  532. continue
  533. else
  534. ${${FAST_HIGHLIGHT[chroma-${__list[1]}]}%\%*} ${(M)FAST_HIGHLIGHT[chroma-${__list[1]}]%\%*} 1 "$__arg" $_start_pos $_end_pos 2>/dev/null && continue
  535. fi
  536. } || (( 1 ))
  537. }
  538. expanded_path=""
  539. # The Great Fork: is this a command word? Is this a non-command word?
  540. if (( this_word & 16 )) && [[ $__arg == 'always' ]]; then
  541. # try-always construct
  542. __style=${FAST_THEME_NAME}reserved-word # de facto a reserved word, although not de jure
  543. (( next_word = 1 | (this_word & BIT_case_code) ))
  544. elif (( (this_word & 1) && (in_redirection == 0) )) || [[ $braces_stack = T* ]]; then # T - typedef, etc.
  545. if (( __arg_type == 1 )); then
  546. __style=${FAST_THEME_NAME}precommand
  547. [[ $__arg = "command" || $__arg = "exec" ]] && (( next_word = next_word | 64 ))
  548. elif [[ $__arg = (sudo|doas) ]]; then
  549. __style=${FAST_THEME_NAME}precommand
  550. (( next_word = (next_word & ~2) | 4 | 1 ))
  551. else
  552. _mybuf=${${(Q)__arg}#\"}
  553. if (( ${+parameters} )) && \
  554. [[ $_mybuf = (#b)(*)(*)\$([a-zA-Z_][a-zA-Z0-9_]#|[0-9]##)(*) || \
  555. $_mybuf = (#b)(*)(*)\$\{([a-zA-Z_][a-zA-Z0-9_:-]#|[0-9]##)(*) ]] && \
  556. (( ${+parameters[${match[3]%%:-*}]} ))
  557. then
  558. -fast-highlight-main-type ${match[1]}${match[2]}${(P)match[3]%%:-*}${match[4]#\}}
  559. elif [[ $braces_stack = T* ]]; then # T - typedef, etc.
  560. REPLY=none
  561. else
  562. : ${expanded_path::=${~_mybuf}}
  563. -fast-highlight-main-type $expanded_path
  564. fi
  565. case $REPLY in
  566. reserved) # reserved word
  567. [[ $__arg = "[[" ]] && __style=${FAST_THEME_NAME}double-sq-bracket || __style=${FAST_THEME_NAME}reserved-word
  568. if [[ $__arg == $'\x7b' ]]; then # Y - '{'
  569. braces_stack='Y'$braces_stack
  570. elif [[ $__arg == $'\x7d' && $braces_stack = Y* ]]; then # Y - '}'
  571. # We're at command word, so no need to check right_brace_is_recognised_everywhere
  572. braces_stack=${braces_stack#Y}
  573. __style=${FAST_THEME_NAME}reserved-word
  574. (( next_word = next_word | 16 ))
  575. elif [[ $__arg == "[[" ]]; then # A - [[
  576. braces_stack='A'$braces_stack
  577. # Counting complex brackets (for brackets-highlighter): 1. [[ as command
  578. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
  579. elif [[ $__arg == "for" ]]; then
  580. (( next_word = next_word | 32 )) # BIT_for
  581. elif [[ $__arg == "case" ]]; then
  582. (( next_word = BIT_case_preamble ))
  583. elif [[ $__arg = (typeset|declare|local|float|integer|export|readonly) ]]; then
  584. braces_stack='T'$braces_stack
  585. fi
  586. ;;
  587. 'suffix alias') __style=${FAST_THEME_NAME}suffix-alias;;
  588. 'global alias') __style=${FAST_THEME_NAME}global-alias;;
  589. alias)
  590. if [[ $__arg = ?*'='* ]]; then
  591. # The so called (by old code) "insane_alias"
  592. __style=${FAST_THEME_NAME}unknown-token
  593. else
  594. __style=${FAST_THEME_NAME}alias
  595. (( ${+aliases} )) && alias_target=${aliases[$__arg]} || alias_target="${"$(alias -- $__arg)"#*=}"
  596. [[ ${__FAST_HIGHLIGHT_TOKEN_TYPES[$alias_target]} = "1" && $__arg_type != "1" ]] && __FAST_HIGHLIGHT_TOKEN_TYPES[$__arg]="1"
  597. fi
  598. ;;
  599. builtin) [[ $__arg = "[" ]] && {
  600. __style=${FAST_THEME_NAME}single-sq-bracket
  601. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
  602. } || __style=${FAST_THEME_NAME}builtin
  603. # T - typeset, etc. mode
  604. [[ $__arg = (typeset|declare|local|float|integer|export|readonly) ]] && braces_stack='T'$braces_stack
  605. [[ $__arg = eval ]] && (( next_word = next_word | 256 ))
  606. ;;
  607. function) __style=${FAST_THEME_NAME}function;;
  608. command) __style=${FAST_THEME_NAME}command;;
  609. hashed) __style=${FAST_THEME_NAME}hashed-command;;
  610. dirpath) __style=${FAST_THEME_NAME}path-to-dir;;
  611. none) # Assign?
  612. if [[ $__arg == [a-zA-Z_][a-zA-Z0-9_]#(|\[[^\]]#\])(|[^\]]#\])(|[+])=* || $__arg == [0-9]##(|[+])=* || ( $braces_stack = T* && ${__arg_type} != 3 ) ]] {
  613. __style=${FAST_THEME_NAME}assign
  614. FAST_ASSIGNS_SEEN[${__arg%%=*}]=1
  615. # Handle array assignment
  616. [[ $__arg = (#b)*=(\()*(\))* || $__arg = (#b)*=(\()* ]] && {
  617. (( __start=_start_pos-__PBUFLEN+${mbegin[1]}-1, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
  618. # Counting complex brackets (for brackets-highlighter): 2. ( in array assign
  619. _FAST_COMPLEX_BRACKETS+=( $__start )
  620. (( mbegin[2] >= 1 )) && {
  621. (( __start=_start_pos-__PBUFLEN+${mbegin[2]}-1, __end=__start+1, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
  622. # Counting complex brackets (for brackets-highlighter): 3a. ) in array assign
  623. _FAST_COMPLEX_BRACKETS+=( $__start )
  624. } || in_array_assignment=1
  625. } || { [[ ${braces_stack[1]} != 'T' ]] && (( next_word = (next_word | 1) & ~2 )); }
  626. # Handle no-string highlight, string "/' highlight, math mode highlight
  627. local ctmp="\"" dtmp="'"
  628. itmp=${__arg[(i)$ctmp]}-1 iitmp=${__arg[(i)$dtmp]}-1
  629. integer jtmp=${__arg[(b:itmp+2:i)$ctmp]} jjtmp=${__arg[(b:iitmp+2:i)$dtmp]}
  630. (( itmp < iitmp && itmp <= __asize - 1 )) && (( jtmp > __asize && (jtmp = __asize), 1 > 0 )) && \
  631. (( __start=_start_pos-__PBUFLEN+itmp, __end=_start_pos-__PBUFLEN+jtmp, __start >= 0 )) && \
  632. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-quoted-argument]}") && \
  633. { itmp=${__arg[(i)=]}; __arg=${__arg[itmp,__asize]}; (( _start_pos += itmp - 1 ));
  634. -fast-highlight-string; (( _start_pos = _start_pos - itmp + 1, 1 > 0 )); } || \
  635. {
  636. (( iitmp <= __asize - 1 )) && (( jjtmp > __asize && (jjtmp = __asize), 1 > 0 )) && \
  637. (( __start=_start_pos-__PBUFLEN+iitmp, __end=_start_pos-__PBUFLEN+jjtmp, __start >= 0 )) && \
  638. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}single-quoted-argument]}")
  639. } || \
  640. {
  641. itmp=${__arg[(i)=]}; __arg=${__arg[itmp,__asize]}; (( _start_pos += itmp - 1 ));
  642. [[ ${__arg[2,4]} = '$((' ]] && { -fast-highlight-math-string;
  643. (( __start=_start_pos-__PBUFLEN+2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  644. # Counting complex brackets (for brackets-highlighter): 4. $(( in assign argument
  645. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  646. (( jtmp = ${__arg[(I)\)\)]}-1, jtmp > 0 )) && {
  647. (( __start=_start_pos-__PBUFLEN+jtmp, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  648. # Counting complex brackets (for brackets-highlighter): 5. )) in assign argument
  649. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  650. }
  651. } || -fast-highlight-string;
  652. (( _start_pos = _start_pos - itmp + 1, 1 > 0 ))
  653. }
  654. } elif [[ $__arg = ${histchars[1]}* && -n ${__arg[2]} ]] {
  655. __style=${FAST_THEME_NAME}history-expansion
  656. } elif [[ $__arg == ${histchars[2]}* ]] {
  657. __style=${FAST_THEME_NAME}history-expansion
  658. } elif (( __arg_type == 3 )) {
  659. # This highlights empty commands (semicolon follows nothing) as an error.
  660. # Zsh accepts them, though.
  661. (( this_word & 3 )) && __style=${FAST_THEME_NAME}commandseparator
  662. } elif [[ $__arg[1,2] == '((' ]] {
  663. # Arithmetic evaluation.
  664. #
  665. # Note: prior to zsh-5.1.1-52-g4bed2cf (workers/36669), the ${(z)...}
  666. # splitter would only output the '((' token if the matching '))' had
  667. # been typed. Therefore, under those versions of zsh, BUFFER="(( 42"
  668. # would be highlighted as an error until the matching "))" are typed.
  669. #
  670. # We highlight just the opening parentheses, as a reserved word; this
  671. # is how [[ ... ]] is highlighted, too.
  672. # ADD
  673. (( __start=_start_pos-__PBUFLEN, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  674. already_added=1
  675. # Counting complex brackets (for brackets-highlighter): 6. (( as command
  676. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  677. -fast-highlight-math-string
  678. # ADD
  679. [[ $__arg[-2,-1] == '))' ]] && {
  680. (( __start=_end_pos-__PBUFLEN-2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  681. (( __delimited = __delimited ? 2 : __delimited ))
  682. # Counting complex brackets (for brackets-highlighter): 7. )) for as-command ((
  683. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  684. }
  685. } elif [[ $__arg == '()' ]] {
  686. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
  687. # anonymous function
  688. __style=${FAST_THEME_NAME}reserved-word
  689. } elif [[ $__arg == $'\x28' ]] {
  690. # subshell '(', stack: letter 'R'
  691. __style=${FAST_THEME_NAME}reserved-word
  692. braces_stack='R'$braces_stack
  693. } elif [[ $__arg == $'\x29' ]] {
  694. # ')', stack: letter 'R' for subshell
  695. [[ $braces_stack = R* ]] && { braces_stack=${braces_stack#R}; __style=${FAST_THEME_NAME}reserved-word; }
  696. } elif (( this_word & 14 )) {
  697. __style=${FAST_THEME_NAME}default
  698. } elif [[ $__arg = (';;'|';&'|';|') ]] && (( this_word & BIT_case_code )) {
  699. (( next_word = (next_word | BIT_case_item) & ~(BIT_case_code+3) ))
  700. __style=${FAST_THEME_NAME}default
  701. } elif [[ $__arg = \$\([^\(]* ]] {
  702. already_added=1
  703. }
  704. ;;
  705. *)
  706. # ADD
  707. # (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end commandtypefromthefuture-$REPLY")
  708. already_added=1
  709. ;;
  710. esac
  711. fi
  712. # in_redirection || BIT_regular || BIT_sudo_opt || BIT_sudo_arg
  713. elif (( in_redirection + this_word & 14 ))
  714. then # $__arg is a non-command word
  715. case $__arg in
  716. ']]')
  717. # A - [[
  718. [[ $braces_stack = A* ]] && {
  719. __style=${FAST_THEME_NAME}double-sq-bracket
  720. (( __delimited = __delimited ? 2 : __delimited ))
  721. # Counting complex brackets (for brackets-highlighter): 8a. ]] for as-command [[
  722. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
  723. } || {
  724. [[ $braces_stack = *A* ]] && {
  725. __style=${FAST_THEME_NAME}unknown-token
  726. # Counting complex brackets (for brackets-highlighter): 8b. ]] for as-command [[
  727. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
  728. } || __style=${FAST_THEME_NAME}default
  729. }
  730. braces_stack=${braces_stack#A}
  731. ;;
  732. ']')
  733. __style=${FAST_THEME_NAME}single-sq-bracket
  734. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
  735. ;;
  736. $'\x28')
  737. # '(' inside [[
  738. __style=${FAST_THEME_NAME}reserved-word
  739. braces_stack='R'$braces_stack
  740. ;;
  741. $'\x29') # ')' - subshell or end of array assignment
  742. if (( in_array_assignment )); then
  743. in_array_assignment=0
  744. (( next_word = next_word | 1 ))
  745. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}assign-array-bracket]}")
  746. already_added=1
  747. # Counting complex brackets (for brackets-highlighter): 3b. ) in array assign
  748. _FAST_COMPLEX_BRACKETS+=( $__start )
  749. elif [[ $braces_stack = R* ]]; then
  750. braces_stack=${braces_stack#R}
  751. __style=${FAST_THEME_NAME}reserved-word
  752. # Zsh doesn't tokenize final ) if it's just single ')',
  753. # but logically what's below is correct, so it is kept
  754. # in case Zsh will be changed / fixed, etc.
  755. elif [[ $braces_stack = F* ]]; then
  756. __style=${FAST_THEME_NAME}builtin
  757. fi
  758. ;;
  759. $'\x28\x29') # '()' - possibly a function definition
  760. # || false # TODO: or if the previous word was a command word
  761. (( FAST_HIGHLIGHT[multi_func_def] )) && (( next_word = next_word | 1 ))
  762. __style=${FAST_THEME_NAME}reserved-word
  763. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN + 1 )) )
  764. # Remove possible annoying unknown-token __style, or misleading function __style
  765. reply[-1]=()
  766. __fast_highlight_main__command_type_cache[$active_command]="function"
  767. ;;
  768. '--'*) [[ $__arg == "--" ]] && { _was_double_hyphen=1; __style=${FAST_THEME_NAME}double-hyphen-option; } || {
  769. (( !_was_double_hyphen )) && {
  770. [[ "$__arg" = (#b)(--[a-zA-Z0-9_]##)=(*) ]] && {
  771. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  772. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-hyphen-option]}")
  773. (( __start=_start_pos-__PBUFLEN+1+mend[1], __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  774. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}optarg-${${${(M)match[2]:#<->}:+number}:-string}]}")
  775. already_added=1
  776. } || __style=${FAST_THEME_NAME}double-hyphen-option
  777. } || __style=${FAST_THEME_NAME}default
  778. }
  779. ;;
  780. '-'*) (( !_was_double_hyphen )) && __style=${FAST_THEME_NAME}single-hyphen-option || __style=${FAST_THEME_NAME}default;;
  781. \$\'*)
  782. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}dollar-quoted-argument]}")
  783. -fast-highlight-dollar-string
  784. already_added=1
  785. ;;
  786. [\"\']*|[^\"\\]##([\\][\\])#\"*|[^\'\\]##([\\][\\])#\'*)
  787. # 256 is eval-mode
  788. if (( this_word & 256 )) && [[ $__arg = [\'\"]* ]]; then
  789. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  790. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}recursive-base]}")
  791. if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
  792. __idx=1
  793. _mybuf=$FAST_THEME_NAME
  794. FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
  795. (( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
  796. else
  797. __idx=0
  798. fi
  799. (( _start_pos-__PBUFLEN >= 0 )) && \
  800. -fast-highlight-process "$PREBUFFER" "${${__arg%[\'\"]}#[\'\"]}" $(( _start_pos + 1 ))
  801. (( __idx )) && FAST_THEME_NAME=$_mybuf
  802. already_added=1
  803. else
  804. [[ $__arg = *([^\\][\#][\#]|"(#b)"|"(#B)"|"(#m)"|"(#c")* && $highlight_glob -ne 0 ]] && \
  805. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  806. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}globbing-ext]}")
  807. # Reusing existing vars, treat this code like C++ STL
  808. # header, full of underscores and unhelpful var names
  809. itmp=0 __workbuf=$__arg __tmp="" cdpath_dir=$__arg
  810. while [[ $__workbuf = (#b)[^\"\'\\]#(([\"\'])|[\\](*))(*) ]]; do
  811. [[ -n ${match[3]} ]] && {
  812. itmp+=${mbegin[1]}
  813. # Optionally skip 1 quoted char
  814. [[ $__tmp = \' ]] && __workbuf=${match[3]} || { itmp+=1; __workbuf=${match[3]:1}; }
  815. } || {
  816. itmp+=${mbegin[1]}
  817. __workbuf=${match[4]}
  818. # Toggle quoting
  819. [[ ( ${match[1]} = \" && $__tmp != \' ) || ( ${match[1]} = \' && $__tmp != \" ) ]] && {
  820. [[ $__tmp = [\"\'] ]] && {
  821. # End of quoting
  822. (( __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}]}")
  823. already_added=1
  824. [[ $__tmp = \" ]] && {
  825. __arg=${cdpath_dir[iitmp+1,itmp-1]}
  826. (( _start_pos += iitmp - 1 + 1 ))
  827. -fast-highlight-string
  828. (( _start_pos = _start_pos - iitmp + 1 - 1 ))
  829. }
  830. # The end-of-quoting proper algorithm action
  831. __tmp=
  832. } || {
  833. # Beginning of quoting
  834. iitmp=itmp
  835. # The beginning-of-quoting proper algorithm action
  836. __tmp=${match[1]}
  837. }
  838. }
  839. }
  840. done
  841. [[ $__tmp = [\"\'] ]] && {
  842. (( __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}]}")
  843. already_added=1
  844. [[ $__tmp = \" ]] && {
  845. __arg=${cdpath_dir[iitmp+1,__asize]}
  846. (( _start_pos += iitmp - 1 + 1 ))
  847. -fast-highlight-string
  848. (( _start_pos = _start_pos - iitmp + 1 - 1 ))
  849. }
  850. }
  851. fi
  852. ;;
  853. \$\(\(*)
  854. already_added=1
  855. -fast-highlight-math-string
  856. # ADD
  857. (( __start=_start_pos-__PBUFLEN+1, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  858. # Counting complex brackets (for brackets-highlighter): 9. $(( as argument
  859. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  860. # ADD
  861. [[ $__arg[-2,-1] == '))' ]] && (( __start=_end_pos-__PBUFLEN-2, __end=__start+2, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}double-paren]}")
  862. # Counting complex brackets (for brackets-highlighter): 10. )) for as-argument $((
  863. _FAST_COMPLEX_BRACKETS+=( $__start $(( __start + 1 )) )
  864. ;;
  865. '`'*)
  866. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  867. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-quoted-argument]}")
  868. if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
  869. __idx=1
  870. _mybuf=$FAST_THEME_NAME
  871. FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
  872. (( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
  873. else
  874. __idx=0
  875. fi
  876. (( _start_pos-__PBUFLEN >= 0 )) && \
  877. -fast-highlight-process "$PREBUFFER" "${${__arg%[\`]}#[\`]}" $(( _start_pos + 1 ))
  878. (( __idx )) && FAST_THEME_NAME=$_mybuf
  879. already_added=1
  880. ;;
  881. '((') # 'F' - (( after for
  882. (( this_word & 32 )) && {
  883. braces_stack='F'$braces_stack
  884. __style=${FAST_THEME_NAME}double-paren
  885. # Counting complex brackets (for brackets-highlighter): 11. (( as for-syntax
  886. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
  887. # This is set after __arg_type == 2, and also here,
  888. # when another alternate-syntax capable command occurs
  889. __delimited=1
  890. }
  891. ;;
  892. '))') # 'F' - (( after for
  893. [[ $braces_stack = F* ]] && {
  894. braces_stack=${braces_stack#F}
  895. __style=${FAST_THEME_NAME}double-paren
  896. # Counting complex brackets (for brackets-highlighter): 12. )) as for-syntax
  897. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) $(( _start_pos-__PBUFLEN+1 )) )
  898. (( __delimited = __delimited ? 2 : __delimited ))
  899. }
  900. ;;
  901. '<<<')
  902. (( next_word = (next_word | 128) & ~3 ))
  903. [[ ${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]}")
  904. already_added=1
  905. ;;
  906. *) # F - (( after for
  907. if [[ $braces_stack = F* ]]; then
  908. -fast-highlight-string
  909. _mybuf=$__arg
  910. __idx=_start_pos
  911. while [[ $_mybuf = (#b)[^a-zA-Z\{\$]#([a-zA-Z][a-zA-Z0-9]#)(*) ]]; do
  912. (( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
  913. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-variable]}")
  914. __idx+=${mend[1]}
  915. _mybuf=${match[2]}
  916. done
  917. _mybuf=$__arg
  918. __idx=_start_pos
  919. while [[ $_mybuf = (#b)[^+\<\>=:\*\|\&\^\~-]#([+\<\>=:\*\|\&\^\~-]##)(*) ]]; do
  920. (( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
  921. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-operator]}")
  922. __idx+=${mend[1]}
  923. _mybuf=${match[2]}
  924. done
  925. _mybuf=$__arg
  926. __idx=_start_pos
  927. while [[ $_mybuf = (#b)[^0-9]#([0-9]##)(*) ]]; do
  928. (( __start=__idx-__PBUFLEN+${mbegin[1]}-1, __end=__idx-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
  929. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-number]}")
  930. __idx+=${mend[1]}
  931. _mybuf=${match[2]}
  932. done
  933. if [[ $__arg = (#b)[^\;]#(\;)[\ ]# ]]; then
  934. (( __start=_start_pos-__PBUFLEN+${mbegin[1]}-1, __end=_start_pos-__PBUFLEN+${mend[1]}+1-1, __start >= 0 )) && \
  935. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}for-loop-separator]}")
  936. fi
  937. already_added=1
  938. elif [[ $__arg = *([^\\][\#][\#]|"(#b)"|"(#B)"|"(#m)"|"(#c")* ]]; then
  939. (( highlight_glob )) && __style=${FAST_THEME_NAME}globbing-ext || __style=${FAST_THEME_NAME}default
  940. elif [[ $__arg = ([*?]*|*[^\\][*?]*) ]]; then
  941. (( highlight_glob )) && __style=${FAST_THEME_NAME}globbing || __style=${FAST_THEME_NAME}default
  942. elif [[ $__arg = \$* ]]; then
  943. __style=${FAST_THEME_NAME}variable
  944. elif [[ $__arg = $'\x7d' && $braces_stack = Y* && ${FAST_HIGHLIGHT[right_brace_is_recognised_everywhere]} = "1" ]]; then
  945. # right brace, i.e. $'\x7d' == '}'
  946. # Parsing rule: # {
  947. #
  948. # Additionally, `tt(})' is recognized in any position if neither the
  949. # tt(IGNORE_BRACES) option nor the tt(IGNORE_CLOSE_BRACES) option is set."""
  950. braces_stack=${braces_stack#Y}
  951. __style=${FAST_THEME_NAME}reserved-word
  952. (( next_word = next_word | 16 ))
  953. elif [[ $__arg = (';;'|';&'|';|') ]] && (( this_word & BIT_case_code )); then
  954. (( next_word = (next_word | BIT_case_item) & ~(BIT_case_code+3) ))
  955. __style=${FAST_THEME_NAME}default
  956. elif [[ $__arg = ${histchars[1]}* && -n ${__arg[2]} ]]; then
  957. __style=${FAST_THEME_NAME}history-expansion
  958. elif (( __arg_type == 3 )); then
  959. __style=${FAST_THEME_NAME}commandseparator
  960. elif (( in_redirection == 2 )); then
  961. __style=${FAST_THEME_NAME}redirection
  962. elif (( ${+galiases[(e)${(Q)__arg}]} )); then
  963. __style=${FAST_THEME_NAME}global-alias
  964. else
  965. if [[ ${FAST_HIGHLIGHT[no_check_paths]} != 1 ]]; then
  966. if [[ ${FAST_HIGHLIGHT[use_async]} != 1 ]]; then
  967. if -fast-highlight-check-path noasync; then
  968. # ADD
  969. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  970. already_added=1
  971. # TODO: path separators, optimize and add to async code-path
  972. [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]} && ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path]} != ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]} ]] && {
  973. for (( __pos = _start_pos; __pos <= _end_pos; __pos++ )) ; do
  974. # ADD
  975. [[ ${__buf[__pos]} == "/" ]] && (( __start=__pos-__PBUFLEN, __start >= 0 )) && reply+=("$(( __start - 1 )) $__start ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path_pathseparator]}")
  976. done
  977. }
  978. else
  979. __style=${FAST_THEME_NAME}default
  980. fi
  981. else
  982. if [[ -z ${FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}]} || $(( EPOCHSECONDS - FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}-born-at] )) -gt 8 ]]; then
  983. if [[ $LASTWIDGET != *-or-beginning-search ]]; then
  984. exec {PCFD}< <(-fast-highlight-check-path; sleep 5)
  985. command sleep 0
  986. FAST_HIGHLIGHT[path-queue]+=";$_start_pos $_end_pos;"
  987. is-at-least 5.0.6 && __pos=1 || __pos=0
  988. zle -F ${${__pos:#0}:+-w} $PCFD fast-highlight-check-path-handler
  989. already_added=1
  990. else
  991. __style=${FAST_THEME_NAME}default
  992. fi
  993. elif [[ ${FAST_HIGHLIGHT[cache-path-${(q)__arg}-${_start_pos}]%D} -eq 1 ]]; then
  994. (( __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}]}")
  995. already_added=1
  996. else
  997. __style=${FAST_THEME_NAME}default
  998. fi
  999. fi
  1000. else
  1001. __style=${FAST_THEME_NAME}default
  1002. fi
  1003. fi
  1004. ;;
  1005. esac
  1006. elif (( this_word & 128 ))
  1007. then
  1008. (( next_word = (next_word | 2) & ~129 ))
  1009. [[ ${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]}")
  1010. -fast-highlight-string ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}here-string-var]:#none}
  1011. already_added=1
  1012. elif (( this_word & (BIT_case_preamble + BIT_case_item) ))
  1013. then
  1014. if (( this_word & BIT_case_preamble )); then
  1015. [[ $__arg = "in" ]] && {
  1016. __style=${FAST_THEME_NAME}reserved-word
  1017. (( next_word = BIT_case_item ))
  1018. } || {
  1019. __style=${FAST_THEME_NAME}case-input
  1020. (( next_word = BIT_case_preamble ))
  1021. }
  1022. else
  1023. if (( this_word & BIT_case_nempty_item == 0 )) && [[ $__arg = "esac" ]]; then
  1024. (( next_word = 1 ))
  1025. __style=${FAST_THEME_NAME}reserved-word
  1026. elif [[ $__arg = (\(*\)|\)|\() ]]; then
  1027. [[ $__arg = *\) ]] && (( next_word = BIT_case_code | 1 )) || (( next_word = BIT_case_item | BIT_case_nempty_item ))
  1028. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos-__PBUFLEN )) )
  1029. (( ${#__arg} > 1 )) && {
  1030. _FAST_COMPLEX_BRACKETS+=( $(( _start_pos+${#__arg}-1-__PBUFLEN )) )
  1031. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && \
  1032. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}case-parentheses]}")
  1033. (( __start=_start_pos+1-__PBUFLEN, __end=_end_pos-1-__PBUFLEN, __start >= 0 )) && \
  1034. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}case-condition]}")
  1035. already_added=1
  1036. } || {
  1037. __style=${FAST_THEME_NAME}case-parentheses
  1038. }
  1039. else
  1040. (( next_word = BIT_case_item | BIT_case_nempty_item ))
  1041. __style=${FAST_THEME_NAME}case-condition
  1042. fi
  1043. fi
  1044. fi
  1045. 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]))(|[^[:alnum:]]*) || $__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
  1046. if [[ -n $match[2] ]]; then
  1047. if [[ $match[2] = ?? || $match[3] = ?? || $match[4] = ?? ]]; then
  1048. (( __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]}")
  1049. else
  1050. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end bg=#$match[2]$match[3]$match[4]")
  1051. fi
  1052. else
  1053. (( __start=_start_pos-__PBUFLEN, __end=_end_pos-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end bg=#$match[5]$match[6]$match[7]")
  1054. fi
  1055. already_added=1
  1056. fi
  1057. # ADD
  1058. (( 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]}")
  1059. if (( (__arg_type == 3) && ((this_word & (BIT_case_preamble|BIT_case_item)) == 0) )); then
  1060. if [[ $__arg == ';' ]] && (( in_array_assignment )); then
  1061. # literal newline inside an array assignment
  1062. (( next_word = 2 | (next_word & BIT_case_code) ))
  1063. elif [[ -n ${braces_stack[(r)A]} ]]; then
  1064. # 'A' in stack -> inside [[ ... ]]
  1065. (( next_word = 2 | (next_word & BIT_case_code) ))
  1066. else
  1067. braces_stack=${braces_stack#T}
  1068. (( next_word = 1 | (next_word & BIT_case_code) ))
  1069. highlight_glob=1
  1070. # A new command means that we should not expect that alternate
  1071. # syntax will occur (this is also in the ';' short-path), but
  1072. # || and && mean going down just 1 step, not all the way to 0
  1073. [[ $__arg != ("||"|"&&") ]] && __delimited=0 || (( __delimited = __delimited == 2 ? 1 : __delimited ))
  1074. fi
  1075. elif (( ( (__arg_type == 1) || (__arg_type == 2) ) && (this_word & 1) )); then # (( __arg_type == 1 || __arg_type == 2 )) && (( this_word & 1 ))
  1076. __delimited=1
  1077. (( next_word = 1 | (next_word & (64 | BIT_case_code)) ))
  1078. elif [[ $__arg == "repeat" ]] && (( this_word & 1 )); then
  1079. __delimited=1
  1080. # skip the repeat-count word
  1081. in_redirection=2
  1082. # The redirection mechanism assumes $this_word describes the word
  1083. # following the redirection. Make it so.
  1084. #
  1085. # That word can be a command word with shortloops (`repeat 2 ls`)
  1086. # or a command separator (`repeat 2; ls` or `repeat 2; do ls; done`).
  1087. #
  1088. # The repeat-count word will be handled like a redirection target.
  1089. (( this_word = 3 ))
  1090. fi
  1091. _start_pos=$_end_pos
  1092. # This is the default/common codepath.
  1093. (( this_word = in_redirection == 0 ? next_word : this_word )) #else # Stall $this_word.
  1094. done
  1095. # Do we have whole buffer? I.e. start at zero
  1096. [[ $3 != 0 ]] && return 0
  1097. # The loop overwrites ")" with "x", except those from $( ) substitution
  1098. #
  1099. # __pos: current nest level, starts from 0
  1100. # __workbuf: copy of __buf, with limit on 250 characters
  1101. # __idx: index in whole command line buffer
  1102. # __list: list of coordinates of ) which shouldn't be ovewritten
  1103. _mybuf=${__buf[1,250]} __workbuf=$_mybuf __idx=0 __pos=0 __list=()
  1104. while [[ $__workbuf = (#b)[^\(\)]#([\(\)])(*) ]]; do
  1105. if [[ ${match[1]} == \( ]]; then
  1106. __arg=${_mybuf[__idx+${mbegin[1]}-1,__idx+${mbegin[1]}-1+2]}
  1107. [[ $__arg = '$('[^\(] ]] && __list+=( $__pos )
  1108. [[ $__arg = '$((' ]] && _mybuf[__idx+${mbegin[1]}-1]=x
  1109. # Increase parenthesis level
  1110. __pos+=1
  1111. else
  1112. # Decrease parenthesis level
  1113. __pos=__pos-1
  1114. [[ -z ${__list[(r)$__pos]} ]] && [[ $__pos -gt 0 ]] && _mybuf[__idx+${mbegin[1]}]=x
  1115. fi
  1116. __idx+=${mbegin[2]}-1
  1117. __workbuf=${match[2]}
  1118. done
  1119. # Run on fake buffer with replaced parentheses: ")" into "x"
  1120. if [[ "$_mybuf" = *$__nul* ]]; then
  1121. # Try to avoid conflict with the \0, however
  1122. # we have to split at *some* character - \7
  1123. # is ^G, so one cannot have null and ^G at
  1124. # the same time on the command line
  1125. __nul=$'\7'
  1126. fi
  1127. __inputs=( ${(ps:$__nul:)${(S)_mybuf//(#b)*\$\(([^\)]#)(\)|(#e))/${mbegin[1]};${mend[1]}${__nul}}%$__nul*} )
  1128. if [[ "${__inputs[1]}" != "$_mybuf" && -n "${__inputs[1]}" ]]; then
  1129. if [[ -n ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]} ]]; then
  1130. __idx=1
  1131. __tmp=$FAST_THEME_NAME
  1132. FAST_THEME_NAME=${${${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}secondary]}:t:r}#(XDG|LOCAL|HOME|OPT):}
  1133. (( ${+FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}default]} )) || source $FAST_WORK_DIR/secondary_theme.zsh
  1134. else
  1135. __idx=0
  1136. fi
  1137. for _mybuf in $__inputs; do
  1138. (( __start=${_mybuf%%;*}-__PBUFLEN-1, __end=${_mybuf##*;}-__PBUFLEN, __start >= 0 )) && \
  1139. reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[${__tmp}recursive-base]}")
  1140. # Pass authentic buffer for recursive analysis
  1141. -fast-highlight-process "$PREBUFFER" "${__buf[${_mybuf%%;*},${_mybuf##*;}]}" $(( ${_mybuf%%;*} - 1 ))
  1142. done
  1143. # Restore theme
  1144. (( __idx )) && FAST_THEME_NAME=$__tmp
  1145. fi
  1146. return 0
  1147. }
  1148. -fast-highlight-check-path()
  1149. {
  1150. (( _start_pos-__PBUFLEN >= 0 )) || \
  1151. { [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
  1152. [[ $1 != "noasync" ]] && {
  1153. print -r -- ${sysparams[pid]}
  1154. # This is to fill cache
  1155. print -r -- $__arg
  1156. }
  1157. : ${expanded_path:=${(Q)~__arg}}
  1158. [[ -n ${FAST_BLIST_PATTERNS[(k)${${(M)expanded_path:#/*}:-$PWD/$expanded_path}]} ]] && { [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
  1159. [[ -z $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"; return 1; }
  1160. [[ -d $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos ${_end_pos}D" || __style=${FAST_THEME_NAME}path-to-dir; return 0; }
  1161. [[ -e $expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos $_end_pos" || __style=${FAST_THEME_NAME}path; return 0; }
  1162. # Search the path in CDPATH, only for CD command
  1163. [[ $active_command = "cd" ]] && for cdpath_dir in $cdpath; do
  1164. [[ -d $cdpath_dir/$expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos ${_end_pos}D" || __style=${FAST_THEME_NAME}path-to-dir; return 0; }
  1165. [[ -e $cdpath_dir/$expanded_path ]] && { [[ $1 != "noasync" ]] && print -r -- "$_start_pos $_end_pos" || __style=${FAST_THEME_NAME}path; return 0; }
  1166. done
  1167. # It's not a path.
  1168. [[ $1 != "noasync" ]] && print -r -- "- $_start_pos $_end_pos"
  1169. return 1
  1170. }
  1171. -fast-highlight-check-path-handler() {
  1172. local IFS=$'\n' pid PCFD=$1 line stripped val
  1173. integer idx
  1174. if read -r -u $PCFD pid; then
  1175. if read -r -u $PCFD val; then
  1176. if read -r -u $PCFD line; then
  1177. stripped=${${line#- }%D}
  1178. FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}-born-at]=$EPOCHSECONDS
  1179. idx=${${FAST_HIGHLIGHT[path-queue]}[(I)$stripped]}
  1180. (( idx > 0 )) && {
  1181. if [[ $line != -* ]]; then
  1182. FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]="1${(M)line%D}"
  1183. region_highlight+=("${line%% *} ${${line##* }%D} ${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}path${${(M)line%D}:+-to-dir}]}")
  1184. else
  1185. FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]=0
  1186. fi
  1187. val=${FAST_HIGHLIGHT[path-queue]}
  1188. val[idx-1,idx+${#stripped}]=""
  1189. FAST_HIGHLIGHT[path-queue]=$val
  1190. [[ ${FAST_HIGHLIGHT[cache-path-${(q)val}-${stripped%% *}]%D} = 1 && ${#val} -le 27 ]] && zle -R
  1191. }
  1192. fi
  1193. fi
  1194. kill -9 $pid 2>/dev/null
  1195. fi
  1196. zle -F -w ${PCFD}
  1197. exec {PCFD}<&-
  1198. }
  1199. zle -N -- fast-highlight-check-path-handler -fast-highlight-check-path-handler
  1200. # Highlight special blocks inside double-quoted strings
  1201. #
  1202. # The while [[ ... ]] pattern is logically ((A)|(B)|(C)|(D)|(E))(*), where:
  1203. # - A matches $var[abc]
  1204. # - B matches ${(...)var[abc]}
  1205. # - C matches $
  1206. # - D matches \$ or \" or \'
  1207. # - E matches \*
  1208. #
  1209. # and the first condition -n ${match[7] uses D to continue searching when
  1210. # backslash-something (not ['"$]) is occured.
  1211. #
  1212. # $1 - additional style to glue-in to added style
  1213. -fast-highlight-string()
  1214. {
  1215. (( _start_pos-__PBUFLEN >= 0 )) || return 0
  1216. _mybuf=$__arg
  1217. __idx=_start_pos
  1218. # 7 8
  1219. 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
  1220. [[ -n ${match[7]} ]] && {
  1221. # Skip following char – it is quoted. Choice is
  1222. # made to not highlight such quoting
  1223. __idx+=${mbegin[1]}+1
  1224. _mybuf=${match[7]:1}
  1225. } || {
  1226. __idx+=${mbegin[1]}-1
  1227. _end_idx=__idx+${mend[1]}-${mbegin[1]}+1
  1228. _mybuf=${match[8]}
  1229. # ADD
  1230. (( __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]}}")
  1231. __idx=_end_idx
  1232. }
  1233. done
  1234. return 0
  1235. }
  1236. # Highlight math and non-math context variables inside $(( )) and (( ))
  1237. #
  1238. # The while [[ ... ]] pattern is logically ((A)|(B)|(C)|(D))(*), where:
  1239. # - A matches $var[abc]
  1240. # - B matches ${(...)var[abc]}
  1241. # - C matches $
  1242. # - D matches words [a-zA-Z]## (variables)
  1243. #
  1244. # Parameters used: _mybuf, __idx, _end_idx, __style
  1245. -fast-highlight-math-string()
  1246. {
  1247. (( _start_pos-__PBUFLEN >= 0 )) || return 0
  1248. _mybuf=$__arg
  1249. __idx=_start_pos
  1250. # 7
  1251. 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
  1252. __idx+=${mbegin[1]}-1
  1253. _end_idx=__idx+${mend[1]}-${mbegin[1]}+1
  1254. _mybuf=${match[7]}
  1255. [[ ${match[1]} = [0-9]* ]] && __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}mathnum]} || {
  1256. [[ ${match[1]} = [a-zA-Z_]* ]] && {
  1257. [[ ${+parameters[${match[1]}]} = 1 || ${FAST_ASSIGNS_SEEN[${match[1]}]} = 1 ]] && \
  1258. __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}mathvar]} || \
  1259. __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}matherr]}
  1260. } || {
  1261. [[ ${match[1]} = "$"* ]] && {
  1262. match[1]=${match[1]//[\{\}+]/}
  1263. if [[ ${match[1]} = "$" || ${FAST_ASSIGNS_SEEN[${match[1]:1}]} = 1 ]] || \
  1264. { eval "[[ -n \${(P)\${match[1]:1}} ]]" } 2>> /dev/null; then
  1265. __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}back-or-dollar-double-quoted-argument]}
  1266. else
  1267. __style=${FAST_HIGHLIGHT_STYLES[${FAST_THEME_NAME}matherr]}
  1268. fi
  1269. }
  1270. }
  1271. }
  1272. # ADD
  1273. [[ $__style != "none" && -n $__style ]] && (( __start=__idx-__PBUFLEN, __end=_end_idx-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end $__style")
  1274. __idx=_end_idx
  1275. done
  1276. }
  1277. # Highlight special chars inside dollar-quoted strings
  1278. -fast-highlight-dollar-string()
  1279. {
  1280. (( _start_pos-__PBUFLEN >= 0 )) || return 0
  1281. local i j k __style
  1282. local AA
  1283. integer c
  1284. # Starting dollar-quote is at 1:2, so __start parsing at offset 3 in the string.
  1285. for (( i = 3 ; i < _end_pos - _start_pos ; i += 1 )) ; do
  1286. (( j = i + _start_pos - 1 ))
  1287. (( k = j + 1 ))
  1288. case ${__arg[$i]} in
  1289. "\\") __style=${FAST_THEME_NAME}back-dollar-quoted-argument
  1290. for (( c = i + 1 ; c <= _end_pos - _start_pos ; c += 1 )); do
  1291. [[ ${__arg[$c]} != ([0-9xXuUa-fA-F]) ]] && break
  1292. done
  1293. AA=$__arg[$i+1,$c-1]
  1294. # Matching for HEX and OCT values like \0xA6, \xA6 or \012
  1295. if [[ "$AA" == (#m)(#s)(x|X)[0-9a-fA-F](#c1,2)
  1296. || "$AA" == (#m)(#s)[0-7](#c1,3)
  1297. || "$AA" == (#m)(#s)u[0-9a-fA-F](#c1,4)
  1298. || "$AA" == (#m)(#s)U[0-9a-fA-F](#c1,8)
  1299. ]]; then
  1300. (( k += MEND ))
  1301. (( i += MEND ))
  1302. else
  1303. if (( __asize > i+1 )) && [[ $__arg[i+1] == [xXuU] ]]; then
  1304. # \x not followed by hex digits is probably an error
  1305. __style=${FAST_THEME_NAME}unknown-token
  1306. fi
  1307. (( k += 1 )) # Color following char too.
  1308. (( i += 1 )) # Skip parsing the escaped char.
  1309. fi
  1310. ;;
  1311. *) continue ;;
  1312. esac
  1313. # ADD
  1314. (( __start=j-__PBUFLEN, __end=k-__PBUFLEN, __start >= 0 )) && reply+=("$__start $__end ${FAST_HIGHLIGHT_STYLES[$__style]}")
  1315. done
  1316. }
  1317. -fast-highlight-init() {
  1318. _FAST_COMPLEX_BRACKETS=()
  1319. __fast_highlight_main__command_type_cache=()
  1320. }
  1321. typeset -ga FSH_LIST
  1322. -fsh_sy_h_shappend() {
  1323. FSH_LIST+=( "$(( $1 - 1 ));;$(( $2 ))" )
  1324. }
  1325. functions -M fsh_sy_h_append 2 2 -fsh_sy_h_shappend 2>/dev/null
  1326. # vim:ft=zsh:sw=2:sts=2