zsh-users / zsh-syntax-highlighting

Fish shell like syntax highlighting for Zsh.
github.com/zsh-users/zsh-syntax-highlighting
BSD 3-Clause "New" or "Revised" License
19.5k stars 1.32k forks source link

Missing highlight for "&>" (redirection of both stdout and stderr) #942

Closed zhouyc98 closed 6 months ago

zhouyc98 commented 6 months ago

The &> in echo hello &> tmp cannot be highlighted.

I have enabled the main highlighter, and set both named-fd and numeric-fd styles. In my case, ">" and "1>" can be highlighted as expected, while "&>" cannot.

Note that from the bash man page:

There  are  two  formats  for  redirecting standard output and standard
   error:

          &>word
   and
          >&word

   Of the two forms, the first is preferred.  This is semantically equiva-
   lent to

          >word 2>&1
danielshahaf commented 6 months ago

It should be highlighted using the 'redirection' style—unsurprisingly, as it's neither a named fd ({foo}>) nor a numeric one (4>).

And you really should be referring to the zsh man pages: https://github.com/zsh-users/zsh/blob/a528af5c57436c730144e35d97547163c57c8420/Etc/FAQ.yo#L910-L968

The easiest way to determine what style something is highlighted by is... to use tests/generate.zsh, I suppose.

zhouyc98 commented 6 months ago

@danielshahaf Thanks. Yes, I agree that it should be highlighted by the 'redirection' style (and thus enabled by default).
I read the zsh man page and find that &> also means redirection both like bash (https://zsh.sourceforge.io/Doc/Release/Redirection.html).

phy1729 commented 6 months ago

Rather than say a redirection starts with a > or < and then excluding process substitutions and globs, I think we can just match on the tokens listed in zshmisc.

diff --git a/highlighters/main/main-highlighter.zsh b/highlighters/main/main-highlighter.zsh
index 54938b7..b218bea 100644
--- a/highlighters/main/main-highlighter.zsh
+++ b/highlighters/main/main-highlighter.zsh
@@ -254,10 +254,8 @@ _zsh_highlight_main__is_runnable() {
 _zsh_highlight_main__is_redirection() {
   # A redirection operator token:
   # - starts with an optional single-digit number;
-  # - then, has a '<' or '>' character;
-  # - is not a process substitution [<(...) or >(...)].
-  # - is not a numeric glob <->
-  [[ $1 == (<0-9>|)(\<|\>)* ]] && [[ $1 != (\<|\>)$'\x28'* ]] && [[ $1 != *'<'*'-'*'>'* ]]
+  # - is one of the tokens listed in zshmisc(1)
+  [[ ${1#[0-9]} == (\<|\<\>|(\>|\>\>)(|\||\!)|\<\<(|-)|\<\<\<|\<\&|\&\<|(\>|\>\>)\&(|\||\!)|\&(\>|\>\>)(|\||\!)) ]]
 }

 # Resolve alias.
diff --git a/highlighters/main/test-data/redirection-all.zsh b/highlighters/main/test-data/redirection-all.zsh
index 126d6e5..e8ffb5d 100644
--- a/highlighters/main/test-data/redirection-all.zsh
+++ b/highlighters/main/test-data/redirection-all.zsh
@@ -28,3 +28,68 @@
 # vim: ft=zsh sw=2 ts=2 et
 # -------------------------------------------------------------------------------------------------

+BUFFER=$': <foo 9<foo <>foo 9<>foo >foo 9>foo >|foo >\!foo >>foo >>|foo >>\!foo <<<foo <&9 >&9 <&- >&- <&p >&p >&foo &>foo >&|foo >&\!foo &>|foo &>\!foo >>&foo &>>foo >>&|foo >>&\!foo &>>|foo &>>\!foo'
+
+expected_region_highlight=(
+  '1 1 builtin' # :
+  '3 3 redirection' # <
+  '4 6 default' # foo
+  '8 9 redirection' # 9<
+  '10 12 default' # foo
+  '14 15 redirection' # <>
+  '16 18 default' # foo
+  '20 22 redirection' # 9<>
+  '23 25 default' # foo
+  '27 27 redirection' # >
+  '28 30 default' # foo
+  '32 33 redirection' # 9>
+  '34 36 default' # foo
+  '38 39 redirection' # >|
+  '40 42 default' # foo
+  '44 45 redirection' # >\!
+  '46 48 default' # foo
+  '50 51 redirection' # >>
+  '52 54 default' # foo
+  '56 58 redirection' # >>|
+  '59 61 default' # foo
+  '63 65 redirection' # >>\!
+  '66 68 default' # foo
+  '70 72 redirection' # <<<
+  '73 75 default' # foo
+  '77 78 redirection' # <&
+  '79 79 numeric-fd' # 9
+  '81 82 redirection' # >&
+  '83 83 numeric-fd' # 9
+  '85 86 redirection' # <&
+  '87 87 redirection' # -
+  '89 90 redirection' # >&
+  '91 91 redirection' # -
+  '93 94 redirection' # <&
+  '95 95 redirection' # p
+  '97 98 redirection' # >&
+  '99 99 redirection' # p
+  '101 102 redirection' # >&
+  '103 105 default' # foo
+  '107 108 redirection' # &>
+  '109 111 default' # foo
+  '113 115 redirection' # >&|
+  '116 118 default' # foo
+  '120 122 redirection' # >&\!
+  '123 125 default' # foo
+  '127 129 redirection' # &>|
+  '130 132 default' # foo
+  '134 136 redirection' # &>\!
+  '137 139 default' # foo
+  '141 143 redirection' # >>&
+  '144 146 default' # foo
+  '148 150 redirection' # &>>
+  '151 153 default' # foo
+  '155 158 redirection' # >>&|
+  '159 161 default' # foo
+  '163 166 redirection' # >>&\!
+  '167 169 default' # foo
+  '171 174 redirection' # &>>|
+  '175 177 default' # foo
+  '179 182 redirection' # &>>\!
+  '183 185 default' # foo
+)
danielshahaf commented 6 months ago

To be clear, are you requesting/proposing that the 'redirection' style ought to have a different default value?

zhouyc98 commented 6 months ago

To be clear, are you requesting/proposing that the 'redirection' style ought to have a different default value?

No. I just want "&>" to be highlighted like ">" or "<". I personally don't care the default style for different redirection.

danielshahaf commented 6 months ago

@phy1729 Sounds good.

IIRC, ${(z):-'>!'} is '>|'. (I figure you remember this; just stating it for completeness.)

danielshahaf commented 6 months ago

To be clear, are you requesting/proposing that the 'redirection' style ought to have a different default value?

No. I just want "&>" to be highlighted like ">" or "<". I personally don't care the default style for different redirection.

Ah, so you're saying '&>' should be highlighted as 'redirection' rather than 'default'? +1. (And if someone in the future asks to highlight different redirection operators differently, we can deal with that then.)

zhouyc98 commented 6 months ago

@danielshahaf Yes. IIRC, 'redirection' style is fg=yellow while 'default' is none. I want '&>' to be highlighted as fg=yellow.

phy1729 commented 6 months ago

Fixed in e0165ea.