fast-highlight 70 KB

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