mirror of
				https://github.com/zsh-users/zsh-syntax-highlighting.git
				synced 2025-10-30 15:56:28 +08:00 
			
		
		
		
	main: Run the entirety of aliases through the state machine
Fixes #540 #544 #552 #554 #555
This commit is contained in:
		
							parent
							
								
									2d4fe988ba
								
							
						
					
					
						commit
						cb8c736a56
					
				| @ -72,6 +72,9 @@ _zsh_highlight_main_add_region_highlight() { | |||||||
|   integer start=$1 end=$2 |   integer start=$1 end=$2 | ||||||
|   shift 2 |   shift 2 | ||||||
| 
 | 
 | ||||||
|  |   (( highlighted_alias )) && return | ||||||
|  |   (( in_alias )) && highlighted_alias=1 | ||||||
|  | 
 | ||||||
|   # The calculation was relative to $buf but region_highlight is relative to $BUFFER. |   # The calculation was relative to $buf but region_highlight is relative to $BUFFER. | ||||||
|   (( start += buf_offset )) |   (( start += buf_offset )) | ||||||
|   (( end += buf_offset )) |   (( end += buf_offset )) | ||||||
| @ -363,10 +366,18 @@ _zsh_highlight_highlighter_main_paint() | |||||||
| _zsh_highlight_main_highlighter_highlight_list() | _zsh_highlight_main_highlighter_highlight_list() | ||||||
| { | { | ||||||
|   integer start_pos end_pos=0 buf_offset=$1 has_end=$3 |   integer start_pos end_pos=0 buf_offset=$1 has_end=$3 | ||||||
|   local buf=$4 highlight_glob=true arg arg_raw style |   # last_alias is the last alias arg (lhs) expanded (if in an alias). | ||||||
|  |   #     This allows for expanding alias ls='ls -l' while avoiding loops. | ||||||
|  |   local arg buf=$4 highlight_glob=true last_alias style | ||||||
|   local in_array_assignment=false # true between 'a=(' and the matching ')' |   local in_array_assignment=false # true between 'a=(' and the matching ')' | ||||||
|   integer len=$#buf |   # highlighted_alias is 1 when the alias arg has been highlighted with a non-alias style. | ||||||
|  |   #     E.g. alias x=ls;  x has been highlighted as alias AND command. | ||||||
|  |   # in_alias is equal to the number of shifts needed until arg=args[1] pops an | ||||||
|  |   #     arg from BUFFER and not added by an alias. | ||||||
|  |   integer highlighted_alias=0 in_alias=0 len=$#buf | ||||||
|   local -a match mbegin mend list_highlights |   local -a match mbegin mend list_highlights | ||||||
|  |   # seen_alias is a map of aliases already seen to avoid loops like alias a=b b=a | ||||||
|  |   local -A seen_alias | ||||||
|   list_highlights=() |   list_highlights=() | ||||||
| 
 | 
 | ||||||
|   # "R" for round |   # "R" for round | ||||||
| @ -427,10 +438,12 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|     args=(${(z)buf}) |     args=(${(z)buf}) | ||||||
|   fi |   fi | ||||||
|   while (( $#args )); do |   while (( $#args )); do | ||||||
|     # Save an unmunged copy of the current word. |  | ||||||
|     arg=$args[1] |     arg=$args[1] | ||||||
|     arg_raw="$arg" |  | ||||||
|     shift args |     shift args | ||||||
|  |     if (( in_alias )); then | ||||||
|  |       (( in_alias-- )) | ||||||
|  |       (( in_alias == 0 )) && highlighted_alias=0 last_alias= seen_alias=() | ||||||
|  |     fi | ||||||
| 
 | 
 | ||||||
|     # Initialize this_word and next_word. |     # Initialize this_word and next_word. | ||||||
|     if (( in_redirection == 0 )); then |     if (( in_redirection == 0 )); then | ||||||
| @ -455,7 +468,7 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
| 
 | 
 | ||||||
|     if true; then |     if (( in_alias == 0 )); then | ||||||
|       # Compute the new $start_pos and $end_pos, skipping over whitespace in $buf. |       # Compute the new $start_pos and $end_pos, skipping over whitespace in $buf. | ||||||
|       start_pos=$end_pos |       start_pos=$end_pos | ||||||
|       if [[ $arg == ';' ]] ; then |       if [[ $arg == ';' ]] ; then | ||||||
| @ -531,34 +544,20 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|       # Expand aliases. |       # Expand aliases. | ||||||
|       _zsh_highlight_main__type "$arg" |       _zsh_highlight_main__type "$arg" | ||||||
|       local res="$REPLY" |       local res="$REPLY" | ||||||
|       if [[ $res == "alias" ]]; then |       if [[ $res == "alias" ]] && [[ $last_alias != $arg ]]; then | ||||||
|         () { |         # Avoid looping forever on alias a=b b=c c=b, but allow alias foo='foo bar' | ||||||
|         local -A seen_alias |         if (( $+seen_alias[$arg] )); then | ||||||
|         while [[ $REPLY == alias ]]; do |           _zsh_highlight_main_add_region_highlight $start_pos $end_pos unknown-token | ||||||
|  |           continue | ||||||
|  |         fi | ||||||
|         seen_alias[$arg]=1 |         seen_alias[$arg]=1 | ||||||
|  |         last_alias=$arg | ||||||
|         _zsh_highlight_main__resolve_alias $arg |         _zsh_highlight_main__resolve_alias $arg | ||||||
|         # Use a temporary array to ensure the subscript is interpreted as |  | ||||||
|         # an array subscript, not as a scalar subscript |  | ||||||
|         local -a alias_args |         local -a alias_args | ||||||
|         # TODO: the ${interactive_comments+set} path needs to skip comments; see test-data/alias-comment1.zsh |         # Elision is desired in case alias x='' | ||||||
|         alias_args=( ${interactive_comments-${(z)REPLY}} |         alias_args=( ${interactive_comments-${(z)REPLY}} | ||||||
|                      ${interactive_comments+${(zZ+c+)REPLY}} ) |                      ${interactive_comments+${(zZ+c+)REPLY}} ) | ||||||
|         # Avoid looping forever on alias a=b b=c c=b, but allow alias foo='foo bar' |         case $arg in | ||||||
|         [[ $arg == $alias_args[1] ]] && break |  | ||||||
|         arg=$alias_args[1] |  | ||||||
|         if (( $+seen_alias[$arg] )); then |  | ||||||
|           res=none |  | ||||||
|           break |  | ||||||
|         fi |  | ||||||
|         _zsh_highlight_main__type "$arg" |  | ||||||
|         done |  | ||||||
|         } |  | ||||||
|         _zsh_highlight_main_highlighter_expand_path $arg |  | ||||||
|         arg=$REPLY |  | ||||||
|         () { |  | ||||||
|         # Make sure to use $arg_raw here, rather than $arg. |  | ||||||
|         integer insane_alias |  | ||||||
|         case $arg_raw in |  | ||||||
|           # Issue #263: aliases with '=' on their LHS. |           # Issue #263: aliases with '=' on their LHS. | ||||||
|           # |           # | ||||||
|           # There are three cases: |           # There are three cases: | ||||||
| @ -566,27 +565,29 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|           # - Unsupported, breaks 'alias -L' output, but invokable: |           # - Unsupported, breaks 'alias -L' output, but invokable: | ||||||
|           ('='*) :;; |           ('='*) :;; | ||||||
|           # - Unsupported, not invokable: |           # - Unsupported, not invokable: | ||||||
|           (*'='*) insane_alias=1;; |           (*'='*) | ||||||
|  |             _zsh_highlight_main_add_region_highlight $start_pos $end_pos unknown-token | ||||||
|  |             continue | ||||||
|  |             ;; | ||||||
|           # - The common case: |           # - The common case: | ||||||
|           (*) :;; |           (*) :;; | ||||||
|         esac |         esac | ||||||
|         if (( insane_alias )); then |         args=( $alias_args $args ) | ||||||
|           style=unknown-token |         if (( in_alias == 0 )); then | ||||||
|         # Calling 'type' again; since __type memoizes the answer, this call is just a hash lookup. |           _zsh_highlight_main_add_region_highlight $start_pos $end_pos alias | ||||||
|         elif ! _zsh_highlight_main__type "$arg" || [[ $REPLY == 'none' ]]; then |           # Add one because we will in_alias-- on the next loop iteration so | ||||||
|           style=unknown-token |           # this iteration should be considered in in_alias as well | ||||||
|  |           (( in_alias += $#alias_args + 1 )) | ||||||
|         else |         else | ||||||
|           # The common case. |           # This arg is already included in the count, so no need to + 1. | ||||||
|           style=alias |           (( in_alias += $#alias_args )) | ||||||
|           if (( ${+precommand_options[(re)"$arg"]} )) && (( ! ${+precommand_options[(re)"$arg_raw"]} )); then |  | ||||||
|             precommand_options[$arg_raw]=$precommand_options[$arg] |  | ||||||
|           fi |  | ||||||
|         fi |         fi | ||||||
|         } |         (( in_redirection++ )) # Stall this arg | ||||||
|  |         continue | ||||||
|       else |       else | ||||||
|         _zsh_highlight_main_highlighter_expand_path $arg |         _zsh_highlight_main_highlighter_expand_path $arg | ||||||
|         arg=$REPLY |         arg=$REPLY | ||||||
|         _zsh_highlight_main__type "$arg" |         _zsh_highlight_main__type "$arg" 0 | ||||||
|         res="$REPLY" |         res="$REPLY" | ||||||
|       fi |       fi | ||||||
|     fi |     fi | ||||||
| @ -635,7 +636,7 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|             arg=${(P)MATCH} |             arg=${(P)MATCH} | ||||||
|             ;; |             ;; | ||||||
|         esac |         esac | ||||||
|         _zsh_highlight_main__type "$arg" |         _zsh_highlight_main__type "$arg" 0 | ||||||
|         res=$REPLY |         res=$REPLY | ||||||
|       fi |       fi | ||||||
|     } |     } | ||||||
| @ -703,7 +704,7 @@ _zsh_highlight_main_highlighter_highlight_list() | |||||||
|      next_word=':start:' |      next_word=':start:' | ||||||
|    elif ! (( in_redirection)) && [[ $this_word == *':start:'* ]]; then # $arg is the command word |    elif ! (( in_redirection)) && [[ $this_word == *':start:'* ]]; then # $arg is the command word | ||||||
|      if (( ${+precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then |      if (( ${+precommand_options[$arg]} )) && _zsh_highlight_main__is_runnable $arg; then | ||||||
|       [[ $res != alias ]] && style=precommand |       style=precommand | ||||||
|       flags_with_argument=${precommand_options[$arg]%:*} |       flags_with_argument=${precommand_options[$arg]%:*} | ||||||
|       flags_sans_argument=${precommand_options[$arg]#*:} |       flags_sans_argument=${precommand_options[$arg]#*:} | ||||||
|       next_word=${next_word//:regular:/} |       next_word=${next_word//:regular:/} | ||||||
|  | |||||||
| @ -33,5 +33,6 @@ alias x=$'# foo\npwd' | |||||||
| BUFFER='x' | BUFFER='x' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   "1 1 alias 'interactivecomments applies to aliases'" # x becomes pwd |   '1 1 alias' # x | ||||||
|  |   '1 1 comment' # x (#) | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -33,5 +33,6 @@ alias x=$'# foo\npwd' | |||||||
| BUFFER='x' | BUFFER='x' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   "1 1 unknown-token" # x becomes # |   '1 1 alias' # x | ||||||
|  |   '1 1 unknown-token' # x (#) | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -33,7 +33,8 @@ alias a=b b=c c=b | |||||||
| BUFFER='a foo; :' | BUFFER='a foo; :' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 1 unknown-token' # a |   '1 1 alias' # a | ||||||
|  |   '1 1 unknown-token' # a (invalid alias loop) | ||||||
|   '3 5 default' # foo |   '3 5 default' # foo | ||||||
|   '6 6 commandseparator' # ; |   '6 6 commandseparator' # ; | ||||||
|   '8 8 builtin' # : |   '8 8 builtin' # : | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ BUFFER='a -u phy1729 echo; :' | |||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 1 alias' # a |   '1 1 alias' # a | ||||||
|  |   '1 1 precommand' # a (sudo) | ||||||
|   '3 4 single-hyphen-option' # -u |   '3 4 single-hyphen-option' # -u | ||||||
|   '6 12 default' # phy1729 |   '6 12 default' # phy1729 | ||||||
|   '14 17 builtin' # echo |   '14 17 builtin' # echo | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ BUFFER='a foo; :' | |||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 1 alias' # a |   '1 1 alias' # a | ||||||
|  |   '1 1 builtin' # a (:) | ||||||
|   '3 5 default' # foo |   '3 5 default' # foo | ||||||
|   '6 6 commandseparator' # ; |   '6 6 commandseparator' # ; | ||||||
|   '8 8 builtin' # : |   '8 8 builtin' # : | ||||||
|  | |||||||
| @ -35,7 +35,8 @@ BUFFER='sdu phy1729 echo foo' | |||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 3 alias' # sdu |   '1 3 alias' # sdu | ||||||
|   '5 11 default "issue #540"' # phy1729 |   '1 3 precommand' # sdu (sudo) | ||||||
|  |   '5 11 default' # phy1729 | ||||||
|   '13 16 commmand "issue #540"' # echo (not builtin) |   '13 16 commmand "issue #540"' # echo (not builtin) | ||||||
|   '18 20 default' # foo |   '18 20 default' # foo | ||||||
| ) | ) | ||||||
| @ -0,0 +1,43 @@ | |||||||
|  | #!/usr/bin/env zsh | ||||||
|  | # ------------------------------------------------------------------------------------------------- | ||||||
|  | # Copyright (c) 2018 zsh-syntax-highlighting contributors | ||||||
|  | # All rights reserved. | ||||||
|  | # | ||||||
|  | # Redistribution and use in source and binary forms, with or without modification, are permitted | ||||||
|  | # provided that the following conditions are met: | ||||||
|  | # | ||||||
|  | #  * Redistributions of source code must retain the above copyright notice, this list of conditions | ||||||
|  | #    and the following disclaimer. | ||||||
|  | #  * Redistributions in binary form must reproduce the above copyright notice, this list of | ||||||
|  | #    conditions and the following disclaimer in the documentation and/or other materials provided | ||||||
|  | #    with the distribution. | ||||||
|  | #  * Neither the name of the zsh-syntax-highlighting contributors nor the names of its contributors | ||||||
|  | #    may be used to endorse or promote products derived from this software without specific prior | ||||||
|  | #    written permission. | ||||||
|  | # | ||||||
|  | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR | ||||||
|  | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | ||||||
|  | # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR | ||||||
|  | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
|  | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||||||
|  | # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||||||
|  | # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | # ------------------------------------------------------------------------------------------------- | ||||||
|  | # -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- | ||||||
|  | # vim: ft=zsh sw=2 ts=2 et | ||||||
|  | # ------------------------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | alias sde='sudo -e' | ||||||
|  | alias seu='sde -u' | ||||||
|  | sudo(){} | ||||||
|  | 
 | ||||||
|  | BUFFER='seu phy1729 echo foo' | ||||||
|  | 
 | ||||||
|  | expected_region_highlight=( | ||||||
|  |   '1 3 alias' # seu | ||||||
|  |   '1 3 precommand' # seu (sudo) | ||||||
|  |   '5 11 default' # phy1729 | ||||||
|  |   '13 16 commmand "issue #540"' # echo (not builtin) | ||||||
|  |   '18 20 default' # foo | ||||||
|  | ) | ||||||
| @ -35,5 +35,5 @@ expected_region_highlight=( | |||||||
|   '1 3 unknown-token' # "a" |   '1 3 unknown-token' # "a" | ||||||
|   '5 7 default' # foo |   '5 7 default' # foo | ||||||
|   '8 8 commandseparator' # ; |   '8 8 commandseparator' # ; | ||||||
|   '10 12 command "issue #544' # \ls |   '10 12 command' # \ls | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -31,7 +31,8 @@ alias x=\> | |||||||
| BUFFER='x foo echo bar' | BUFFER='x foo echo bar' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 1 redirection' # x becomes > |   '1 1 alias' # x | ||||||
|  |   '1 1 redirection' # x (>) | ||||||
|   '3 5 default' # foo |   '3 5 default' # foo | ||||||
|   '7 10 builtin' # echo |   '7 10 builtin' # echo | ||||||
|   '12 14 default' # bar |   '12 14 default' # bar | ||||||
|  | |||||||
| @ -34,5 +34,6 @@ BUFFER='echo bar' | |||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 4 alias' # echo |   '1 4 alias' # echo | ||||||
|  |   '1 4 builtin' # echo | ||||||
|   '6 8 default' # bar |   '6 8 default' # bar | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -32,5 +32,6 @@ alias x=/ | |||||||
| BUFFER=$'x' | BUFFER=$'x' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   '1 1 unknown-token' # x |   '1 1 alias' # x | ||||||
|  |   '1 1 unknown-token "issue #202"' # x (/) | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -48,4 +48,5 @@ fi | |||||||
| expected_region_highlight+=( | expected_region_highlight+=( | ||||||
|   "9 9 commandseparator" # ; |   "9 9 commandseparator" # ; | ||||||
|   "11 16 alias" # alias1 |   "11 16 alias" # alias1 | ||||||
|  |   "11 16 command" # alias1 (ls) | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -32,5 +32,6 @@ BUFFER='x ls' | |||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   "1 1 alias" # x |   "1 1 alias" # x | ||||||
|  |   "1 1 precommand" # x (command) | ||||||
|   "3 4 command" # ls |   "3 4 command" # ls | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -33,8 +33,9 @@ f() {} | |||||||
| BUFFER='a;f;' | BUFFER='a;f;' | ||||||
| 
 | 
 | ||||||
| expected_region_highlight=( | expected_region_highlight=( | ||||||
|   "1 1 alias" # f |   "1 1 alias" # a | ||||||
|  |   "1 1 builtin" # a (:) | ||||||
|   "2 2 commandseparator" # ; |   "2 2 commandseparator" # ; | ||||||
|   "3 3 function" # g |   "3 3 function" # f | ||||||
|   "4 4 commandseparator" # ; |   "4 4 commandseparator" # ; | ||||||
| ) | ) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Matthew Martin
						Matthew Martin