[gtksourceview] sh.lang: Complement for parenthesized subshells
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview] sh.lang: Complement for parenthesized subshells
- Date: Fri, 22 Nov 2019 23:37:09 +0000 (UTC)
commit d47b53da58583f717835689ec88a241d73f34f76
Author: neyfag <11970-neyfag users noreply gitlab gnome org>
Date: Mon Nov 18 12:15:39 2019 +0100
sh.lang: Complement for parenthesized subshells
data/language-specs/sh.lang | 214 ++++++++++++++++++++++++++++++--------
tests/syntax-highlighting/file.sh | 9 +-
2 files changed, 179 insertions(+), 44 deletions(-)
---
diff --git a/data/language-specs/sh.lang b/data/language-specs/sh.lang
index 54461801..bfca0f93 100644
--- a/data/language-specs/sh.lang
+++ b/data/language-specs/sh.lang
@@ -42,13 +42,16 @@
<style id="subshell" name="Subshell" map-to="def:preprocessor"/>
</styles>
-<keyword-char-class>[^()`&|;]</keyword-char-class>
-
<definitions>
<define-regex id="command-name">[a-zA-Z_][a-zA-Z0-9_.-]*</define-regex>
<define-regex id="identifier">[a-zA-Z_][a-zA-Z0-9_]*</define-regex>
<define-regex id="unescaped-space">(?<!\\)\s</define-regex>
+ <define-regex id="brackets-prefix">(?<=\%{unescaped-space}|[`&|;]|^)</define-regex>
+ <define-regex id="brackets-suffix">(?=\s|[)`&|;]|$)</define-regex>
+ <define-regex id="command-suffix">(?=[)`&|;])</define-regex>
+ <define-regex id="lb">(?<=\%{unescaped-space}|[()`&|;]|^)</define-regex>
+ <define-regex id="rb">(?=\s|[()`&|;]|$)</define-regex>
<!-- we cannot use def:shell-like-comment, because
m4.lang needs to replace this context -->
@@ -71,6 +74,7 @@
<context ref="variable"/>
<context ref="backtick-subshell"/>
<context ref="command-substitution"/>
+ <context ref="arithmetic-expansion"/>
</include>
</context>
@@ -80,8 +84,8 @@
</context>
<context id="subshell" style-ref="subshell">
- <start>(?<=\%{unescaped-space}|[`&|;]|^)\((?!\()</start>
- <end>\)(?=\s|[`&|;]|$)</end>
+ <start>\%{brackets-prefix}\((?!\()</start>
+ <end>\)\%{brackets-suffix}</end>
<include>
<context sub-pattern="0" where="start" style-ref="keyword"/>
<context sub-pattern="0" where="end" style-ref="keyword"/>
@@ -99,6 +103,114 @@
</include>
</context>
+ <context id="process-substitution" style-ref="subshell">
+ <start>(?<=\%{unescaped-space}|^)[<>]\((?!\()</start>
+ <end>\)\%{brackets-suffix}</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context ref="sh"/>
+ </include>
+ </context>
+
+ <context id="reference-by-name" style-ref="variable">
+ <match>\%{identifier}</match>
+ </context>
+
+ <context id="numeral-system">
+ <include>
+ <context id="base-n-integer" style-ref="def:base-n-integer">
+ <match extended="true">
+ (?<![\w\.]) ([2-9]|[1-5][0-9]|6[0-4])\#[0-9a-zA-Z_@]+ (?![\w\.])
+ </match>
+ </context>
+ <context ref="def:hexadecimal"/>
+ <context ref="def:octal"/>
+ <context ref="def:decimal"/>
+ </include>
+ </context>
+
+ <context id="evaluation-nesting">
+ <include>
+ <context ref="def:escape"/>
+ <context ref="def:line-continue"/>
+ <context ref="single-quoted-string"/>
+ <context ref="double-quoted-string"/>
+ <context ref="backtick-subshell"/>
+ <context ref="command-substitution"/>
+ <context ref="variable"/>
+ <context ref="reference-by-name"/>
+ <context ref="numeral-system"/>
+ </include>
+ </context>
+
+ <!-- Defined like this, "precedence" also emulates the inclusion of
+ "arithmetic-evaluation" and "arithmetic-expansion" -->
+ <context id="evaluation-precedence">
+ <start>\$?\(</start>
+ <end>\)</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context ref="evaluation-nesting"/>
+ <context ref="evaluation-precedence"/>
+ </include>
+ </context>
+
+ <context id="arithmetic-evaluation">
+ <start>\%{brackets-prefix}\({2}(?!\()</start>
+ <end>\){2}\%{brackets-suffix}</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context ref="evaluation-nesting"/>
+ <context ref="evaluation-precedence"/>
+ </include>
+ </context>
+
+ <context id="arithmetic-expansion">
+ <start>\$\({2}(?!\()</start>
+ <end>\){2}</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context id="expansion-nesting">
+ <include>
+ <context ref="def:line-continue"/>
+ <context ref="double-quoted-string"/>
+ <context ref="backtick-subshell"/>
+ <context ref="command-substitution"/>
+ <context ref="variable"/>
+ <context ref="reference-by-name"/>
+ <context ref="numeral-system"/>
+ </include>
+ </context>
+ <context id="expansion-precedence">
+ <start>\$?\(</start>
+ <end>\)</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context ref="expansion-nesting"/>
+ <context ref="expansion-precedence"/>
+ </include>
+ </context>
+ </include>
+ </context>
+
+ <!-- Exclusions above in <start>/<end> tags enable highlighting only for
+ unambiguous nesting of subshells and arithmetic evaluations/expansions.
+ This covers the remainder and array definition, with default highlighting -->
+ <context id="default-subshell">
+ <start>\(</start>
+ <end>\)</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context sub-pattern="0" where="end" style-ref="keyword"/>
+ <context ref="sh"/>
+ </include>
+ </context>
+
<!-- Treated separately, not including itself nor command-like contexts
(see https://gitlab.gnome.org/GNOME/gtksourceview/issues/94) -->
<context id="backtick-subshell" style-ref="subshell">
@@ -112,6 +224,11 @@
<context ref="double-quoted-string"/>
<context ref="subshell"/>
<context ref="command-substitution"/>
+ <context ref="process-substitution"/>
+ <context ref="arithmetic-evaluation"/>
+ <context ref="arithmetic-expansion"/>
+ <!-- Must be included after all other parenthesized subshells -->
+ <context ref="default-subshell"/>
<context ref="punctuator"/>
<context ref="function"/>
<context ref="here-doc"/>
@@ -119,7 +236,9 @@
<context ref="operator"/>
<context ref="variable"/>
<context ref="stand-alone-variable-definition"/>
- <context ref="built-in-command"/>
+ <context ref="reserved-word"/>
+ <context ref="case-command"/>
+ <context ref="for-command"/>
</include>
</context>
@@ -128,7 +247,7 @@
</context>
<context id="function" style-ref="function">
- <match>(?<=\%{unescaped-space}|\%[)\%{command-name}\s*\(\)</match>
+ <match>\%{lb}\%{command-name}\s*\(\)</match>
</context>
<context id="redirection" style-ref="others">
@@ -219,6 +338,7 @@
<context ref="variable"/>
<context ref="backtick-subshell"/>
<context ref="command-substitution"/>
+ <context ref="arithmetic-expansion"/>
</include>
</context>
@@ -230,31 +350,28 @@
</context>
<context id="stand-alone-variable-definition">
- <match>(?<=\%{unescaped-space}|\%[)(\%{identifier})\+?=</match>
+ <match>\%{lb}(\%{identifier})\+?=</match>
<include>
<context sub-pattern="1" style-ref="variable-definition"/>
</include>
</context>
<context id="variable-definition-command" end-at-line-end="true">
- <start extended="true">
- (?<=\%{unescaped-space}|\%[)
- (declare|local|typeset|readonly|export)
- (?=\s|\%])
- </start>
- <end>\%]</end>
+ <start>\%{lb}(declare|local|typeset|readonly|export)\%{rb}</start>
+ <end>\%{command-suffix}</end>
<include>
<context sub-pattern="0" where="start" style-ref="keyword"/>
- <context sub-pattern="0" where="end" style-ref="keyword"/>
<context ref="def:escape"/>
<context ref="def:line-continue"/>
<context ref="line-comment"/>
<context ref="single-quoted-string"/>
<context ref="double-quoted-string"/>
- <context ref="here-doc"/>
<context ref="redirection"/>
<context ref="backtick-subshell"/>
<context ref="command-substitution"/>
+ <context ref="arithmetic-expansion"/>
+ <!-- Must be included after all other parenthesized subshells -->
+ <context ref="default-subshell"/>
<context ref="variable"/>
<context style-ref="variable-definition">
<match>(?<=\%{unescaped-space})\%{identifier}</match>
@@ -269,20 +386,15 @@
</include>
</context>
- <context id="built-in-command-1" style-ref="keyword">
- <prefix>(?<=\%{unescaped-space}|\%[)</prefix>
- <suffix>(?=\s|\%])</suffix>
+ <!-- To prevent conflicts, keywords below should be removed from the list
+ before being used in any container context -->
+ <context id="reserved-word" style-ref="keyword">
+ <prefix>\%{lb}</prefix>
+ <suffix>\%{rb}</suffix>
<keyword>\!</keyword>
<keyword>\{</keyword>
<keyword>\}</keyword>
<keyword>\:</keyword>
- </context>
-
- <!-- To prevent conflicts, keywords below should be removed from the list
- before being used in any container context -->
- <context id="built-in-command-2" style-ref="keyword">
- <prefix>(?<=\%{unescaped-space}|\%[)</prefix>
- <suffix>(?=\s|\%])</suffix>
<keyword>do</keyword>
<keyword>done</keyword>
<keyword>elif</keyword>
@@ -300,14 +412,14 @@
</context>
<context id="case-command">
- <start>(?<=\%{unescaped-space}|\%[)case(?=\s)</start>
+ <start>\%{lb}case(?=\s)</start>
<include>
<context sub-pattern="0" where="start" style-ref="keyword"/>
<!-- Must be included before any reference context
(replaces <end> tag, to enforce priority) -->
<context style-ref="keyword" end-parent="true">
- <prefix>(?<=\%{unescaped-space}|\%[)</prefix>
- <suffix>(?=\s|\%])</suffix>
+ <prefix>\%{lb}</prefix>
+ <suffix>\%{rb}</suffix>
<keyword>esac</keyword>
</context>
<context ref="sh"/>
@@ -315,7 +427,7 @@
</context>
<context id="for-command" end-at-line-end="true">
- <start>(?<=\%{unescaped-space}|\%[)for(?=\s)</start>
+ <start>\%{lb}for(?=\s)</start>
<end>(?=\S)</end>
<include>
<context sub-pattern="0" where="start" style-ref="keyword"/>
@@ -326,21 +438,33 @@
</include>
</context>
+ <context id="let-command" end-at-line-end="true">
+ <start>\%{lb}let(?=\s)</start>
+ <end>\%{command-suffix}</end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="keyword"/>
+ <context ref="line-comment"/>
+ <context ref="redirection"/>
+ <context ref="evaluation-nesting"/>
+ <context ref="evaluation-precedence"/>
+ </include>
+ </context>
+
<context id="built-in-command">
<include>
- <context ref="built-in-command-1"/>
- <context ref="built-in-command-2"/>
+ <context ref="reserved-word"/>
<context ref="case-command"/>
<context ref="for-command"/>
+ <context ref="let-command"/>
</include>
</context>
<context id="generic-command" end-at-line-end="true">
- <start extended="true">
- (?<=\%{unescaped-space}|\%[)
- (?=\%{command-name}(\s|\%]))
- </start>
- <end>(?=[)`&|;])</end>
+ <start>\%{lb}(?=\%{command-name}\%{rb})</start>
+ <!-- \%{command-suffix} + '(', to prevent false positives in ambiguous
+ nesting of subshells and arithmetic evaluations/expansions,
+ like (((a-(b+c)))) -->
+ <end>\%{command-suffix}|(?=\()</end>
<include>
<!-- Must be included first -->
<context once-only="true">
@@ -348,7 +472,7 @@
<include>
<context style-ref="keyword" end-parent="true">
<prefix></prefix>
- <suffix></suffix>
+ <suffix>\%{rb}</suffix>
<keyword>\.</keyword>
<keyword>alias</keyword>
<keyword>bg</keyword>
@@ -374,7 +498,6 @@
<keyword>help</keyword>
<keyword>history</keyword>
<keyword>jobs</keyword>
- <keyword>let</keyword>
<keyword>logout</keyword>
<keyword>popd</keyword>
<keyword>printf</keyword>
@@ -396,7 +519,7 @@
</context>
<context style-ref="common-command" end-parent="true">
<prefix></prefix>
- <suffix></suffix>
+ <suffix>\%{rb}</suffix>
<keyword>ar</keyword>
<keyword>awk</keyword>
<keyword>basename</keyword>
@@ -573,10 +696,12 @@
<context ref="line-comment"/>
<context ref="single-quoted-string"/>
<context ref="double-quoted-string"/>
- <context ref="here-doc"/>
- <context ref="redirection"/>
<context ref="backtick-subshell"/>
<context ref="command-substitution"/>
+ <context ref="process-substitution"/>
+ <context ref="arithmetic-expansion"/>
+ <context ref="here-doc"/>
+ <context ref="redirection"/>
<context ref="variable"/>
</include>
</context>
@@ -589,9 +714,14 @@
<context ref="def:escape"/>
<context ref="single-quoted-string"/>
<context ref="double-quoted-string"/>
- <context ref="subshell"/>
<context ref="backtick-subshell"/>
+ <context ref="subshell"/>
<context ref="command-substitution"/>
+ <context ref="process-substitution"/>
+ <context ref="arithmetic-evaluation"/>
+ <context ref="arithmetic-expansion"/>
+ <!-- Must be included after all other parenthesized subshells -->
+ <context ref="default-subshell"/>
<context ref="punctuator"/>
<context ref="function"/>
<context ref="here-doc"/>
diff --git a/tests/syntax-highlighting/file.sh b/tests/syntax-highlighting/file.sh
index 6361c083..8a1529e0 100644
--- a/tests/syntax-highlighting/file.sh
+++ b/tests/syntax-highlighting/file.sh
@@ -41,7 +41,7 @@ if var=$(cmd); then some; fi
test -f xxx && var=xxx || var=yyy
echo text | var=xxx cmd & var=yyy
declare -i '-r' "-x" var1=val1 var2=$val1 var3=`cmd1` \
- var4=$(cmd2) var5=xxx\ yyy var6 # Comment
+ var4=$(cmd2) var5=xxx\ yyy var6=("${ar[@]}") var7 # Comment
var+=xxx; (var=yyy); { var=zzz; }
case $1 in
item) var=xxx;;
@@ -60,7 +60,7 @@ arg; do echo $arg; done
# Generic command (e.g. echo)
echo for case grep $var ${var/x/y} $(cmd) `cmd` \
- 'a' "b" \\ | grep 'pattern'
+ 'a' "b" \\ | grep 'pattern' > >(tee file)
echo echo; echo echo & echo echo
echo
@@ -73,3 +73,8 @@ echo
'no special characters'
"$var, ${var/x/y}, $(cmd), `cmd`, \
\$, \`, \", \\, \ "
+
+# Arithmetic evaluation/expansion
+var1=$((var2+2#101+$(cmd)+($var3+ \
+ "$var4")/0x1f))
+let var1='1'+010-23+`cmd`+var2 # Comment
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]