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.

754 regels
30 KiB

8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
8 jaren geleden
9 jaren geleden
9 jaren geleden
9 jaren geleden
9 jaren geleden
minor: Fix WARN_CREATE_GLOBAL warnings issued by zsh 5.1.1-dev-0. The following warnings are issued by zsh as of zsh-workers/37018 (commit de9effbce601 to zsh itself): _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter match created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter mbegin created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter mend created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: numeric parameter parameter MBEGIN created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: numeric parameter parameter MEND created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: scalar parameter MATCH created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter match created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter mbegin created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter mend created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: numeric parameter parameter MBEGIN created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: numeric parameter parameter MEND created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: scalar parameter MATCH created globally in function _zsh_highlight_main_highlighter_highlight_string
9 jaren geleden
minor: Fix WARN_CREATE_GLOBAL warnings issued by zsh 5.1.1-dev-0. The following warnings are issued by zsh as of zsh-workers/37018 (commit de9effbce601 to zsh itself): _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter match created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter mbegin created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: array parameter mend created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: numeric parameter parameter MBEGIN created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: numeric parameter parameter MEND created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_dollar_string:17: scalar parameter MATCH created globally in function _zsh_highlight_main_highlighter_highlight_dollar_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter match created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter mbegin created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: array parameter mend created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: numeric parameter parameter MBEGIN created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: numeric parameter parameter MEND created globally in function _zsh_highlight_main_highlighter_highlight_string _zsh_highlight_main_highlighter_highlight_string:11: scalar parameter MATCH created globally in function _zsh_highlight_main_highlighter_highlight_string
9 jaren geleden
  1. # -------------------------------------------------------------------------------------------------
  2. # Copyright (c) 2010-2016 zsh-syntax-highlighting contributors
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without modification, are permitted
  6. # provided that the following conditions are met:
  7. #
  8. # * Redistributions of source code must retain the above copyright notice, this list of conditions
  9. # and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright notice, this list of
  11. # conditions and the following disclaimer in the documentation and/or other materials provided
  12. # with the distribution.
  13. # * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors
  14. # may be used to endorse or promote products derived from this software without specific prior
  15. # written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  18. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  19. # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  20. # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  23. # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  24. # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. # -------------------------------------------------------------------------------------------------
  26. # -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
  27. # vim: ft=zsh sw=2 ts=2 et
  28. # -------------------------------------------------------------------------------------------------
  29. # Define default styles.
  30. : ${ZSH_HIGHLIGHT_STYLES[default]:=none}
  31. : ${ZSH_HIGHLIGHT_STYLES[unknown-token]:=fg=red,bold}
  32. : ${ZSH_HIGHLIGHT_STYLES[reserved-word]:=fg=yellow}
  33. : ${ZSH_HIGHLIGHT_STYLES[alias]:=fg=green}
  34. : ${ZSH_HIGHLIGHT_STYLES[suffix-alias]:=fg=green,underline}
  35. : ${ZSH_HIGHLIGHT_STYLES[builtin]:=fg=green}
  36. : ${ZSH_HIGHLIGHT_STYLES[function]:=fg=green}
  37. : ${ZSH_HIGHLIGHT_STYLES[command]:=fg=green}
  38. : ${ZSH_HIGHLIGHT_STYLES[precommand]:=fg=green,underline}
  39. : ${ZSH_HIGHLIGHT_STYLES[commandseparator]:=none}
  40. : ${ZSH_HIGHLIGHT_STYLES[hashed-command]:=fg=green}
  41. : ${ZSH_HIGHLIGHT_STYLES[path]:=underline}
  42. : ${ZSH_HIGHLIGHT_STYLES[path_pathseparator]:=}
  43. : ${ZSH_HIGHLIGHT_STYLES[path_prefix]:=underline}
  44. : ${ZSH_HIGHLIGHT_STYLES[path_prefix_pathseparator]:=}
  45. : ${ZSH_HIGHLIGHT_STYLES[globbing]:=fg=blue}
  46. : ${ZSH_HIGHLIGHT_STYLES[history-expansion]:=fg=blue}
  47. : ${ZSH_HIGHLIGHT_STYLES[single-hyphen-option]:=none}
  48. : ${ZSH_HIGHLIGHT_STYLES[double-hyphen-option]:=none}
  49. : ${ZSH_HIGHLIGHT_STYLES[back-quoted-argument]:=none}
  50. : ${ZSH_HIGHLIGHT_STYLES[single-quoted-argument]:=fg=yellow}
  51. : ${ZSH_HIGHLIGHT_STYLES[double-quoted-argument]:=fg=yellow}
  52. : ${ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]:=fg=yellow}
  53. : ${ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]:=fg=cyan}
  54. : ${ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]:=fg=cyan}
  55. : ${ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]:=fg=cyan}
  56. : ${ZSH_HIGHLIGHT_STYLES[assign]:=none}
  57. : ${ZSH_HIGHLIGHT_STYLES[redirection]:=none}
  58. : ${ZSH_HIGHLIGHT_STYLES[comment]:=fg=black,bold}
  59. # Whether the highlighter should be called or not.
  60. _zsh_highlight_highlighter_main_predicate()
  61. {
  62. # may need to remove path_prefix highlighting when the line ends
  63. [[ $WIDGET == zle-line-finish ]] || _zsh_highlight_buffer_modified
  64. }
  65. # Helper to deal with tokens crossing line boundaries.
  66. _zsh_highlight_main_add_region_highlight() {
  67. integer start=$1 end=$2
  68. shift 2
  69. # The calculation was relative to $PREBUFFER$BUFFER, but region_highlight is
  70. # relative to $BUFFER.
  71. (( start -= $#PREBUFFER ))
  72. (( end -= $#PREBUFFER ))
  73. (( end < 0 )) && return # having end<0 would be a bug
  74. (( start < 0 )) && start=0 # having start<0 is normal with e.g. multiline strings
  75. _zsh_highlight_add_highlight $start $end "$@"
  76. }
  77. # Get the type of a command.
  78. #
  79. # Uses the zsh/parameter module if available to avoid forks, and a
  80. # wrapper around 'type -w' as fallback.
  81. #
  82. # Takes a single argument.
  83. #
  84. # The result will be stored in REPLY.
  85. _zsh_highlight_main__type() {
  86. if (( $+_zsh_highlight_main__command_type_cache )); then
  87. REPLY=$_zsh_highlight_main__command_type_cache[(e)$1]
  88. if [[ -n "$REPLY" ]]; then
  89. return
  90. fi
  91. fi
  92. if (( $#options_to_set )); then
  93. setopt localoptions $options_to_set;
  94. fi
  95. unset REPLY
  96. if zmodload -e zsh/parameter; then
  97. if (( $+aliases[(e)$1] )); then
  98. REPLY=alias
  99. elif (( $+saliases[(e)${1##*.}] )); then
  100. REPLY='suffix alias'
  101. elif (( $reswords[(Ie)$1] )); then
  102. REPLY=reserved
  103. elif (( $+functions[(e)$1] )); then
  104. REPLY=function
  105. elif (( $+builtins[(e)$1] )); then
  106. REPLY=builtin
  107. elif (( $+commands[(e)$1] )); then
  108. REPLY=command
  109. # zsh 5.2 and older have a bug whereby running 'type -w ./sudo' implicitly
  110. # runs 'hash ./sudo=/usr/local/bin/./sudo' (assuming /usr/local/bin/sudo
  111. # exists and is in $PATH). Avoid triggering the bug, at the expense of
  112. # falling through to the $() below, incurring a fork. (Issue #354.)
  113. #
  114. # The second disjunct mimics the isrelative() C call from the zsh bug.
  115. elif { is-at-least 5.3 || [[ $1 != */* ]] } &&
  116. ! builtin type -w -- $1 >/dev/null 2>&1; then
  117. REPLY=none
  118. fi
  119. fi
  120. if ! (( $+REPLY )); then
  121. REPLY="${$(LC_ALL=C builtin type -w -- $1 2>/dev/null)#*: }"
  122. fi
  123. if (( $+_zsh_highlight_main__command_type_cache )); then
  124. _zsh_highlight_main__command_type_cache[(e)$1]=$REPLY
  125. fi
  126. }
  127. # Check whether the first argument is a redirection operator token.
  128. # Report result via the exit code.
  129. _zsh_highlight_main__is_redirection() {
  130. # A redirection operator token:
  131. # - starts with an optional single-digit number;
  132. # - then, has a '<' or '>' character;
  133. # - is not a process substitution [<(...) or >(...)].
  134. [[ $1 == (<0-9>|)(\<|\>)* ]] && [[ $1 != (\<|\>)$'\x28'* ]]
  135. }
  136. # Resolve alias.
  137. #
  138. # Takes a single argument.
  139. #
  140. # The result will be stored in REPLY.
  141. _zsh_highlight_main__resolve_alias() {
  142. if zmodload -e zsh/parameter; then
  143. REPLY=${aliases[$arg]}
  144. else
  145. REPLY="${"$(alias -- $arg)"#*=}"
  146. fi
  147. }
  148. # Main syntax highlighting function.
  149. _zsh_highlight_highlighter_main_paint()
  150. {
  151. ## Before we even 'emulate -L', we must test a few options that would reset.
  152. if [[ -o interactive_comments ]]; then
  153. local interactive_comments= # set to empty
  154. fi
  155. if [[ -o path_dirs ]]; then
  156. integer path_dirs_was_set=1
  157. else
  158. integer path_dirs_was_set=0
  159. fi
  160. emulate -L zsh
  161. setopt localoptions extendedglob bareglobqual
  162. # At the PS3 prompt and in vared, highlight nothing.
  163. #
  164. # (We can't check this in _zsh_highlight_highlighter_main_predicate because
  165. # if the predicate returns false, the previous value of region_highlight
  166. # would be reused.)
  167. if [[ $CONTEXT == (select|vared) ]]; then
  168. return
  169. fi
  170. ## Variable declarations and initializations
  171. local start_pos=0 end_pos highlight_glob=true arg style
  172. local in_array_assignment=false # true between 'a=(' and the matching ')'
  173. typeset -a ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR
  174. typeset -a ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS
  175. typeset -a ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW
  176. local -a options_to_set # used in callees
  177. local buf="$PREBUFFER$BUFFER"
  178. integer len="${#buf}"
  179. if (( path_dirs_was_set )); then
  180. options_to_set+=( PATH_DIRS )
  181. fi
  182. unset path_dirs_was_set
  183. ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR=(
  184. '|' '||' ';' '&' '&&'
  185. '|&'
  186. '&!' '&|'
  187. # ### 'case' syntax, but followed by a pattern, not by a command
  188. # ';;' ';&' ';|'
  189. )
  190. ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS=(
  191. 'builtin' 'command' 'exec' 'nocorrect' 'noglob'
  192. 'pkexec' # immune to #121 because it's usually not passed --option flags
  193. )
  194. # Tokens that, at (naively-determined) "command position", are followed by
  195. # a de jure command position. All of these are reserved words.
  196. ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW=(
  197. $'\x7b' # block
  198. $'\x28' # subshell
  199. '()' # anonymous function
  200. 'while'
  201. 'until'
  202. 'if'
  203. 'then'
  204. 'elif'
  205. 'else'
  206. 'do'
  207. 'time'
  208. 'coproc'
  209. '!' # reserved word; unrelated to $histchars[1]
  210. )
  211. # State machine
  212. #
  213. # The states are:
  214. # - :start: Command word
  215. # - :sudo_opt: A leading-dash option to sudo (such as "-u" or "-i")
  216. # - :sudo_arg: The argument to a sudo leading-dash option that takes one,
  217. # when given as a separate word; i.e., "foo" in "-u foo" (two
  218. # words) but not in "-ufoo" (one word).
  219. # - :regular: "Not a command word", and command delimiters are permitted.
  220. # Mainly used to detect premature termination of commands.
  221. #
  222. # When the kind of a word is not yet known, $this_word / $next_word may contain
  223. # multiple states. For example, after "sudo -i", the next word may be either
  224. # another --flag or a command name, hence the state would include both :start:
  225. # and :sudo_opt:.
  226. #
  227. # The tokens are always added with both leading and trailing colons to serve as
  228. # word delimiters (an improvised array); [[ $x == *:foo:* ]] and x=${x//:foo:/}
  229. # will DTRT regardless of how many elements or repetitions $x has..
  230. #
  231. # Handling of redirections: upon seeing a redirection token, we must stall
  232. # the current state --- that is, the value of $this_word --- for two iterations
  233. # (one for the redirection operator, one for the word following it representing
  234. # the redirection target). Therefore, we set $in_redirection to 2 upon seeing a
  235. # redirection operator, decrement it each iteration, and stall the current state
  236. # when it is non-zero. Thus, upon reaching the next word (the one that follows
  237. # the redirection operator and target), $this_word will still contain values
  238. # appropriate for the word immediately following the word that preceded the
  239. # redirection operator.
  240. #
  241. # The "the previous word was a redirection operator" state is not communicated
  242. # to the next iteration via $next_word/$this_word as usual, but via
  243. # $in_redirection. The value of $next_word from the iteration that processed
  244. # the operator is discarded.
  245. #
  246. local this_word=':start:' next_word
  247. integer in_redirection
  248. # Processing buffer
  249. local proc_buf="$buf"
  250. for arg in ${interactive_comments-${(z)buf}} \
  251. ${interactive_comments+${(zZ+c+)buf}}; do
  252. # Initialize $next_word.
  253. if (( in_redirection )); then
  254. (( --in_redirection ))
  255. fi
  256. if (( in_redirection == 0 )); then
  257. # Initialize $next_word to its default value.
  258. next_word=':regular:'
  259. else
  260. # Stall $next_word.
  261. fi
  262. # Initialize per-"simple command" [zshmisc(1)] variables:
  263. #
  264. # $already_added (see next paragraph)
  265. # $style how to highlight $arg
  266. # $in_array_assignment boolean flag for "between '(' and ')' of array assignment"
  267. # $highlight_glob boolean flag for "'noglob' is in effect"
  268. #
  269. # $already_added is set to 1 to disable adding an entry to region_highlight
  270. # for this iteration. Currently, that is done for "" and $'' strings,
  271. # which add the entry early so escape sequences within the string override
  272. # the string's color.
  273. integer already_added=0
  274. style=unknown-token
  275. if [[ $this_word == *':start:'* ]]; then
  276. in_array_assignment=false
  277. if [[ $arg == 'noglob' ]]; then
  278. highlight_glob=false
  279. fi
  280. fi
  281. # Compute the new $start_pos and $end_pos, skipping over whitespace in $buf.
  282. if [[ $arg == ';' ]] ; then
  283. # We're looking for either a semicolon or a newline, whichever comes
  284. # first. Both of these are rendered as a ";" (SEPER) by the ${(z)..}
  285. # flag.
  286. #
  287. # We can't use the (Z+n+) flag because that elides the end-of-command
  288. # token altogether, so 'echo foo\necho bar' (two commands) becomes
  289. # indistinguishable from 'echo foo echo bar' (one command with three
  290. # words for arguments).
  291. local needle=$'[;\n]'
  292. integer offset=$(( ${proc_buf[(i)$needle]} - 1 ))
  293. (( start_pos += offset ))
  294. (( end_pos = start_pos + $#arg ))
  295. else
  296. integer offset=$(((len-start_pos)-${#${proc_buf##([[:space:]]|\\[[:space:]])#}}))
  297. ((start_pos+=offset))
  298. ((end_pos=$start_pos+${#arg}))
  299. fi
  300. # Compute the new $proc_buf. We advance it
  301. # (chop off characters from the beginning)
  302. # beyond what end_pos points to, by skipping
  303. # as many characters as end_pos was advanced.
  304. #
  305. # end_pos was advanced by $offset (via start_pos)
  306. # and by $#arg. Note the `start_pos=$end_pos`
  307. # below.
  308. #
  309. # As for the [,len]. We could use [,len-start_pos+offset]
  310. # here, but to make it easier on eyes, we use len and
  311. # rely on the fact that Zsh simply handles that. The
  312. # length of proc_buf is len-start_pos+offset because
  313. # we're chopping it to match current start_pos, so its
  314. # length matches the previous value of start_pos.
  315. #
  316. # Why [,-1] is slower than [,length] isn't clear.
  317. proc_buf="${proc_buf[offset + $#arg + 1,len]}"
  318. # Handle the INTERACTIVE_COMMENTS option.
  319. #
  320. # We use the (Z+c+) flag so the entire comment is presented as one token in $arg.
  321. if [[ -n ${interactive_comments+'set'} && $arg[1] == $histchars[3] ]]; then
  322. if [[ $this_word == *(':regular:'|':start:')* ]]; then
  323. style=comment
  324. else
  325. style=unknown-token # prematurely terminated
  326. fi
  327. _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
  328. already_added=1
  329. continue
  330. fi
  331. # Analyse the current word.
  332. if _zsh_highlight_main__is_redirection $arg ; then
  333. # A '<' or '>', possibly followed by a digit
  334. in_redirection=2
  335. fi
  336. # Special-case the first word after 'sudo'.
  337. if (( ! in_redirection )); then
  338. if [[ $this_word == *':sudo_opt:'* ]] && [[ $arg != -* ]]; then
  339. this_word=${this_word//:sudo_opt:/}
  340. fi
  341. fi
  342. # Parse the sudo command line
  343. if (( ! in_redirection )); then
  344. if [[ $this_word == *':sudo_opt:'* ]]; then
  345. case "$arg" in
  346. # Flag that requires an argument
  347. '-'[Cgprtu]) this_word=${this_word//:start:/};
  348. next_word=':sudo_arg:';;
  349. # This prevents misbehavior with sudo -u -otherargument
  350. '-'*) this_word=${this_word//:start:/};
  351. next_word+=':start:';
  352. next_word+=':sudo_opt:';;
  353. *) ;;
  354. esac
  355. elif [[ $this_word == *':sudo_arg:'* ]]; then
  356. next_word+=':sudo_opt:'
  357. next_word+=':start:'
  358. fi
  359. fi
  360. # The Great Fork: is this a command word? Is this a non-command word?
  361. if [[ $this_word == *':start:'* ]] && (( in_redirection == 0 )); then # $arg is the command word
  362. if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS:#"$arg"} ]]; then
  363. style=precommand
  364. elif [[ "$arg" = "sudo" ]]; then
  365. style=precommand
  366. next_word=${next_word//:regular:/}
  367. next_word+=':sudo_opt:'
  368. next_word+=':start:'
  369. else
  370. _zsh_highlight_main_highlighter_expand_path $arg
  371. local expanded_arg="$REPLY"
  372. _zsh_highlight_main__type ${expanded_arg}
  373. local res="$REPLY"
  374. () {
  375. # Special-case: command word is '$foo', like that, without braces or anything.
  376. #
  377. # That's not entirely correct --- if the parameter's value happens to be a reserved
  378. # word, the parameter expansion will be highlighted as a reserved word --- but that
  379. # incorrectness is outweighed by the usability improvement of permitting the use of
  380. # parameters that refer to commands, functions, and builtins.
  381. local -a match mbegin mend
  382. local MATCH; integer MBEGIN MEND
  383. if [[ $res == none ]] && (( ${+parameters} )) &&
  384. [[ ${arg[1]} == \$ ]] && [[ ${arg:1} =~ ^([A-Za-z_][A-Za-z0-9_]*|[0-9]+)$ ]] &&
  385. (( ${+parameters[${MATCH}]} ))
  386. then
  387. _zsh_highlight_main__type ${(P)MATCH}
  388. res=$REPLY
  389. fi
  390. }
  391. case $res in
  392. reserved) style=reserved-word;;
  393. 'suffix alias') style=suffix-alias;;
  394. alias) () {
  395. integer insane_alias
  396. case $arg in
  397. # Issue #263: aliases with '=' on their LHS.
  398. #
  399. # There are three cases:
  400. #
  401. # - Unsupported, breaks 'alias -L' output, but invokable:
  402. ('='*) :;;
  403. # - Unsupported, not invokable:
  404. (*'='*) insane_alias=1;;
  405. # - The common case:
  406. (*) :;;
  407. esac
  408. if (( insane_alias )); then
  409. style=unknown-token
  410. else
  411. style=alias
  412. _zsh_highlight_main__resolve_alias $arg
  413. local alias_target="$REPLY"
  414. [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS:#"$alias_target"} && -z ${(M)ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS:#"$arg"} ]] && ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS+=($arg)
  415. fi
  416. }
  417. ;;
  418. builtin) style=builtin;;
  419. function) style=function;;
  420. command) style=command;;
  421. hashed) style=hashed-command;;
  422. none) if _zsh_highlight_main_highlighter_check_assign; then
  423. style=assign
  424. if [[ $arg[-1] == '(' ]]; then
  425. in_array_assignment=true
  426. else
  427. # assignment to a scalar parameter.
  428. # (For array assignments, the command doesn't start until the ")" token.)
  429. next_word+=':start:'
  430. fi
  431. elif [[ $arg[0,1] = $histchars[0,1] ]] && (( $#arg[0,2] == 2 )); then
  432. style=history-expansion
  433. elif [[ $arg[0,1] == $histchars[2,2] ]]; then
  434. style=history-expansion
  435. elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]]; then
  436. if [[ $this_word == *':regular:'* ]]; then
  437. # This highlights empty commands (semicolon follows nothing) as an error.
  438. # Zsh accepts them, though.
  439. style=commandseparator
  440. else
  441. style=unknown-token
  442. fi
  443. elif (( in_redirection == 2 )); then
  444. style=redirection
  445. elif [[ $arg[1,2] == '((' ]]; then
  446. # Arithmetic evaluation.
  447. #
  448. # Note: prior to zsh-5.1.1-52-g4bed2cf (workers/36669), the ${(z)...}
  449. # splitter would only output the '((' token if the matching '))' had
  450. # been typed. Therefore, under those versions of zsh, BUFFER="(( 42"
  451. # would be highlighted as an error until the matching "))" are typed.
  452. #
  453. # We highlight just the opening parentheses, as a reserved word; this
  454. # is how [[ ... ]] is highlighted, too.
  455. style=reserved-word
  456. _zsh_highlight_main_add_region_highlight $start_pos $((start_pos + 2)) $style
  457. already_added=1
  458. if [[ $arg[-2,-1] == '))' ]]; then
  459. _zsh_highlight_main_add_region_highlight $((end_pos - 2)) $end_pos $style
  460. already_added=1
  461. fi
  462. elif [[ $arg == '()' || $arg == $'\x28' ]]; then
  463. # anonymous function
  464. # subshell
  465. style=reserved-word
  466. else
  467. if _zsh_highlight_main_highlighter_check_path; then
  468. style=$REPLY
  469. else
  470. style=unknown-token
  471. fi
  472. fi
  473. ;;
  474. *) _zsh_highlight_main_add_region_highlight $start_pos $end_pos commandtypefromthefuture-$res
  475. already_added=1
  476. ;;
  477. esac
  478. fi
  479. fi
  480. if (( ! already_added )) && [[ $style == unknown-token ]] && # not handled by the 'command word' codepath
  481. { (( in_redirection )) || [[ $this_word == *':regular:'* ]] || [[ $this_word == *':sudo_opt:'* ]] || [[ $this_word == *':sudo_arg:'* ]] }
  482. then # $arg is a non-command word
  483. case $arg in
  484. $'\x29') # subshell or end of array assignment
  485. if $in_array_assignment; then
  486. style=assign
  487. in_array_assignment=false
  488. next_word+=':start:'
  489. else
  490. style=reserved-word
  491. fi;;
  492. $'\x7d') style=reserved-word;; # block
  493. '--'*) style=double-hyphen-option;;
  494. '-'*) style=single-hyphen-option;;
  495. "'"*) style=single-quoted-argument;;
  496. '"'*) style=double-quoted-argument
  497. _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
  498. _zsh_highlight_main_highlighter_highlight_string
  499. already_added=1
  500. ;;
  501. \$\'*) style=dollar-quoted-argument
  502. _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
  503. _zsh_highlight_main_highlighter_highlight_dollar_string
  504. already_added=1
  505. ;;
  506. '`'*) style=back-quoted-argument;;
  507. [*?]*|*[^\\][*?]*)
  508. $highlight_glob && style=globbing || style=default;;
  509. *) if false; then
  510. elif [[ $arg[0,1] = $histchars[0,1] ]] && (( $#arg[0,2] == 2 )); then
  511. style=history-expansion
  512. elif [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]]; then
  513. if [[ $this_word == *':regular:'* ]]; then
  514. style=commandseparator
  515. else
  516. style=unknown-token
  517. fi
  518. elif (( in_redirection == 2 )); then
  519. style=redirection
  520. else
  521. if _zsh_highlight_main_highlighter_check_path; then
  522. style=$REPLY
  523. else
  524. style=default
  525. fi
  526. fi
  527. ;;
  528. esac
  529. fi
  530. if ! (( already_added )); then
  531. _zsh_highlight_main_add_region_highlight $start_pos $end_pos $style
  532. [[ $style == path || $style == path_prefix ]] && _zsh_highlight_main_highlighter_highlight_path_separators
  533. fi
  534. if [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_COMMANDSEPARATOR:#"$arg"} ]]; then
  535. next_word=':start:'
  536. highlight_glob=true
  537. elif
  538. [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_CONTROL_FLOW:#"$arg"} && $this_word == *':start:'* ]] ||
  539. [[ -n ${(M)ZSH_HIGHLIGHT_TOKENS_PRECOMMANDS:#"$arg"} && $this_word == *':start:'* ]]; then
  540. next_word=':start:'
  541. elif [[ $arg == "repeat" && $this_word == *':start:'* ]]; then
  542. # skip the repeat-count word
  543. in_redirection=2
  544. # The redirection mechanism assumes $this_word describes the word
  545. # following the redirection. Make it so.
  546. #
  547. # That word can be a command word with shortloops (`repeat 2 ls`)
  548. # or a command separator (`repeat 2; ls` or `repeat 2; do ls; done`).
  549. #
  550. # The repeat-count word will be handled like a redirection target.
  551. this_word=':start::regular:'
  552. fi
  553. start_pos=$end_pos
  554. if (( in_redirection == 0 )); then
  555. # This is the default/common codepath.
  556. this_word=$next_word
  557. else
  558. # Stall $this_word.
  559. fi
  560. done
  561. }
  562. # Check if $arg is variable assignment
  563. _zsh_highlight_main_highlighter_check_assign()
  564. {
  565. setopt localoptions extended_glob
  566. [[ $arg == [[:alpha:]_][[:alnum:]_]#(|\[*\])(|[+])=* ]] ||
  567. [[ $arg == [0-9]##(|[+])=* ]]
  568. }
  569. _zsh_highlight_main_highlighter_highlight_path_separators()
  570. {
  571. local pos style_pathsep
  572. style_pathsep=${style}_pathseparator
  573. [[ -z "$ZSH_HIGHLIGHT_STYLES[$style_pathsep]" || "$ZSH_HIGHLIGHT_STYLES[$style]" == "$ZSH_HIGHLIGHT_STYLES[$style_pathsep]" ]] && return 0
  574. for (( pos = start_pos; $pos <= end_pos; pos++ )) ; do
  575. if [[ $BUFFER[pos] == / ]]; then
  576. _zsh_highlight_main_add_region_highlight $((pos - 1)) $pos $style_pathsep
  577. fi
  578. done
  579. }
  580. # Check if $arg is a path.
  581. # If yes, return 0 and in $REPLY the style to use.
  582. # Else, return non-zero (and the contents of $REPLY is undefined).
  583. _zsh_highlight_main_highlighter_check_path()
  584. {
  585. _zsh_highlight_main_highlighter_expand_path $arg;
  586. local expanded_path="$REPLY"
  587. REPLY=path
  588. [[ -z $expanded_path ]] && return 1
  589. [[ -L $expanded_path ]] && return 0
  590. [[ -e $expanded_path ]] && return 0
  591. # Search the path in CDPATH
  592. local cdpath_dir
  593. for cdpath_dir in $cdpath ; do
  594. [[ -e "$cdpath_dir/$expanded_path" ]] && return 0
  595. done
  596. # If dirname($arg) doesn't exist, neither does $arg.
  597. [[ ! -d ${expanded_path:h} ]] && return 1
  598. # If this word ends the buffer, check if it's the prefix of a valid path.
  599. if [[ ${BUFFER[1]} != "-" && ${#BUFFER} == $end_pos ]] &&
  600. [[ $WIDGET != zle-line-finish ]]; then
  601. local -a tmp
  602. tmp=( ${expanded_path}*(N) )
  603. (( $#tmp > 0 )) && REPLY=path_prefix && return 0
  604. fi
  605. # It's not a path.
  606. return 1
  607. }
  608. # Highlight special chars inside double-quoted strings
  609. _zsh_highlight_main_highlighter_highlight_string()
  610. {
  611. setopt localoptions noksharrays
  612. local -a match mbegin mend
  613. local MATCH; integer MBEGIN MEND
  614. local i j k style
  615. # Starting quote is at 1, so start parsing at offset 2 in the string.
  616. for (( i = 2 ; i < end_pos - start_pos ; i += 1 )) ; do
  617. (( j = i + start_pos - 1 ))
  618. (( k = j + 1 ))
  619. case "$arg[$i]" in
  620. '$' ) style=dollar-double-quoted-argument
  621. # Look for an alphanumeric parameter name.
  622. if [[ ${arg:$i} =~ ^([A-Za-z_][A-Za-z0-9_]*|[0-9]+) ]] ; then
  623. (( k += $#MATCH )) # highlight the parameter name
  624. (( i += $#MATCH )) # skip past it
  625. elif [[ ${arg:$i} =~ ^[{]([A-Za-z_][A-Za-z0-9_]*|[0-9]+)[}] ]] ; then
  626. (( k += $#MATCH )) # highlight the parameter name and braces
  627. (( i += $#MATCH )) # skip past it
  628. else
  629. continue
  630. fi
  631. ;;
  632. "\\") style=back-double-quoted-argument
  633. if [[ \\\`\"\$ == *$arg[$i+1]* ]]; then
  634. (( k += 1 )) # Color following char too.
  635. (( i += 1 )) # Skip parsing the escaped char.
  636. else
  637. continue
  638. fi
  639. ;;
  640. *) continue ;;
  641. esac
  642. _zsh_highlight_main_add_region_highlight $j $k $style
  643. done
  644. }
  645. # Highlight special chars inside dollar-quoted strings
  646. _zsh_highlight_main_highlighter_highlight_dollar_string()
  647. {
  648. setopt localoptions noksharrays
  649. local -a match mbegin mend
  650. local MATCH; integer MBEGIN MEND
  651. local i j k style
  652. local AA
  653. integer c
  654. # Starting dollar-quote is at 1:2, so start parsing at offset 3 in the string.
  655. for (( i = 3 ; i < end_pos - start_pos ; i += 1 )) ; do
  656. (( j = i + start_pos - 1 ))
  657. (( k = j + 1 ))
  658. case "$arg[$i]" in
  659. "\\") style=back-dollar-quoted-argument
  660. for (( c = i + 1 ; c <= end_pos - start_pos ; c += 1 )); do
  661. [[ "$arg[$c]" != ([0-9xXuUa-fA-F]) ]] && break
  662. done
  663. AA=$arg[$i+1,$c-1]
  664. # Matching for HEX and OCT values like \0xA6, \xA6 or \012
  665. if [[ "$AA" =~ "^(x|X)[0-9a-fA-F]{1,2}"
  666. || "$AA" =~ "^[0-7]{1,3}"
  667. || "$AA" =~ "^u[0-9a-fA-F]{1,4}"
  668. || "$AA" =~ "^U[0-9a-fA-F]{1,8}"
  669. ]]; then
  670. (( k += $#MATCH ))
  671. (( i += $#MATCH ))
  672. else
  673. if (( $#arg > $i+1 )) && [[ $arg[$i+1] == [xXuU] ]]; then
  674. # \x not followed by hex digits is probably an error
  675. style=unknown-token
  676. fi
  677. (( k += 1 )) # Color following char too.
  678. (( i += 1 )) # Skip parsing the escaped char.
  679. fi
  680. ;;
  681. *) continue ;;
  682. esac
  683. _zsh_highlight_main_add_region_highlight $j $k $style
  684. done
  685. }
  686. # Called with a single positional argument.
  687. # Perform filename expansion (tilde expansion) on the argument and set $REPLY to the expanded value.
  688. #
  689. # Does not perform filename generation (globbing).
  690. _zsh_highlight_main_highlighter_expand_path()
  691. {
  692. (( $# == 1 )) || print -r -- >&2 "zsh-syntax-highlighting: BUG: _zsh_highlight_main_highlighter_expand_path: called without argument"
  693. # The $~1 syntax normally performs filename generation, but not when it's on the right-hand side of ${x:=y}.
  694. setopt localoptions nonomatch
  695. unset REPLY
  696. : ${REPLY:=${(Q)~1}}
  697. }
  698. # -------------------------------------------------------------------------------------------------
  699. # Main highlighter initialization
  700. # -------------------------------------------------------------------------------------------------
  701. _zsh_highlight_main__precmd_hook() {
  702. _zsh_highlight_main__command_type_cache=()
  703. }
  704. autoload -U add-zsh-hook
  705. if add-zsh-hook precmd _zsh_highlight_main__precmd_hook 2>/dev/null; then
  706. # Initialize command type cache
  707. typeset -gA _zsh_highlight_main__command_type_cache
  708. else
  709. print -r -- >&2 'zsh-syntax-highlighting: Failed to load add-zsh-hook. Some speed optimizations will not be used.'
  710. # Make sure the cache is unset
  711. unset _zsh_highlight_main__command_type_cache
  712. fi