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

1463 lines
70 KiB

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