This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new b371c0646d add support for sh and cmd files to the text editor, fixes 
#7640 (#7645)
b371c0646d is described below

commit b371c0646d77a5644c96cd322a4b58622a1ddf97
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Mon Jul 27 17:20:13 2026 +0200

    add support for sh and cmd files to the text editor, fixes #7640 (#7645)
---
 .../transforms/types/BatExplorerFileType.java      |    6 +-
 .../types/BatExplorerFileTypeHandler.java          |   40 +
 ...lorerFileType.java => CmdExplorerFileType.java} |   22 +-
 .../transforms/types/ShellExplorerFileType.java    |    6 +-
 .../types/ShellExplorerFileTypeHandler.java        |   37 +
 .../transforms/types/CmdExplorerFileTypeTest.java  |   92 +
 .../org/apache/hop/ui/hopgui/monaco-editor.js      |    6 +
 .../hop/ui/hopgui/ContentEditorTm4eSupport.java    |   12 +-
 .../hopgui/RuleBasedSourceViewerConfiguration.java |    3 +-
 .../org/apache/hop/ui/hopgui/grammars/bat.json     |  788 +++++++
 .../org/apache/hop/ui/hopgui/grammars/shell.json   | 2353 ++++++++++++++++++++
 .../ui/hopgui/ContentEditorTm4eSupportTest.java    |  114 +
 12 files changed, 3460 insertions(+), 19 deletions(-)

diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
index e897142597..a60a687c30 100644
--- 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
@@ -34,7 +34,7 @@ import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExp
     name = "Windows Batch File Type",
     description = "Batch file handling in the explorer perspective",
     image = "ui/images/script.svg")
-public class BatExplorerFileType extends 
BaseTextExplorerFileType<TextExplorerFileTypeHandler> {
+public class BatExplorerFileType extends 
BaseTextExplorerFileType<BatExplorerFileTypeHandler> {
 
   public BatExplorerFileType() {
     super(
@@ -54,9 +54,9 @@ public class BatExplorerFileType extends 
BaseTextExplorerFileType<TextExplorerFi
   }
 
   @Override
-  public TextExplorerFileTypeHandler createFileTypeHandler(
+  public BatExplorerFileTypeHandler createFileTypeHandler(
       HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
-    return new TextExplorerFileTypeHandler(hopGui, perspective, file);
+    return new BatExplorerFileTypeHandler(hopGui, perspective, file);
   }
 
   @Override
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileTypeHandler.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileTypeHandler.java
new file mode 100644
index 0000000000..e1fdded62d
--- /dev/null
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileTypeHandler.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.types;
+
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExplorerFileTypeHandler;
+
+/**
+ * Handler for Windows batch and command files (.bat / .cmd) in the file 
explorer perspective
+ * (syntax-highlighted edit). Both extensions are the same language, mapped to 
the "bat" grammar.
+ */
+public class BatExplorerFileTypeHandler extends 
BaseTextExplorerFileTypeHandler {
+
+  public BatExplorerFileTypeHandler(
+      HopGui hopGui, ExplorerPerspective perspective, ExplorerFile 
explorerFile) {
+    super(hopGui, perspective, explorerFile);
+  }
+
+  @Override
+  protected String getLanguageId() {
+    return "bat";
+  }
+}
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileType.java
similarity index 81%
copy from 
plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
copy to 
plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileType.java
index e897142597..ae14188dea 100644
--- 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/BatExplorerFileType.java
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileType.java
@@ -30,18 +30,18 @@ import 
org.apache.hop.ui.hopgui.perspective.explorer.file.capabilities.FileTypeC
 import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExplorerFileType;
 
 @HopFileTypePlugin(
-    id = "BatExplorerFileType",
-    name = "Windows Batch File Type",
-    description = "Batch file handling in the explorer perspective",
+    id = "CmdExplorerFileType",
+    name = "Windows Command File Type",
+    description = "Windows command file handling in the explorer perspective",
     image = "ui/images/script.svg")
-public class BatExplorerFileType extends 
BaseTextExplorerFileType<TextExplorerFileTypeHandler> {
+public class CmdExplorerFileType extends 
BaseTextExplorerFileType<BatExplorerFileTypeHandler> {
 
-  public BatExplorerFileType() {
+  public CmdExplorerFileType() {
     super(
-        "Batch file",
-        ".bat",
-        new String[] {"*.bat", "*.BAT"},
-        new String[] {"Batch files"},
+        "Command file",
+        ".cmd",
+        new String[] {"*.cmd", "*.CMD"},
+        new String[] {"Command files"},
         FileTypeCapabilities.getCapabilities(
             IHopFileType.CAPABILITY_SAVE,
             IHopFileType.CAPABILITY_SAVE_AS,
@@ -54,9 +54,9 @@ public class BatExplorerFileType extends 
BaseTextExplorerFileType<TextExplorerFi
   }
 
   @Override
-  public TextExplorerFileTypeHandler createFileTypeHandler(
+  public BatExplorerFileTypeHandler createFileTypeHandler(
       HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
-    return new TextExplorerFileTypeHandler(hopGui, perspective, file);
+    return new BatExplorerFileTypeHandler(hopGui, perspective, file);
   }
 
   @Override
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileType.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileType.java
index c8ecd00dd0..7493c3670f 100644
--- 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileType.java
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileType.java
@@ -34,7 +34,7 @@ import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExp
     name = "Shell File Type",
     description = "Shell file handling in the explorer perspective",
     image = "ui/images/script.svg")
-public class ShellExplorerFileType extends 
BaseTextExplorerFileType<TextExplorerFileTypeHandler> {
+public class ShellExplorerFileType extends 
BaseTextExplorerFileType<ShellExplorerFileTypeHandler> {
 
   public ShellExplorerFileType() {
     super(
@@ -54,9 +54,9 @@ public class ShellExplorerFileType extends 
BaseTextExplorerFileType<TextExplorer
   }
 
   @Override
-  public TextExplorerFileTypeHandler createFileTypeHandler(
+  public ShellExplorerFileTypeHandler createFileTypeHandler(
       HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
-    return new TextExplorerFileTypeHandler(hopGui, perspective, file);
+    return new ShellExplorerFileTypeHandler(hopGui, perspective, file);
   }
 
   @Override
diff --git 
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileTypeHandler.java
 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileTypeHandler.java
new file mode 100644
index 0000000000..fe250cb91a
--- /dev/null
+++ 
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/ShellExplorerFileTypeHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.types;
+
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExplorerFileTypeHandler;
+
+/** Handler for shell script files in the file explorer perspective 
(syntax-highlighted edit). */
+public class ShellExplorerFileTypeHandler extends 
BaseTextExplorerFileTypeHandler {
+
+  public ShellExplorerFileTypeHandler(
+      HopGui hopGui, ExplorerPerspective perspective, ExplorerFile 
explorerFile) {
+    super(hopGui, perspective, explorerFile);
+  }
+
+  @Override
+  protected String getLanguageId() {
+    return "shell";
+  }
+}
diff --git 
a/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileTypeTest.java
 
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileTypeTest.java
new file mode 100644
index 0000000000..562b830ffc
--- /dev/null
+++ 
b/plugins/transforms/textfile/src/test/java/org/apache/hop/pipeline/transforms/types/CmdExplorerFileTypeTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.types;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Method;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import 
org.apache.hop.ui.hopgui.perspective.explorer.file.types.text.BaseTextExplorerFileTypeHandler;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class CmdExplorerFileTypeTest {
+
+  private CmdExplorerFileType fileType;
+
+  @BeforeEach
+  void setUp() {
+    fileType = new CmdExplorerFileType();
+  }
+
+  @Test
+  void testConstructor() {
+    assertNotNull(fileType);
+  }
+
+  @Test
+  void testGetDefaultFileExtension() {
+    assertEquals(".cmd", fileType.getDefaultFileExtension());
+  }
+
+  @Test
+  void testGetFilterExtensions() {
+    String[] extensions = fileType.getFilterExtensions();
+    assertNotNull(extensions);
+    assertEquals(2, extensions.length);
+    assertEquals("*.cmd", extensions[0]);
+    assertEquals("*.CMD", extensions[1]);
+  }
+
+  @Test
+  void testGetFilterNames() {
+    String[] names = fileType.getFilterNames();
+    assertNotNull(names);
+    assertEquals(1, names.length);
+    assertEquals("Command files", names[0]);
+  }
+
+  @Test
+  void testHasExpectedCapabilities() {
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_SAVE));
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_SAVE_AS));
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_CLOSE));
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_FILE_HISTORY));
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_COPY));
+    assertTrue(fileType.hasCapability(IHopFileType.CAPABILITY_SELECT));
+    assertFalse(fileType.hasCapability(IHopFileType.CAPABILITY_NEW));
+  }
+
+  @Test
+  void testCreateFileTypeHandlerReturnsBatHandler() {
+    assertInstanceOf(
+        BatExplorerFileTypeHandler.class, fileType.createFileTypeHandler(null, 
null, null));
+  }
+
+  @Test
+  void testHandlerReturnsBatLanguageId() throws Exception {
+    BatExplorerFileTypeHandler handler = new BatExplorerFileTypeHandler(null, 
null, null);
+    Method method = 
BaseTextExplorerFileTypeHandler.class.getDeclaredMethod("getLanguageId");
+    method.setAccessible(true);
+    assertEquals("bat", method.invoke(handler));
+  }
+}
diff --git a/rap/src/main/resources/org/apache/hop/ui/hopgui/monaco-editor.js 
b/rap/src/main/resources/org/apache/hop/ui/hopgui/monaco-editor.js
index 61e8e87a4e..9c463327f2 100644
--- a/rap/src/main/resources/org/apache/hop/ui/hopgui/monaco-editor.js
+++ b/rap/src/main/resources/org/apache/hop/ui/hopgui/monaco-editor.js
@@ -48,6 +48,12 @@
       sql: "sql",
       python: "python",
       py: "python",
+      shell: "shell",
+      bash: "shell",
+      sh: "shell",
+      bat: "bat",
+      cmd: "bat",
+      batch: "bat",
       yaml: "yaml",
       yml: "yaml",
       properties: "ini"
diff --git 
a/rcp/src/main/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupport.java 
b/rcp/src/main/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupport.java
index 89a348063f..fc2ec902f5 100644
--- a/rcp/src/main/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupport.java
+++ b/rcp/src/main/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupport.java
@@ -55,6 +55,8 @@ final class ContentEditorTm4eSupport {
   private static final String SCOPE_SQL = "source.sql";
   private static final String SCOPE_PYTHON = "source.python";
   private static final String SCOPE_YAML = "source.yaml";
+  private static final String SCOPE_SHELL = "source.shell";
+  private static final String SCOPE_BATCH = "source.batchfile";
 
   /** Maps TM4E scope names to grammar resource filenames (classpath-relative 
to grammars/). */
   private static final Map<String, String> GRAMMAR_FILES =
@@ -63,7 +65,9 @@ final class ContentEditorTm4eSupport {
           SCOPE_XML, "xml.json",
           SCOPE_SQL, "sql.json",
           SCOPE_PYTHON, "python.json",
-          SCOPE_YAML, "yaml.json");
+          SCOPE_YAML, "yaml.json",
+          SCOPE_SHELL, "shell.json",
+          SCOPE_BATCH, "bat.json");
 
   // Same palette as before (light/dark) for consistency
   private static final RGB L_COMMENT = new RGB(128, 128, 128);
@@ -114,6 +118,8 @@ final class ContentEditorTm4eSupport {
       case "sql" -> SCOPE_SQL;
       case "python", "py" -> SCOPE_PYTHON;
       case "yaml", "yml" -> SCOPE_YAML;
+      case "shell", "bash", "sh" -> SCOPE_SHELL;
+      case "bat", "cmd", "batch" -> SCOPE_BATCH;
       default -> null;
     };
   }
@@ -269,6 +275,10 @@ final class ContentEditorTm4eSupport {
       return dark ? D_KEYWORD : L_KEYWORD;
     }
 
+    // Variables ($VAR in shell, %VAR% in batch): VS Code renders these in the 
same light blue as
+    // JSON keys. Checked after string so interpolation inside a string stays 
string-colored.
+    if (scope.contains("variable")) return dark ? D_JSON_KEY : L_JSON_KEY;
+
     // XML: <? ?> then tags then attribute names
     if (scope.contains("meta.tag.preprocessor")) {
       return dark ? D_XML_HEADER : L_XML_HEADER;
diff --git 
a/rcp/src/main/java/org/apache/hop/ui/hopgui/RuleBasedSourceViewerConfiguration.java
 
b/rcp/src/main/java/org/apache/hop/ui/hopgui/RuleBasedSourceViewerConfiguration.java
index 123ede5fc3..bda9e9a047 100644
--- 
a/rcp/src/main/java/org/apache/hop/ui/hopgui/RuleBasedSourceViewerConfiguration.java
+++ 
b/rcp/src/main/java/org/apache/hop/ui/hopgui/RuleBasedSourceViewerConfiguration.java
@@ -31,7 +31,8 @@ public final class RuleBasedSourceViewerConfiguration {
 
   /**
    * Creates a configuration for the given language. Uses TM4E when a grammar 
is available (json,
-   * xml, sql, python, yaml); otherwise returns a plain configuration with no 
syntax highlighting.
+   * xml, sql, python, yaml, shell, bat); otherwise returns a plain 
configuration with no syntax
+   * highlighting.
    *
    * @param languageId language id (e.g. "json", "xml", "sql", "yaml"), or 
null for plain text
    * @return configuration, never null
diff --git a/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/bat.json 
b/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/bat.json
new file mode 100644
index 0000000000..85e03dbc85
--- /dev/null
+++ b/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/bat.json
@@ -0,0 +1,788 @@
+{
+       "information_for_contributors": [
+               "This file has been converted from 
https://github.com/mmims/language-batchfile/blob/master/grammars/batchfile.cson";,
+               "If you want to provide a fix or improvement, please create a 
pull request against the original repository.",
+               "Once accepted there, we are happy to receive an update 
request."
+       ],
+       "version": 
"https://github.com/mmims/language-batchfile/commit/6154ae25a24e01ac9329e7bcf958e093cd8733a9";,
+       "name": "Batch File",
+       "scopeName": "source.batchfile",
+       "injections": {
+               "L:meta.block.repeat.batchfile": {
+                       "patterns": [
+                               {
+                                       "include": "#repeatParameter"
+                               }
+                       ]
+               }
+       },
+       "patterns": [
+               {
+                       "include": "#commands"
+               },
+               {
+                       "include": "#comments"
+               },
+               {
+                       "include": "#constants"
+               },
+               {
+                       "include": "#controls"
+               },
+               {
+                       "include": "#escaped_characters"
+               },
+               {
+                       "include": "#labels"
+               },
+               {
+                       "include": "#numbers"
+               },
+               {
+                       "include": "#operators"
+               },
+               {
+                       "include": "#parens"
+               },
+               {
+                       "include": "#strings"
+               },
+               {
+                       "include": "#variables"
+               }
+       ],
+       "repository": {
+               "commands": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|d
 [...]
+                                       "name": "keyword.command.batchfile"
+                               },
+                               {
+                                       "begin": 
"(?i)(?<=^|[\\s@])(echo)(?:(?=$|\\.|:)|\\s+(?:(on|off)(?=\\s*$))?)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.command.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.other.special-method.batchfile"
+                                               }
+                                       },
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#escaped_characters"
+                                               },
+                                               {
+                                                       "include": "#variables"
+                                               },
+                                               {
+                                                       "include": "#numbers"
+                                               },
+                                               {
+                                                       "include": "#strings"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "match": 
"(?i)(?<=^|[\\s@])(setlocal)(?:\\s*$|\\s+(EnableExtensions|DisableExtensions|EnableDelayedExpansion|DisableDelayedExpansion)(?=\\s*$))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"keyword.command.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.other.special-method.batchfile"
+                                               }
+                                       }
+                               },
+                               {
+                                       "include": "#command_set"
+                               }
+                       ]
+               },
+               "command_set": {
+                       "patterns": [
+                               {
+                                       "begin": 
"(?<=^|[\\s@])(?i:SET)(?=$|\\s)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.command.batchfile"
+                                               }
+                                       },
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#command_set_inside"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "command_set_inside": {
+                       "patterns": [
+                               {
+                                       "include": "#escaped_characters"
+                               },
+                               {
+                                       "include": "#variables"
+                               },
+                               {
+                                       "include": "#numbers"
+                               },
+                               {
+                                       "include": "#parens"
+                               },
+                               {
+                                       "include": "#command_set_strings"
+                               },
+                               {
+                                       "include": "#strings"
+                               },
+                               {
+                                       "begin": "([^ ][^=]*)(=)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"variable.other.readwrite.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.operator.assignment.batchfile"
+                                               }
+                                       },
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#escaped_characters"
+                                               },
+                                               {
+                                                       "include": "#variables"
+                                               },
+                                               {
+                                                       "include": "#numbers"
+                                               },
+                                               {
+                                                       "include": "#parens"
+                                               },
+                                               {
+                                                       "include": "#strings"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "\\s+/[aA]\\s+",
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "name": "meta.expression.set.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "begin": "\"",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.definition.string.begin.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "\"",
+                                                       "endCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.definition.string.end.batchfile"
+                                                               }
+                                                       },
+                                                       "name": 
"string.quoted.double.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#command_set_inside_arithmetic"
+                                                               },
+                                                               {
+                                                                       
"include": "#command_set_group"
+                                                               },
+                                                               {
+                                                                       
"include": "#variables"
+                                                               }
+                                                       ]
+                                               },
+                                               {
+                                                       "include": 
"#command_set_inside_arithmetic"
+                                               },
+                                               {
+                                                       "include": 
"#command_set_group"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "\\s+/[pP]\\s+",
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#command_set_strings"
+                                               },
+                                               {
+                                                       "begin": "([^ 
][^=]*)(=)",
+                                                       "beginCaptures": {
+                                                               "1": {
+                                                                       "name": 
"variable.other.readwrite.batchfile"
+                                                               },
+                                                               "2": {
+                                                                       "name": 
"keyword.operator.assignment.batchfile"
+                                                               }
+                                                       },
+                                                       "end": 
"(?=$\\n|[&|><)])",
+                                                       "name": 
"meta.prompt.set.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#strings"
+                                                               }
+                                                       ]
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "command_set_group": {
+                       "patterns": [
+                               {
+                                       "begin": "\\(",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.group.begin.batchfile"
+                                               }
+                                       },
+                                       "end": "\\)",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.group.end.batchfile"
+                                               }
+                                       },
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#command_set_inside_arithmetic"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "command_set_inside_arithmetic": {
+                       "patterns": [
+                               {
+                                       "include": "#command_set_operators"
+                               },
+                               {
+                                       "include": "#numbers"
+                               },
+                               {
+                                       "match": ",",
+                                       "name": 
"punctuation.separator.batchfile"
+                               }
+                       ]
+               },
+               "command_set_operators": {
+                       "patterns": [
+                               {
+                                       "match": "([^ 
]*)(\\+\\=|\\-\\=|\\*\\=|\\/\\=|%%\\=|&\\=|\\|\\=|\\^\\=|<<\\=|>>\\=)",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"variable.other.readwrite.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.operator.assignment.augmented.batchfile"
+                                               }
+                                       }
+                               },
+                               {
+                                       "match": 
"\\+|\\-|/|\\*|%%|\\||&|\\^|<<|>>|~",
+                                       "name": 
"keyword.operator.arithmetic.batchfile"
+                               },
+                               {
+                                       "match": "!",
+                                       "name": 
"keyword.operator.logical.batchfile"
+                               },
+                               {
+                                       "match": "([^ =]*)(=)",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"variable.other.readwrite.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.operator.assignment.batchfile"
+                                               }
+                                       }
+                               }
+                       ]
+               },
+               "command_set_strings": {
+                       "patterns": [
+                               {
+                                       "begin": "(\")\\s*([^ ][^=]*)(=)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.string.begin.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.other.readwrite.batchfile"
+                                               },
+                                               "3": {
+                                                       "name": 
"keyword.operator.assignment.batchfile"
+                                               }
+                                       },
+                                       "end": "\"",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.end.batchfile"
+                                               }
+                                       },
+                                       "name": 
"string.quoted.double.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "include": "#variables"
+                                               },
+                                               {
+                                                       "include": "#numbers"
+                                               },
+                                               {
+                                                       "include": 
"#escaped_characters"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "comments": {
+                       "patterns": [
+                               {
+                                       "begin": "(?:^|(&))\\s*(?=((?::[+=,;: 
])))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.conditional.batchfile"
+                                               }
+                                       },
+                                       "end": "\\n",
+                                       "patterns": [
+                                               {
+                                                       "begin": "((?::[+=,;: 
]))",
+                                                       "beginCaptures": {
+                                                               "1": {
+                                                                       "name": 
"punctuation.definition.comment.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "(?=\\n)",
+                                                       "name": 
"comment.line.colon.batchfile"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(?<=^|[\\s@])(?i)(REM)(\\.)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.command.rem.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.separator.batchfile"
+                                               }
+                                       },
+                                       "end": "(?=$\\n|[&|><)])",
+                                       "name": "comment.line.rem.batchfile"
+                               },
+                               {
+                                       "begin": "(?<=^|[\\s@])(?i:rem)\\b",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.command.rem.batchfile"
+                                               }
+                                       },
+                                       "end": "\\n",
+                                       "name": "comment.line.rem.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "match": "[><|]",
+                                                       "name": 
"invalid.illegal.unexpected-character.batchfile"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "constants": {
+                       "patterns": [
+                               {
+                                       "match": "\\b(?i:NUL)\\b",
+                                       "name": "constant.language.batchfile"
+                               }
+                       ]
+               },
+               "controls": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?i)(?<=^|\\s)(?:call|exit(?=$|\\s)|goto(?=$|\\s|:))",
+                                       "name": 
"keyword.control.statement.batchfile"
+                               },
+                               {
+                                       "match": 
"(?<=^|\\s)(?i)(if)\\s+(?:(not)\\s+)?(exist|defined|errorlevel|cmdextversion)(?=\\s)",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.conditional.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.operator.logical.batchfile"
+                                               },
+                                               "3": {
+                                                       "name": 
"keyword.other.special-method.batchfile"
+                                               }
+                                       }
+                               },
+                               {
+                                       "match": 
"(?<=^|\\s)(?i)(?:if|else)(?=$|\\s)",
+                                       "name": 
"keyword.control.conditional.batchfile"
+                               },
+                               {
+                                       "begin": 
"(?<=^|[\\s(&^])(?i)for(?=\\s)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.control.repeat.batchfile"
+                                               }
+                                       },
+                                       "name": "meta.block.repeat.batchfile",
+                                       "end": "\\n",
+                                       "patterns": [
+                                               {
+                                                       "begin": 
"(?<=[\\s^])(?i)in(?=\\s)",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"keyword.control.repeat.in.batchfile"
+                                                               }
+                                                       },
+                                                       "end": 
"(?<=[\\s)^])(?i)do(?=\\s)|\\n",
+                                                       "endCaptures": {
+                                                               "0": {
+                                                                       "name": 
"keyword.control.repeat.do.batchfile"
+                                                               }
+                                                       },
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "$self"
+                                                               }
+                                                       ]
+                                               },
+                                               {
+                                                       "include": "$self"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "escaped_characters": {
+                       "patterns": [
+                               {
+                                       "match": "%%|\\^\\^!|\\^(?=.)|\\^\\n",
+                                       "name": 
"constant.character.escape.batchfile"
+                               }
+                       ]
+               },
+               "labels": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?i)(?:^\\s*|(?<=call|goto)\\s*)(:)([^+=,;:\\s]\\S*)",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.separator.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.other.special-method.batchfile"
+                                               }
+                                       }
+                               }
+                       ]
+               },
+               "numbers": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?<=^|\\s|=)(0[xX][0-9A-Fa-f]*|[+-]?\\d+)(?=$|\\s|<|>)",
+                                       "name": "constant.numeric.batchfile"
+                               }
+                       ]
+               },
+               "operators": {
+                       "patterns": [
+                               {
+                                       "match": "@(?=\\S)",
+                                       "name": "keyword.operator.at.batchfile"
+                               },
+                               {
+                                       "match": 
"(?<=\\s)(?i:EQU|NEQ|LSS|LEQ|GTR|GEQ)(?=\\s)|==",
+                                       "name": 
"keyword.operator.comparison.batchfile"
+                               },
+                               {
+                                       "match": "(?<=\\s)(?i)(NOT)(?=\\s)",
+                                       "name": 
"keyword.operator.logical.batchfile"
+                               },
+                               {
+                                       "match": "(?<!\\^)&&?|\\|\\|",
+                                       "name": 
"keyword.operator.conditional.batchfile"
+                               },
+                               {
+                                       "match": "(?<!\\^)\\|",
+                                       "name": 
"keyword.operator.pipe.batchfile"
+                               },
+                               {
+                                       "match": "<&?|>[&>]?",
+                                       "name": 
"keyword.operator.redirection.batchfile"
+                               }
+                       ]
+               },
+               "parens": {
+                       "patterns": [
+                               {
+                                       "begin": "\\(",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.group.begin.batchfile"
+                                               }
+                                       },
+                                       "end": "\\)",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.group.end.batchfile"
+                                               }
+                                       },
+                                       "name": "meta.group.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "match": ",|;",
+                                                       "name": 
"punctuation.separator.batchfile"
+                                               },
+                                               {
+                                                       "include": "$self"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "repeatParameter": {
+                       "patterns": [
+                               {
+                                       "match": 
"(%%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?[a-zA-Z])",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.batchfile"
+                                               }
+                                       },
+                                       "name": 
"variable.parameter.repeat.batchfile"
+                               }
+                       ]
+               },
+               "strings": {
+                       "patterns": [
+                               {
+                                       "begin": "\"",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.begin.batchfile"
+                                               }
+                                       },
+                                       "end": "(\")|(\\n)",
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.string.end.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"invalid.illegal.newline.batchfile"
+                                               }
+                                       },
+                                       "name": 
"string.quoted.double.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "match": "%%",
+                                                       "name": 
"constant.character.escape.batchfile"
+                                               },
+                                               {
+                                                       "include": "#variables"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "variables": {
+                       "patterns": [
+                               {
+                                       "match": 
"(%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?\\d|\\*)",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.batchfile"
+                                               }
+                                       },
+                                       "name": "variable.parameter.batchfile"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#variable_delayed_expansion"
+                               }
+                       ]
+               },
+               "variable": {
+                       "patterns": [
+                               {
+                                       "begin": "%(?=[^%]+%)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.variable.begin.batchfile"
+                                               }
+                                       },
+                                       "end": "(%)|\\n",
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.end.batchfile"
+                                               }
+                                       },
+                                       "name": 
"variable.other.readwrite.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "begin": ":~",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.separator.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "(?=%|\\n)",
+                                                       "name": 
"meta.variable.substring.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#variable_substring"
+                                                               }
+                                                       ]
+                                               },
+                                               {
+                                                       "begin": ":",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.separator.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "(?=%|\\n)",
+                                                       "name": 
"meta.variable.substitution.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#variable_replace"
+                                                               },
+                                                               {
+                                                                       
"begin": "=",
+                                                                       
"beginCaptures": {
+                                                                               
"0": {
+                                                                               
        "name": "punctuation.separator.batchfile"
+                                                                               
}
+                                                                       },
+                                                                       "end": 
"(?=%|\\n)",
+                                                                       
"patterns": [
+                                                                               
{
+                                                                               
        "include": "#variable_delayed_expansion"
+                                                                               
},
+                                                                               
{
+                                                                               
        "match": "[^%]+",
+                                                                               
        "name": "string.unquoted.batchfile"
+                                                                               
}
+                                                                       ]
+                                                               }
+                                                       ]
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "variable_delayed_expansion": {
+                       "patterns": [
+                               {
+                                       "begin": "!(?=[^!]+!)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.variable.begin.batchfile"
+                                               }
+                                       },
+                                       "end": "(!)|\\n",
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.end.batchfile"
+                                               }
+                                       },
+                                       "name": 
"variable.other.readwrite.batchfile",
+                                       "patterns": [
+                                               {
+                                                       "begin": ":~",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.separator.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "(?=!|\\n)",
+                                                       "name": 
"meta.variable.substring.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#variable_substring"
+                                                               }
+                                                       ]
+                                               },
+                                               {
+                                                       "begin": ":",
+                                                       "beginCaptures": {
+                                                               "0": {
+                                                                       "name": 
"punctuation.separator.batchfile"
+                                                               }
+                                                       },
+                                                       "end": "(?=!|\\n)",
+                                                       "name": 
"meta.variable.substitution.batchfile",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#escaped_characters"
+                                                               },
+                                                               {
+                                                                       
"include": "#variable_replace"
+                                                               },
+                                                               {
+                                                                       
"include": "#variable"
+                                                               },
+                                                               {
+                                                                       
"begin": "=",
+                                                                       
"beginCaptures": {
+                                                                               
"0": {
+                                                                               
        "name": "punctuation.separator.batchfile"
+                                                                               
}
+                                                                       },
+                                                                       "end": 
"(?=!|\\n)",
+                                                                       
"patterns": [
+                                                                               
{
+                                                                               
        "include": "#variable"
+                                                                               
},
+                                                                               
{
+                                                                               
        "match": "[^!]+",
+                                                                               
        "name": "string.unquoted.batchfile"
+                                                                               
}
+                                                                       ]
+                                                               }
+                                                       ]
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "variable_replace": {
+                       "patterns": [
+                               {
+                                       "match": "[^=%!\\n]+",
+                                       "name": "string.unquoted.batchfile"
+                               }
+                       ]
+               },
+               "variable_substring": {
+                       "patterns": [
+                               {
+                                       "match": 
"([+-]?\\d+)(?:(,)([+-]?\\d+))?",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"constant.numeric.batchfile"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.separator.batchfile"
+                                               },
+                                               "3": {
+                                                       "name": 
"constant.numeric.batchfile"
+                                               }
+                                       }
+                               }
+                       ]
+               }
+       }
+}
\ No newline at end of file
diff --git 
a/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/shell.json 
b/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/shell.json
new file mode 100644
index 0000000000..255638d7db
--- /dev/null
+++ b/rcp/src/main/resources/org/apache/hop/ui/hopgui/grammars/shell.json
@@ -0,0 +1,2353 @@
+{
+       "information_for_contributors": [
+               "This file has been converted from 
https://github.com/jeff-hykin/better-shell-syntax/blob/master/autogenerated/shell.tmLanguage.json";,
+               "If you want to provide a fix or improvement, please create a 
pull request against the original repository.",
+               "Once accepted there, we are happy to receive an update 
request."
+       ],
+       "version": 
"https://github.com/jeff-hykin/better-shell-syntax/commit/35020b0bd79a90d3b262b4c13a8bb0b33adc1f45";,
+       "name": "Shell Script",
+       "scopeName": "source.shell",
+       "patterns": [
+               {
+                       "include": "#initial_context"
+               }
+       ],
+       "repository": {
+               "alias_statement": {
+                       "begin": "(?:(?:[ \\t]*+)(alias)(?:[ 
\\t]*+)((?:(?:((?<!\\w)-\\w+\\b)(?:[ \\t]*+))*))(?:(?:[ 
\\t]*+)(?:((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(?:(?:(\\[)((?:(?:(?:(?:\\$?)(?:(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))|@)|\\*)|(-?\\d+)))(\\]))?))(?:(?:(\\=)|(\\+\\=))|(\\-\\=))))",
+                       "end": "(?:(?= 
|\\t|$)|(?:(?:(?:(;)|(&&))|(\\|\\|))|(&)))",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": "storage.type.alias.shell"
+                               },
+                               "2": {
+                                       "patterns": [
+                                               {
+                                                       "match": 
"(?<!\\w)-\\w+\\b",
+                                                       "name": 
"string.unquoted.argument.shell constant.other.option.shell"
+                                               }
+                                       ]
+                               },
+                               "3": {
+                                       "name": "string.unquoted.argument.shell 
constant.other.option.shell"
+                               },
+                               "4": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "5": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "6": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "7": {
+                                       "name": "constant.numeric.shell 
constant.numeric.integer.shell"
+                               },
+                               "8": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "9": {
+                                       "name": 
"keyword.operator.assignment.shell"
+                               },
+                               "10": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               },
+                               "11": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "1": {
+                                       "name": 
"punctuation.terminator.statement.semicolon.shell"
+                               },
+                               "2": {
+                                       "name": 
"punctuation.separator.statement.and.shell"
+                               },
+                               "3": {
+                                       "name": 
"punctuation.separator.statement.or.shell"
+                               },
+                               "4": {
+                                       "name": 
"punctuation.separator.statement.background.shell"
+                               }
+                       },
+                       "name": "meta.expression.assignment.alias.shell",
+                       "patterns": [
+                               {
+                                       "include": "#normal_context"
+                               }
+                       ]
+               },
+               "argument": {
+                       "begin": "(?:[ \\t]++)(?!(?:&|\\||\\(|\\[|#|\\n|$|;))",
+                       "end": "(?= |\\t|;|\\||&|$|\\n|\\)|\\`)",
+                       "beginCaptures": {},
+                       "endCaptures": {},
+                       "name": "meta.argument.shell",
+                       "patterns": [
+                               {
+                                       "include": "#argument_context"
+                               },
+                               {
+                                       "include": "#line_continuation"
+                               }
+                       ]
+               },
+               "argument_context": {
+                       "patterns": [
+                               {
+                                       "match": "(?:[ \\t]*+)((?:[^ 
\t\n>&;<>\\(\\)\\$`\\\\\"'<\\|]+)(?!>))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"string.unquoted.argument.shell",
+                                                       "patterns": [
+                                                               {
+                                                                       
"match": "\\*",
+                                                                       "name": 
"variable.language.special.wildcard.shell"
+                                                               },
+                                                               {
+                                                                       
"include": "#variable"
+                                                               },
+                                                               {
+                                                                       
"include": "#numeric_literal"
+                                                               },
+                                                               {
+                                                                       
"match": "(?<!\\w)(\\b(?:true|false)\\b)(?!\\w)",
+                                                                       
"captures": {
+                                                                               
"1": {
+                                                                               
        "name": "constant.language.$1.shell"
+                                                                               
}
+                                                                       }
+                                                               }
+                                                       ]
+                                               }
+                                       }
+                               },
+                               {
+                                       "include": "#normal_context"
+                               }
+                       ]
+               },
+               "arithmetic_double": {
+                       "patterns": [
+                               {
+                                       "begin": "\\(\\(",
+                                       "end": "\\)(?:\\s*)\\)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.arithmetic.double.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.arithmetic.double.shell"
+                                               }
+                                       },
+                                       "name": "meta.arithmetic.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": "#math"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "arithmetic_no_dollar": {
+                       "patterns": [
+                               {
+                                       "begin": "\\(",
+                                       "end": "\\)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.arithmetic.single.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.arithmetic.single.shell"
+                                               }
+                                       },
+                                       "name": "meta.arithmetic.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": "#math"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "array_access_inline": {
+                       "match": "(?:(\\[)([^\\[\\]]+)(\\]))",
+                       "captures": {
+                               "1": {
+                                       "name": 
"punctuation.section.array.shell"
+                               },
+                               "2": {
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#special_expansion"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               }
+                                       ]
+                               },
+                               "3": {
+                                       "name": 
"punctuation.section.array.shell"
+                               }
+                       }
+               },
+               "array_value": {
+                       "begin": "(?:[ 
\\t]*+)(?:((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(?:(?:(\\[)((?:(?:(?:(?:\\$?)(?:(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))|@)|\\*)|(-?\\d+)))(\\]))?))(?:(?:(\\=)|(\\+\\=))|(\\-\\=))(?:[
 \\t]*+)(\\()",
+                       "end": "\\)",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "2": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "3": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "4": {
+                                       "name": "constant.numeric.shell 
constant.numeric.integer.shell"
+                               },
+                               "5": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "6": {
+                                       "name": 
"keyword.operator.assignment.shell"
+                               },
+                               "7": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               },
+                               "8": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               },
+                               "9": {
+                                       "name": 
"punctuation.definition.array.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.array.shell"
+                               }
+                       },
+                       "patterns": [
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "match": 
"(?:((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(\\=))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"variable.other.assignment.array.shell entity.other.attribute-name.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"keyword.operator.assignment.shell punctuation.definition.assignment.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "match": "(?:(\\[)(.+?)(\\])(\\=))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.bracket.named-array.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"string.unquoted.shell entity.other.attribute-name.bracket.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"punctuation.definition.bracket.named-array.shell"
+                                               },
+                                               "4": {
+                                                       "name": 
"punctuation.definition.assignment.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "include": "#normal_context"
+                               },
+                               {
+                                       "include": "#simple_unquoted"
+                               }
+                       ]
+               },
+               "assignment_statement": {
+                       "patterns": [
+                               {
+                                       "include": "#array_value"
+                               },
+                               {
+                                       "include": 
"#modified_assignment_statement"
+                               },
+                               {
+                                       "include": 
"#normal_assignment_statement"
+                               }
+                       ]
+               },
+               "basic_command_name": {
+                       "match": 
"(?:(?:(?!(?:!|&|\\||\\(|\\)|\\{|\\[|<|>|#|\\n|$|;|[ \\t]))(?!nocorrect 
|nocorrect\t|nocorrect$|readonly |readonly\t|readonly$|function 
|function\t|function$|foreach |foreach\t|foreach$|coproc 
|coproc\t|coproc$|logout |logout\t|logout$|export |export\t|export$|select 
|select\t|select$|repeat |repeat\t|repeat$|pushd |pushd\t|pushd$|until 
|until\t|until$|while |while\t|while$|local |local\t|local$|case 
|case\t|case$|done |done\t|done$|elif |elif\t|elif$|else |else\t|else$|esac  
[...]
+                       "captures": {
+                               "1": {
+                                       "name": "storage.modifier.$1.shell"
+                               },
+                               "2": {
+                                       "name": 
"entity.name.function.call.shell entity.name.command.shell",
+                                       "patterns": [
+                                               {
+                                                       "match": 
"(?<!\\w)(?:continue|return|break)(?!\\w)",
+                                                       "name": 
"keyword.control.$0.shell"
+                                               },
+                                               {
+                                                       "match": 
"(?<!\\w)(?:(?:unfunction|continue|autoload|unsetopt|bindkey|builtin|getopts|command|declare|unalias|history|unlimit|typeset|suspend|source|printf|unhash|disown|ulimit|return|which|alias|break|false|print|shift|times|umask|umask|unset|read|type|exec|eval|wait|echo|dirs|jobs|kill|hash|stat|exit|test|trap|true|let|set|pwd|cd|fg|bg|fc|:|\\.)(?!\\/))(?!\\w)(?!-)",
+                                                       "name": 
"support.function.builtin.shell"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               }
+                                       ]
+                               }
+                       },
+                       "name": "meta.statement.command.name.basic.shell"
+               },
+               "block_comment": {
+                       "begin": "(?:(?:\\s*+)(\\/\\*))",
+                       "end": "\\*\\/",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": 
"punctuation.definition.comment.begin.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.comment.end.shell"
+                               }
+                       },
+                       "name": "comment.block.shell"
+               },
+               "boolean": {
+                       "match": "\\b(?:true|false)\\b",
+                       "name": "constant.language.$0.shell"
+               },
+               "case_statement": {
+                       "begin": "(?:(\\bcase\\b)(?:[ \\t]*+)(.+?)(?:[ 
\\t]*+)(\\bin\\b))",
+                       "end": "\\besac\\b",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": "keyword.control.case.shell"
+                               },
+                               "2": {
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               "3": {
+                                       "name": "keyword.control.in.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "0": {
+                                       "name": "keyword.control.esac.shell"
+                               }
+                       },
+                       "name": "meta.case.shell",
+                       "patterns": [
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "match": "(?:[ \\t]*+)(\\* *\\))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.pattern.case.default.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "begin": "(?<!\\))(?!(?:[ 
\\t]*+)(?:esac\\b|$))",
+                                       "end": "(?:(?=\\besac\\b)|(\\)))",
+                                       "beginCaptures": {},
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.pattern.case.shell"
+                                               }
+                                       },
+                                       "name": "meta.case.entry.pattern.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#case_statement_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(?<=\\))",
+                                       "end": "(?:(;;)|(?=\\besac\\b))",
+                                       "beginCaptures": {},
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.terminator.statement.case.shell"
+                                               }
+                                       },
+                                       "name": "meta.case.entry.body.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#typical_statements"
+                                               },
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "case_statement_context": {
+                       "patterns": [
+                               {
+                                       "match": "\\*",
+                                       "name": 
"variable.language.special.quantifier.star.shell 
keyword.operator.quantifier.star.shell 
punctuation.definition.arbitrary-repetition.shell 
punctuation.definition.regex.arbitrary-repetition.shell"
+                               },
+                               {
+                                       "match": "\\+",
+                                       "name": 
"variable.language.special.quantifier.plus.shell 
keyword.operator.quantifier.plus.shell 
punctuation.definition.arbitrary-repetition.shell 
punctuation.definition.regex.arbitrary-repetition.shell"
+                               },
+                               {
+                                       "match": "\\?",
+                                       "name": 
"variable.language.special.quantifier.question.shell 
keyword.operator.quantifier.question.shell 
punctuation.definition.arbitrary-repetition.shell 
punctuation.definition.regex.arbitrary-repetition.shell"
+                               },
+                               {
+                                       "match": "@",
+                                       "name": 
"variable.language.special.at.shell keyword.operator.at.shell 
punctuation.definition.regex.at.shell"
+                               },
+                               {
+                                       "match": "\\|",
+                                       "name": 
"keyword.operator.orvariable.language.special.or.shell 
keyword.operator.alternation.ruby.shell 
punctuation.definition.regex.alternation.shell 
punctuation.separator.regex.alternation.shell"
+                               },
+                               {
+                                       "match": "\\\\.",
+                                       "name": 
"constant.character.escape.shell"
+                               },
+                               {
+                                       "match": "(?<=\\tin| in| |\\t|;;)\\(",
+                                       "name": 
"keyword.operator.pattern.case.shell"
+                               },
+                               {
+                                       "begin": "(?<=\\S)(\\()",
+                                       "end": "\\)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.group.shell punctuation.definition.regex.group.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell punctuation.definition.regex.group.shell"
+                                               }
+                                       },
+                                       "name": "meta.parenthese.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#case_statement_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "\\[",
+                                       "end": "\\]",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.character-class.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.character-class.shell"
+                                               }
+                                       },
+                                       "name": 
"string.regexp.character-class.shell",
+                                       "patterns": [
+                                               {
+                                                       "match": "\\\\.",
+                                                       "name": 
"constant.character.escape.shell"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "match": "[^) \\t\\n\\[\\?\\*\\|\\@]",
+                                       "name": "string.unquoted.pattern.shell 
string.regexp.unquoted.shell"
+                               }
+                       ]
+               },
+               "command_name_range": {
+                       "begin": "\\G",
+                       "end": "(?:(?= |\\t|;|\\||&|$|\\n|\\)|\\`)|(?=<))",
+                       "beginCaptures": {},
+                       "endCaptures": {},
+                       "name": "meta.statement.command.name.shell",
+                       "patterns": [
+                               {
+                                       "match": 
"(?<!\\w)(?:continue|return|break)(?!\\w)",
+                                       "name": 
"entity.name.function.call.shell entity.name.command.shell 
keyword.control.$0.shell"
+                               },
+                               {
+                                       "match": 
"(?<!\\w)(?:(?:unfunction|continue|autoload|unsetopt|bindkey|builtin|getopts|command|declare|unalias|history|unlimit|typeset|suspend|source|printf|unhash|disown|ulimit|return|which|alias|break|false|print|shift|times|umask|umask|unset|read|type|exec|eval|wait|echo|dirs|jobs|kill|hash|stat|exit|test|trap|true|let|set|pwd|cd|fg|bg|fc|:|\\.)(?!\\/))(?!\\w)(?!-)",
+                                       "name": 
"entity.name.function.call.shell entity.name.command.shell 
support.function.builtin.shell"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "match": 
"(?:(?<!\\w)(?<=\\G|'|\"|\\}|\\))([^ \\n\\t\\r\"'=;&\\|`\\)\\{<>]+))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"entity.name.function.call.shell entity.name.command.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "begin": "(?:(?:\\G|(?<! 
|\\t|;|\\||&|\\n|\\{|#))(?:(\\$?)((?:(\")|(')))))",
+                                       "end": "(?<!\\G)(?<=(?:\\2))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"meta.statement.command.name.quoted.shell punctuation.definition.string.shell 
entity.name.function.call.shell entity.name.command.shell"
+                                               },
+                                               "2": {},
+                                               "3": {
+                                                       "name": 
"meta.statement.command.name.quoted.shell string.quoted.double.shell 
punctuation.definition.string.begin.shell entity.name.function.call.shell 
entity.name.command.shell"
+                                               },
+                                               "4": {
+                                                       "name": 
"meta.statement.command.name.quoted.shell string.quoted.single.shell 
punctuation.definition.string.begin.shell entity.name.function.call.shell 
entity.name.command.shell"
+                                               }
+                                       },
+                                       "endCaptures": {},
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#continuation_of_single_quoted_command_name"
+                                               },
+                                               {
+                                                       "include": 
"#continuation_of_double_quoted_command_name"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "include": "#line_continuation"
+                               },
+                               {
+                                       "include": "#simple_unquoted"
+                               }
+                       ]
+               },
+               "command_statement": {
+                       "begin": "(?:(?:[ 
\\t]*+)(?:(?!(?:!|&|\\||\\(|\\)|\\{|\\[|<|>|#|\\n|$|;|[ \\t]))(?!nocorrect 
|nocorrect\t|nocorrect$|readonly |readonly\t|readonly$|function 
|function\t|function$|foreach |foreach\t|foreach$|coproc 
|coproc\t|coproc$|logout |logout\t|logout$|export |export\t|export$|select 
|select\t|select$|repeat |repeat\t|repeat$|pushd |pushd\t|pushd$|until 
|until\t|until$|while |while\t|while$|local |local\t|local$|case 
|case\t|case$|done |done\t|done$|elif |elif\t|elif$|else |else\t [...]
+                       "end": "(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ 
\\t]*#|\\])(?<!\\\\)",
+                       "beginCaptures": {},
+                       "endCaptures": {},
+                       "name": "meta.statement.command.shell",
+                       "patterns": [
+                               {
+                                       "include": "#command_name_range"
+                               },
+                               {
+                                       "include": "#line_continuation"
+                               },
+                               {
+                                       "include": "#option"
+                               },
+                               {
+                                       "include": "#argument"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": "#heredoc"
+                               }
+                       ]
+               },
+               "comment": {
+                       "match": "(?:(?:^|(?:[ 
\\t]++))(?:((?:(#!)(?:.*)))|((?:(#)(?:.*)))))",
+                       "captures": {
+                               "1": {
+                                       "name": "comment.line.number-sign.shell 
meta.shebang.shell"
+                               },
+                               "2": {
+                                       "name": 
"punctuation.definition.comment.shebang.shell"
+                               },
+                               "3": {
+                                       "name": "comment.line.number-sign.shell"
+                               },
+                               "4": {
+                                       "name": 
"punctuation.definition.comment.shell"
+                               }
+                       }
+               },
+               "comments": {
+                       "patterns": [
+                               {
+                                       "include": "#block_comment"
+                               },
+                               {
+                                       "include": "#line_comment"
+                               }
+                       ]
+               },
+               "compound-command": {
+                       "patterns": [
+                               {
+                                       "begin": "\\[",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.logical-expression.shell"
+                                               }
+                                       },
+                                       "end": "\\]",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.logical-expression.shell"
+                                               }
+                                       },
+                                       "name": 
"meta.scope.logical-expression.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#logical-expression"
+                                               },
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(?<=\\s|^){(?=\\s|$)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell"
+                                               }
+                                       },
+                                       "end": "(?<=^|;)\\s*(})",
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.group.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.group.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "continuation_of_double_quoted_command_name": {
+                       "begin": "(?:\\G(?<=\"))",
+                       "end": "\"",
+                       "beginCaptures": {},
+                       "endCaptures": {
+                               "0": {
+                                       "name": "string.quoted.double.shell 
punctuation.definition.string.end.shell entity.name.function.call.shell 
entity.name.command.shell"
+                               }
+                       },
+                       "contentName": 
"meta.statement.command.name.continuation string.quoted.double 
entity.name.function.call entity.name.command",
+                       "patterns": [
+                               {
+                                       "match": "\\\\[\\$\\n`\"\\\\]",
+                                       "name": 
"constant.character.escape.shell"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               }
+                       ]
+               },
+               "continuation_of_single_quoted_command_name": {
+                       "begin": "(?:\\G(?<='))",
+                       "end": "'",
+                       "beginCaptures": {},
+                       "endCaptures": {
+                               "0": {
+                                       "name": "string.quoted.single.shell 
punctuation.definition.string.end.shell entity.name.function.call.shell 
entity.name.command.shell"
+                               }
+                       },
+                       "contentName": 
"meta.statement.command.name.continuation string.quoted.single 
entity.name.function.call entity.name.command"
+               },
+               "custom_command_names": {
+                       "patterns": []
+               },
+               "custom_commands": {
+                       "patterns": []
+               },
+               "double_quote_context": {
+                       "patterns": [
+                               {
+                                       "match": "\\\\[\\$`\"\\\\\\n]",
+                                       "name": 
"constant.character.escape.shell"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               }
+                       ]
+               },
+               "double_quote_escape_char": {
+                       "match": "\\\\[\\$`\"\\\\\\n]",
+                       "name": "constant.character.escape.shell"
+               },
+               "floating_keyword": {
+                       "patterns": [
+                               {
+                                       "match": "(?<=^|;|&| 
|\\t)(?:then|elif|else|done|end|do|if|fi)(?= |\\t|;|&|$)",
+                                       "name": "keyword.control.$0.shell"
+                               }
+                       ]
+               },
+               "for_statement": {
+                       "patterns": [
+                               {
+                                       "begin": "(?:(\\bfor\\b)(?:(?:[ 
\\t]*+)((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(?:[ \\t]*+)(\\bin\\b)))",
+                                       "end": 
"(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ \\t]*#|\\])(?<!\\\\)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.for.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.other.for.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"keyword.control.in.shell"
+                                               }
+                                       },
+                                       "endCaptures": {},
+                                       "name": "meta.for.in.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": "#string"
+                                               },
+                                               {
+                                                       "include": 
"#simple_unquoted"
+                                               },
+                                               {
+                                                       "include": 
"#normal_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(\\bfor\\b)",
+                                       "end": 
"(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ \\t]*#|\\])(?<!\\\\)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.for.shell"
+                                               }
+                                       },
+                                       "endCaptures": {},
+                                       "name": "meta.for.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#arithmetic_double"
+                                               },
+                                               {
+                                                       "include": 
"#normal_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "function_definition": {
+                       "begin": "(?:[ \\t]*+)(?:(?:(\\bfunction\\b)(?:[ 
\\t]*+)([^ \\t\\n\\r\\(\\)=\"']+)(?:(?:(\\()(?:[ \\t]*+)(\\)))?))|(?:([^ 
\\t\\n\\r\\(\\)=\"']+)(?:[ \\t]*+)(\\()(?:[ \\t]*+)(\\))))",
+                       "end": "(?<=\\}|\\))",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": "storage.type.function.shell"
+                               },
+                               "2": {
+                                       "name": "entity.name.function.shell"
+                               },
+                               "3": {
+                                       "name": 
"punctuation.definition.arguments.shell"
+                               },
+                               "4": {
+                                       "name": 
"punctuation.definition.arguments.shell"
+                               },
+                               "5": {
+                                       "name": "entity.name.function.shell"
+                               },
+                               "6": {
+                                       "name": 
"punctuation.definition.arguments.shell"
+                               },
+                               "7": {
+                                       "name": 
"punctuation.definition.arguments.shell"
+                               }
+                       },
+                       "endCaptures": {},
+                       "name": "meta.function.shell",
+                       "patterns": [
+                               {
+                                       "match": "(?:\\G(?:\\t| |\\n))"
+                               },
+                               {
+                                       "begin": "\\{",
+                                       "end": "\\}",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell 
punctuation.section.function.definition.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell 
punctuation.section.function.definition.shell"
+                                               }
+                                       },
+                                       "name": "meta.function.body.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "\\(",
+                                       "end": "\\)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell 
punctuation.section.function.definition.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell 
punctuation.section.function.definition.shell"
+                                               }
+                                       },
+                                       "name": "meta.function.body.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "include": "#initial_context"
+                               }
+                       ],
+                       "applyEndPatternLast": 1
+               },
+               "heredoc": {
+                       "patterns": [
+                               {
+                                       "begin": "(?:((?<!<)(?:<<-))(?:[ 
\\t]*+)(\"|')(?:[ \\t]*+)([^\"']+?)(?=\\s|;|&|<|\"|')((?:\\2))(.*))",
+                                       "end": 
"(?:(?:^\\t*)(?:\\3)(?=\\s|;|&|$))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.heredoc.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.string.heredoc.quote.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               },
+                                               "4": {
+                                                       "name": 
"punctuation.definition.string.heredoc.quote.shell"
+                                               },
+                                               "5": {
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#redirect_fix"
+                                                               },
+                                                               {
+                                                                       
"include": "#typical_statements"
+                                                               }
+                                                       ]
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.heredoc.$0.shell"
+                                               }
+                                       },
+                                       "contentName": 
"string.quoted.heredoc.indent.$3",
+                                       "patterns": []
+                               },
+                               {
+                                       "begin": "(?:((?<!<)(?:<<)(?!<))(?:[ 
\\t]*+)(\"|')(?:[ \\t]*+)([^\"']+?)(?=\\s|;|&|<|\"|')((?:\\2))(.*))",
+                                       "end": "(?:^(?:\\3)(?=\\s|;|&|$))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.heredoc.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.string.heredoc.quote.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               },
+                                               "4": {
+                                                       "name": 
"punctuation.definition.string.heredoc.quote.shell"
+                                               },
+                                               "5": {
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#redirect_fix"
+                                                               },
+                                                               {
+                                                                       
"include": "#typical_statements"
+                                                               }
+                                                       ]
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               }
+                                       },
+                                       "contentName": 
"string.quoted.heredoc.no-indent.$3",
+                                       "patterns": []
+                               },
+                               {
+                                       "begin": "(?:((?<!<)(?:<<-))(?:[ 
\\t]*+)([^\"' \\t]+)(?=\\s|;|&|<|\"|')(.*))",
+                                       "end": 
"(?:(?:^\\t*)(?:\\2)(?=\\s|;|&|$))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.heredoc.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               },
+                                               "3": {
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#redirect_fix"
+                                                               },
+                                                               {
+                                                                       
"include": "#typical_statements"
+                                                               }
+                                                       ]
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               }
+                                       },
+                                       "contentName": 
"string.unquoted.heredoc.indent.$2",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#double_quote_escape_char"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               },
+                                               {
+                                                       "include": 
"#interpolation"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(?:((?<!<)(?:<<)(?!<))(?:[ 
\\t]*+)([^\"' \\t]+)(?=\\s|;|&|<|\"|')(.*))",
+                                       "end": "(?:^(?:\\2)(?=\\s|;|&|$))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.heredoc.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               },
+                                               "3": {
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#redirect_fix"
+                                                               },
+                                                               {
+                                                                       
"include": "#typical_statements"
+                                                               }
+                                                       ]
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.heredoc.delimiter.shell"
+                                               }
+                                       },
+                                       "contentName": 
"string.unquoted.heredoc.no-indent.$2",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#double_quote_escape_char"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               },
+                                               {
+                                                       "include": 
"#interpolation"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "herestring": {
+                       "patterns": [
+                               {
+                                       "begin": "(<<<)\\s*(('))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.herestring.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"string.quoted.single.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "end": "(')",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"string.quoted.single.shell"
+                                               },
+                                               "1": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": "meta.herestring.shell",
+                                       "contentName": 
"string.quoted.single.shell"
+                               },
+                               {
+                                       "begin": "(<<<)\\s*((\"))",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.herestring.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"string.quoted.double.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "end": "(\")",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"string.quoted.double.shell"
+                                               },
+                                               "1": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": "meta.herestring.shell",
+                                       "contentName": 
"string.quoted.double.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#double_quote_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.herestring.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"string.unquoted.herestring.shell",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#initial_context"
+                                                               }
+                                                       ]
+                                               }
+                                       },
+                                       "match": 
"(<<<)\\s*(([^\\s)\\\\]|\\\\.)+)",
+                                       "name": "meta.herestring.shell"
+                               }
+                       ]
+               },
+               "initial_context": {
+                       "patterns": [
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "include": "#pipeline"
+                               },
+                               {
+                                       "include": "#normal_statement_seperator"
+                               },
+                               {
+                                       "include": "#logical_expression_double"
+                               },
+                               {
+                                       "include": "#logical_expression_single"
+                               },
+                               {
+                                       "include": "#assignment_statement"
+                               },
+                               {
+                                       "include": "#case_statement"
+                               },
+                               {
+                                       "include": "#for_statement"
+                               },
+                               {
+                                       "include": "#loop"
+                               },
+                               {
+                                       "include": "#function_definition"
+                               },
+                               {
+                                       "include": "#line_continuation"
+                               },
+                               {
+                                       "include": "#arithmetic_double"
+                               },
+                               {
+                                       "include": "#misc_ranges"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               },
+                               {
+                                       "include": "#heredoc"
+                               },
+                               {
+                                       "include": "#herestring"
+                               },
+                               {
+                                       "include": "#redirection"
+                               },
+                               {
+                                       "include": "#pathname"
+                               },
+                               {
+                                       "include": "#floating_keyword"
+                               },
+                               {
+                                       "include": "#alias_statement"
+                               },
+                               {
+                                       "include": "#normal_statement"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": "#support"
+                               }
+                       ]
+               },
+               "inline_comment": {
+                       "match": 
"(\\/\\*)((?:(?:[^\\*]|(?:(?:\\*++)[^\\/]))*+)((?:(?:\\*++)\\/)))",
+                       "captures": {
+                               "1": {
+                                       "name": "comment.block.shell 
punctuation.definition.comment.begin.shell"
+                               },
+                               "2": {
+                                       "name": "comment.block.shell"
+                               },
+                               "3": {
+                                       "patterns": [
+                                               {
+                                                       "match": "\\*\\/",
+                                                       "name": 
"comment.block.shell punctuation.definition.comment.end.shell"
+                                               },
+                                               {
+                                                       "match": "\\*",
+                                                       "name": 
"comment.block.shell"
+                                               }
+                                       ]
+                               }
+                       }
+               },
+               "interpolation": {
+                       "patterns": [
+                               {
+                                       "include": "#arithmetic_dollar"
+                               },
+                               {
+                                       "include": "#subshell_dollar"
+                               },
+                               {
+                                       "begin": "`",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.evaluation.backticks.shell"
+                                               }
+                                       },
+                                       "end": "`",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.evaluation.backticks.shell"
+                                               }
+                                       },
+                                       "name": 
"string.interpolated.backtick.shell",
+                                       "patterns": [
+                                               {
+                                                       "match": "\\\\[`\\\\$]",
+                                                       "name": 
"constant.character.escape.shell"
+                                               },
+                                               {
+                                                       "begin": 
"(?<=\\W)(?=#)(?!#{)",
+                                                       "beginCaptures": {
+                                                               "1": {
+                                                                       "name": 
"punctuation.whitespace.comment.leading.shell"
+                                                               }
+                                                       },
+                                                       "end": "(?!\\G)",
+                                                       "patterns": [
+                                                               {
+                                                                       
"begin": "#",
+                                                                       
"beginCaptures": {
+                                                                               
"0": {
+                                                                               
        "name": "punctuation.definition.comment.shell"
+                                                                               
}
+                                                                       },
+                                                                       "end": 
"(?=`)",
+                                                                       "name": 
"comment.line.number-sign.shell"
+                                                               }
+                                                       ]
+                                               },
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "keyword": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?<=^|;|&|\\s)(then|else|elif|fi|for|in|do|done|select|continue|esac|while|until|return)(?=\\s|;|&|$)",
+                                       "name": "keyword.control.shell"
+                               },
+                               {
+                                       "match": 
"(?<=^|;|&|\\s)(?:export|declare|typeset|local|readonly)(?=\\s|;|&|$)",
+                                       "name": "storage.modifier.shell"
+                               }
+                       ]
+               },
+               "line_comment": {
+                       "begin": "(?:\\s*+)(\\/\\/)",
+                       "end": "(?<=\\n)(?<!\\\\\\n)",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": 
"punctuation.definition.comment.shell"
+                               }
+                       },
+                       "endCaptures": {},
+                       "name": "comment.line.double-slash.shell",
+                       "patterns": [
+                               {
+                                       "include": 
"#line_continuation_character"
+                               }
+                       ]
+               },
+               "line_continuation": {
+                       "match": "\\\\(?=\\n)",
+                       "name": 
"constant.character.escape.line-continuation.shell"
+               },
+               "logical-expression": {
+                       "patterns": [
+                               {
+                                       "include": "#arithmetic_no_dollar"
+                               },
+                               {
+                                       "comment": "do we want a special rule 
for ( expr )?",
+                                       "match": "=[=~]?|!=?|<|>|&&|\\|\\|",
+                                       "name": "keyword.operator.logical.shell"
+                               },
+                               {
+                                       "match": 
"(?<!\\S)-(nt|ot|ef|eq|ne|l[te]|g[te]|[a-hknoprstuwxzOGLSN])\\b",
+                                       "name": "keyword.operator.logical.shell"
+                               }
+                       ]
+               },
+               "logical_expression_context": {
+                       "patterns": [
+                               {
+                                       "include": "#regex_comparison"
+                               },
+                               {
+                                       "include": "#arithmetic_no_dollar"
+                               },
+                               {
+                                       "include": "#logical-expression"
+                               },
+                               {
+                                       "include": "#logical_expression_single"
+                               },
+                               {
+                                       "include": "#logical_expression_double"
+                               },
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "include": "#boolean"
+                               },
+                               {
+                                       "include": "#redirect_number"
+                               },
+                               {
+                                       "include": "#numeric_literal"
+                               },
+                               {
+                                       "include": "#pipeline"
+                               },
+                               {
+                                       "include": "#normal_statement_seperator"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               },
+                               {
+                                       "include": "#heredoc"
+                               },
+                               {
+                                       "include": "#herestring"
+                               },
+                               {
+                                       "include": "#pathname"
+                               },
+                               {
+                                       "include": "#floating_keyword"
+                               },
+                               {
+                                       "include": "#support"
+                               }
+                       ]
+               },
+               "logical_expression_double": {
+                       "begin": "\\[\\[",
+                       "end": "\\]\\]",
+                       "beginCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.logical-expression.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.logical-expression.shell"
+                               }
+                       },
+                       "name": "meta.scope.logical-expression.shell",
+                       "patterns": [
+                               {
+                                       "include": "#logical_expression_context"
+                               }
+                       ]
+               },
+               "logical_expression_single": {
+                       "begin": "\\[",
+                       "end": "\\]",
+                       "beginCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.logical-expression.shell"
+                               }
+                       },
+                       "endCaptures": {
+                               "0": {
+                                       "name": 
"punctuation.definition.logical-expression.shell"
+                               }
+                       },
+                       "name": "meta.scope.logical-expression.shell",
+                       "patterns": [
+                               {
+                                       "include": "#logical_expression_context"
+                               }
+                       ]
+               },
+               "loop": {
+                       "patterns": [
+                               {
+                                       "begin": 
"(?<=^|;|&|\\s)(for)\\s+(.+?)\\s+(in)(?=\\s|;|&|$)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.other.loop.shell",
+                                                       "patterns": [
+                                                               {
+                                                                       
"include": "#string"
+                                                               }
+                                                       ]
+                                               },
+                                               "3": {
+                                                       "name": 
"keyword.control.shell"
+                                               }
+                                       },
+                                       "end": 
"(?<=^|;|&|\\s)done(?=\\s|;|&|$|\\))",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.control.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.for-in-loop.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": 
"(?<=^|;|&|\\s)(while|until)(?=\\s|;|&|$)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.shell"
+                                               }
+                                       },
+                                       "end": 
"(?<=^|;|&|\\s)done(?=\\s|;|&|$|\\))",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.control.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.while-loop.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": 
"(?<=^|;|&|\\s)(select)\\s+((?:[^\\s\\\\]|\\\\.)+)(?=\\s|;|&|$)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.other.loop.shell"
+                                               }
+                                       },
+                                       "end": 
"(?<=^|;|&|\\s)(done)(?=\\s|;|&|$|\\))",
+                                       "endCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.select-block.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": 
"(?<=^|;|&|\\s)if(?=\\s|;|&|$)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.control.if.shell"
+                                               }
+                                       },
+                                       "end": "(?<=^|;|&|\\s)fi(?=\\s|;|&|$)",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"keyword.control.fi.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.if-block.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "math": {
+                       "patterns": [
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "match": 
"\\+{1,2}|-{1,2}|!|~|\\*{1,2}|/|%|<[<=]?|>[>=]?|==|!=|^|\\|{1,2}|&{1,2}|\\?|\\:|,|=|[*/%+\\-&^|]=|<<=|>>=",
+                                       "name": 
"keyword.operator.arithmetic.shell"
+                               },
+                               {
+                                       "match": "0[xX][0-9A-Fa-f]+",
+                                       "name": "constant.numeric.hex.shell"
+                               },
+                               {
+                                       "match": ";",
+                                       "name": 
"punctuation.separator.semicolon.range"
+                               },
+                               {
+                                       "match": "0\\d+",
+                                       "name": "constant.numeric.octal.shell"
+                               },
+                               {
+                                       "match": "\\d{1,2}#[0-9a-zA-Z@_]+",
+                                       "name": "constant.numeric.other.shell"
+                               },
+                               {
+                                       "match": "\\d+",
+                                       "name": "constant.numeric.integer.shell"
+                               },
+                               {
+                                       "match": 
"(?<!\\w)(?:[a-zA-Z_0-9]+)(?!\\w)",
+                                       "name": "variable.other.normal.shell"
+                               }
+                       ]
+               },
+               "math_operators": {
+                       "patterns": [
+                               {
+                                       "match": 
"\\+{1,2}|-{1,2}|!|~|\\*{1,2}|/|%|<[<=]?|>[>=]?|==|!=|^|\\|{1,2}|&{1,2}|\\?|\\:|,|=|[*/%+\\-&^|]=|<<=|>>=",
+                                       "name": 
"keyword.operator.arithmetic.shell"
+                               },
+                               {
+                                       "match": "0[xX][0-9A-Fa-f]+",
+                                       "name": "constant.numeric.hex.shell"
+                               },
+                               {
+                                       "match": "0\\d+",
+                                       "name": "constant.numeric.octal.shell"
+                               },
+                               {
+                                       "match": "\\d{1,2}#[0-9a-zA-Z@_]+",
+                                       "name": "constant.numeric.other.shell"
+                               },
+                               {
+                                       "match": "\\d+",
+                                       "name": "constant.numeric.integer.shell"
+                               }
+                       ]
+               },
+               "misc_ranges": {
+                       "patterns": [
+                               {
+                                       "include": "#logical_expression_single"
+                               },
+                               {
+                                       "include": "#logical_expression_double"
+                               },
+                               {
+                                       "include": "#subshell_dollar"
+                               },
+                               {
+                                       "begin": "(?<![^ \\t])({)(?!\\w|\\$)",
+                                       "end": "}",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.group.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.group.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.group.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "modified_assignment_statement": {
+                       "begin": "(?<=^|;|&|[ 
\\t])(?:readonly|declare|typeset|export|local)(?=[ \\t]|;|&|$)",
+                       "end": "(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ 
\\t]*#|\\])(?<!\\\\)",
+                       "beginCaptures": {
+                               "0": {
+                                       "name": "storage.modifier.$0.shell"
+                               }
+                       },
+                       "endCaptures": {},
+                       "name": "meta.statement.shell 
meta.expression.assignment.modified.shell",
+                       "patterns": [
+                               {
+                                       "match": "(?<!\\w)-\\w+\\b",
+                                       "name": "string.unquoted.argument.shell 
constant.other.option.shell"
+                               },
+                               {
+                                       "include": "#array_value"
+                               },
+                               {
+                                       "match": 
"(?:((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(?:(?:(\\[)((?:(?:(?:(?:\\$?)(?:(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))|@)|\\*)|(-?\\d+)))(\\]))?)(?:(?:(?:(\\=)|(\\+\\=))|(\\-\\=))?)(?:(?:(?<==|
 
|\\t|^|\\{|\\(|\\[)(?:(?:(?:(?:(?:(0[xX][0-9A-Fa-f]+)|(0\\d+))|(\\d{1,2}#[0-9a-zA-Z@_]+))|(-?\\d+(?:\\.\\d+)))|(-?\\d+(?:\\.\\d+)+))|(-?\\d+))(?=
 |\\t|$|\\}|\\)|;))?))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"variable.other.assignment.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.array.access.shell"
+                                               },
+                                               "3": {
+                                                       "name": 
"variable.other.assignment.shell"
+                                               },
+                                               "4": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.integer.shell"
+                                               },
+                                               "5": {
+                                                       "name": 
"punctuation.definition.array.access.shell"
+                                               },
+                                               "6": {
+                                                       "name": 
"keyword.operator.assignment.shell"
+                                               },
+                                               "7": {
+                                                       "name": 
"keyword.operator.assignment.compound.shell"
+                                               },
+                                               "8": {
+                                                       "name": 
"keyword.operator.assignment.compound.shell"
+                                               },
+                                               "9": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.hex.shell"
+                                               },
+                                               "10": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.octal.shell"
+                                               },
+                                               "11": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.other.shell"
+                                               },
+                                               "12": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.decimal.shell"
+                                               },
+                                               "13": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.version.shell"
+                                               },
+                                               "14": {
+                                                       "name": 
"constant.numeric.shell constant.numeric.integer.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "include": "#normal_context"
+                               }
+                       ]
+               },
+               "modifiers": {
+                       "match": "(?<=^|;|&|[ 
\\t])(?:readonly|declare|typeset|export|local)(?=[ \\t]|;|&|$)",
+                       "name": "storage.modifier.$0.shell"
+               },
+               "normal_assignment_statement": {
+                       "begin": "(?:[ 
\\t]*+)(?:((?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))(?:(?:(\\[)((?:(?:(?:(?:\\$?)(?:(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w))|@)|\\*)|(-?\\d+)))(\\]))?))(?:(?:(\\=)|(\\+\\=))|(\\-\\=))",
+                       "end": "(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ 
\\t]*#|\\])(?<!\\\\)",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "2": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "3": {
+                                       "name": 
"variable.other.assignment.shell"
+                               },
+                               "4": {
+                                       "name": "constant.numeric.shell 
constant.numeric.integer.shell"
+                               },
+                               "5": {
+                                       "name": 
"punctuation.definition.array.access.shell"
+                               },
+                               "6": {
+                                       "name": 
"keyword.operator.assignment.shell"
+                               },
+                               "7": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               },
+                               "8": {
+                                       "name": 
"keyword.operator.assignment.compound.shell"
+                               }
+                       },
+                       "endCaptures": {},
+                       "name": "meta.expression.assignment.shell",
+                       "patterns": [
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": 
"#normal_assignment_statement"
+                               },
+                               {
+                                       "begin": "(?<= |\\t)(?! |\\t|\\w+=)",
+                                       "end": 
"(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ \\t]*#|\\])(?<!\\\\)",
+                                       "beginCaptures": {},
+                                       "endCaptures": {},
+                                       "name": 
"meta.statement.command.env.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#command_name_range"
+                                               },
+                                               {
+                                                       "include": 
"#line_continuation"
+                                               },
+                                               {
+                                                       "include": "#option"
+                                               },
+                                               {
+                                                       "include": "#argument"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "include": "#simple_unquoted"
+                               },
+                               {
+                                       "include": "#normal_context"
+                               }
+                       ]
+               },
+               "normal_context": {
+                       "patterns": [
+                               {
+                                       "include": "#comment"
+                               },
+                               {
+                                       "include": "#pipeline"
+                               },
+                               {
+                                       "include": "#normal_statement_seperator"
+                               },
+                               {
+                                       "include": "#misc_ranges"
+                               },
+                               {
+                                       "include": "#boolean"
+                               },
+                               {
+                                       "include": "#redirect_number"
+                               },
+                               {
+                                       "include": "#numeric_literal"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               },
+                               {
+                                       "include": "#heredoc"
+                               },
+                               {
+                                       "include": "#herestring"
+                               },
+                               {
+                                       "include": "#redirection"
+                               },
+                               {
+                                       "include": "#pathname"
+                               },
+                               {
+                                       "include": "#floating_keyword"
+                               },
+                               {
+                                       "include": "#support"
+                               },
+                               {
+                                       "include": "#parenthese"
+                               }
+                       ]
+               },
+               "normal_statement": {
+                       "begin": "(?:(?!^[ \\t]*+$)(?:(?<=^until | until 
|\\tuntil |^while | while |\\twhile |^elif | elif |\\telif |^else | else 
|\\telse |^then | then |\\tthen |^do | do |\\tdo |^if | if |\\tif 
)|(?<=(?:^|;|\\||&|!|\\(|\\{|\\`)))(?:[ 
\\t]*+)(?!nocorrect\\W|nocorrect\\$|function\\W|function\\$|foreach\\W|foreach\\$|repeat\\W|repeat\\$|logout\\W|logout\\$|coproc\\W|coproc\\$|select\\W|select\\$|while\\W|while\\$|pushd\\W|pushd\\$|until\\W|until\\$|case\\W|case\\$|done\\W|done\\$|elif\\W|elif\
 [...]
+                       "end": "(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ 
\\t]*#|\\])(?<!\\\\)",
+                       "beginCaptures": {},
+                       "endCaptures": {},
+                       "name": "meta.statement.shell",
+                       "patterns": [
+                               {
+                                       "include": "#typical_statements"
+                               }
+                       ]
+               },
+               "normal_statement_seperator": {
+                       "match": "(?:(?:(?:(;)|(&&))|(\\|\\|))|(&))",
+                       "captures": {
+                               "1": {
+                                       "name": 
"punctuation.terminator.statement.semicolon.shell"
+                               },
+                               "2": {
+                                       "name": 
"punctuation.separator.statement.and.shell"
+                               },
+                               "3": {
+                                       "name": 
"punctuation.separator.statement.or.shell"
+                               },
+                               "4": {
+                                       "name": 
"punctuation.separator.statement.background.shell"
+                               }
+                       }
+               },
+               "numeric_literal": {
+                       "match": "(?<==| 
|\\t|^|\\{|\\(|\\[)(?:(?:(?:(?:(?:(0[xX][0-9A-Fa-f]+)|(0\\d+))|(\\d{1,2}#[0-9a-zA-Z@_]+))|(-?\\d+(?:\\.\\d+)))|(-?\\d+(?:\\.\\d+)+))|(-?\\d+))(?=
 |\\t|$|\\}|\\)|;)",
+                       "captures": {
+                               "1": {
+                                       "name": "constant.numeric.shell 
constant.numeric.hex.shell"
+                               },
+                               "2": {
+                                       "name": "constant.numeric.shell 
constant.numeric.octal.shell"
+                               },
+                               "3": {
+                                       "name": "constant.numeric.shell 
constant.numeric.other.shell"
+                               },
+                               "4": {
+                                       "name": "constant.numeric.shell 
constant.numeric.decimal.shell"
+                               },
+                               "5": {
+                                       "name": "constant.numeric.shell 
constant.numeric.version.shell"
+                               },
+                               "6": {
+                                       "name": "constant.numeric.shell 
constant.numeric.integer.shell"
+                               }
+                       }
+               },
+               "option": {
+                       "begin": "(?:(?:[ 
\\t]++)(-)((?!(?:!|&|\\||\\(|\\)|\\{|\\[|<|>|#|\\n|$|;|[ \\t]))))",
+                       "end": "(?:(?=[ 
\\t])|(?:(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ \\t]*#|\\])(?<!\\\\)))",
+                       "beginCaptures": {
+                               "1": {
+                                       "name": "string.unquoted.argument.shell 
constant.other.option.dash.shell"
+                               },
+                               "2": {
+                                       "name": "string.unquoted.argument.shell 
constant.other.option.shell"
+                               }
+                       },
+                       "endCaptures": {},
+                       "contentName": "string.unquoted.argument 
constant.other.option",
+                       "patterns": [
+                               {
+                                       "include": "#option_context"
+                               }
+                       ]
+               },
+               "option_context": {
+                       "patterns": [
+                               {
+                                       "include": "#misc_ranges"
+                               },
+                               {
+                                       "include": "#string"
+                               },
+                               {
+                                       "include": "#variable"
+                               },
+                               {
+                                       "include": "#interpolation"
+                               },
+                               {
+                                       "include": "#heredoc"
+                               },
+                               {
+                                       "include": "#herestring"
+                               },
+                               {
+                                       "include": "#redirection"
+                               },
+                               {
+                                       "include": "#pathname"
+                               },
+                               {
+                                       "include": "#floating_keyword"
+                               },
+                               {
+                                       "include": "#support"
+                               }
+                       ]
+               },
+               "parenthese": {
+                       "patterns": [
+                               {
+                                       "begin": "\\(",
+                                       "end": "\\)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.parenthese.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.parenthese.shell"
+                                               }
+                                       },
+                                       "name": "meta.parenthese.group.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "pathname": {
+                       "patterns": [
+                               {
+                                       "match": "(?<=\\s|:|=|^)~",
+                                       "name": "keyword.operator.tilde.shell"
+                               },
+                               {
+                                       "match": "\\*|\\?",
+                                       "name": "keyword.operator.glob.shell"
+                               },
+                               {
+                                       "begin": "([?*+@!])(\\()",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.operator.extglob.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.definition.extglob.shell"
+                                               }
+                                       },
+                                       "end": "\\)",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.extglob.shell"
+                                               }
+                                       },
+                                       "name": "meta.structure.extglob.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "pipeline": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?<=^|;|&|\\s)(time)(?=\\s|;|&|$)",
+                                       "name": "keyword.other.shell"
+                               },
+                               {
+                                       "match": "[|!]",
+                                       "name": "keyword.operator.pipe.shell"
+                               }
+                       ]
+               },
+               "redirect_fix": {
+                       "match": "(?:(>>?)(?:[ \\t]*+)([^ 
\t\n>&;<>\\(\\)\\$`\\\\\"'<\\|]+))",
+                       "captures": {
+                               "1": {
+                                       "name": 
"keyword.operator.redirect.shell"
+                               },
+                               "2": {
+                                       "name": "string.unquoted.argument.shell"
+                               }
+                       }
+               },
+               "redirect_number": {
+                       "match": "(?<=[ \\t])(?:(?:(1)|(2)|(\\d+))(?=>))",
+                       "captures": {
+                               "1": {
+                                       "name": 
"keyword.operator.redirect.stdout.shell"
+                               },
+                               "2": {
+                                       "name": 
"keyword.operator.redirect.stderr.shell"
+                               },
+                               "3": {
+                                       "name": 
"keyword.operator.redirect.$3.shell"
+                               }
+                       }
+               },
+               "redirection": {
+                       "patterns": [
+                               {
+                                       "begin": "[><]\\(",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "end": "\\)",
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": 
"string.interpolated.process-substitution.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "match": 
"(?<![<>])(&>|\\d*>&\\d*|\\d*(>>|>|<)|\\d*<&|\\d*<>)(?![<>])",
+                                       "name": 
"keyword.operator.redirect.shell"
+                               }
+                       ]
+               },
+               "regex_comparison": {
+                       "match": "\\=~",
+                       "name": "keyword.operator.logical.regex.shell"
+               },
+               "regexp": {
+                       "patterns": [
+                               {
+                                       "match": "(?:.+)"
+                               }
+                       ]
+               },
+               "simple_options": {
+                       "match": "(?:(?:[ \\t]++)\\-(?:\\w+))*",
+                       "captures": {
+                               "0": {
+                                       "patterns": [
+                                               {
+                                                       "match": "(?:[ 
\\t]++)(\\-)(\\w+)",
+                                                       "captures": {
+                                                               "1": {
+                                                                       "name": 
"string.unquoted.argument.shell constant.other.option.dash.shell"
+                                                               },
+                                                               "2": {
+                                                                       "name": 
"string.unquoted.argument.shell constant.other.option.shell"
+                                                               }
+                                                       }
+                                               }
+                                       ]
+                               }
+                       }
+               },
+               "simple_unquoted": {
+                       "match": "[^ \\t\\n>&;<>\\(\\)\\$`\\\\\"'<\\|]",
+                       "name": "string.unquoted.shell"
+               },
+               "special_expansion": {
+                       "match": "!|:[-=?]?|\\*|@|##|#|%%|%|\\/",
+                       "name": "keyword.operator.expansion.shell"
+               },
+               "start_of_command": {
+                       "match": "(?:(?:[ 
\\t]*+)(?:(?!(?:!|&|\\||\\(|\\)|\\{|\\[|<|>|#|\\n|$|;|[ \\t]))(?!nocorrect 
|nocorrect\t|nocorrect$|readonly |readonly\t|readonly$|function 
|function\t|function$|foreach |foreach\t|foreach$|coproc 
|coproc\t|coproc$|logout |logout\t|logout$|export |export\t|export$|select 
|select\t|select$|repeat |repeat\t|repeat$|pushd |pushd\t|pushd$|until 
|until\t|until$|while |while\t|while$|local |local\t|local$|case 
|case\t|case$|done |done\t|done$|elif |elif\t|elif$|else |else\t [...]
+               },
+               "string": {
+                       "patterns": [
+                               {
+                                       "match": "\\\\.",
+                                       "name": 
"constant.character.escape.shell"
+                               },
+                               {
+                                       "begin": "'",
+                                       "end": "'",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": "string.quoted.single.shell"
+                               },
+                               {
+                                       "begin": "\\$?\"",
+                                       "end": "\"",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": "string.quoted.double.shell",
+                                       "patterns": [
+                                               {
+                                                       "match": 
"\\\\[\\$\\n`\"\\\\]",
+                                                       "name": 
"constant.character.escape.shell"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               },
+                                               {
+                                                       "include": 
"#interpolation"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "\\$'",
+                                       "end": "'",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.begin.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.string.end.shell"
+                                               }
+                                       },
+                                       "name": 
"string.quoted.single.dollar.shell",
+                                       "patterns": [
+                                               {
+                                                       "match": 
"\\\\(?:a|b|e|f|n|r|t|v|\\\\|')",
+                                                       "name": 
"constant.character.escape.ansi-c.shell"
+                                               },
+                                               {
+                                                       "match": 
"\\\\[0-9]{3}\"",
+                                                       "name": 
"constant.character.escape.octal.shell"
+                                               },
+                                               {
+                                                       "match": 
"\\\\x[0-9a-fA-F]{2}\"",
+                                                       "name": 
"constant.character.escape.hex.shell"
+                                               },
+                                               {
+                                                       "match": "\\\\c.\"",
+                                                       "name": 
"constant.character.escape.control-char.shell"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "subshell_dollar": {
+                       "patterns": [
+                               {
+                                       "begin": "(?:\\$\\()",
+                                       "end": "\\)",
+                                       "beginCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.subshell.single.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.definition.subshell.single.shell"
+                                               }
+                                       },
+                                       "name": "meta.scope.subshell",
+                                       "patterns": [
+                                               {
+                                                       "include": "#parenthese"
+                                               },
+                                               {
+                                                       "include": 
"#initial_context"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               "support": {
+                       "patterns": [
+                               {
+                                       "match": 
"(?<=^|;|&|\\s)(?::|\\.)(?=\\s|;|&|$)",
+                                       "name": "support.function.builtin.shell"
+                               }
+                       ]
+               },
+               "typical_statements": {
+                       "patterns": [
+                               {
+                                       "include": "#assignment_statement"
+                               },
+                               {
+                                       "include": "#case_statement"
+                               },
+                               {
+                                       "include": "#for_statement"
+                               },
+                               {
+                                       "include": "#while_statement"
+                               },
+                               {
+                                       "include": "#function_definition"
+                               },
+                               {
+                                       "include": "#command_statement"
+                               },
+                               {
+                                       "include": "#line_continuation"
+                               },
+                               {
+                                       "include": "#arithmetic_double"
+                               },
+                               {
+                                       "include": "#normal_context"
+                               }
+                       ]
+               },
+               "variable": {
+                       "patterns": [
+                               {
+                                       "match": "(?:(\\$)(\\@(?!\\w)))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell variable.parameter.positional.all.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.parameter.positional.all.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "match": "(?:(\\$)([0-9](?!\\w)))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell variable.parameter.positional.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.parameter.positional.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "match": "(?:(\\$)([-*#?$!0_](?!\\w)))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell variable.language.special.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.language.special.shell"
+                                               }
+                                       }
+                               },
+                               {
+                                       "begin": "(?:(\\$)(\\{)(?:[ 
\\t]*+)(?=\\d))",
+                                       "end": "\\}",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell variable.parameter.positional.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.section.bracket.curly.variable.begin.shell 
punctuation.definition.variable.shell variable.parameter.positional.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.bracket.curly.variable.end.shell 
punctuation.definition.variable.shell variable.parameter.positional.shell"
+                                               }
+                                       },
+                                       "contentName": 
"meta.parameter-expansion",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#special_expansion"
+                                               },
+                                               {
+                                                       "include": 
"#array_access_inline"
+                                               },
+                                               {
+                                                       "match": "[0-9]+",
+                                                       "name": 
"variable.parameter.positional.shell"
+                                               },
+                                               {
+                                                       "match": 
"(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w)",
+                                                       "name": 
"variable.other.normal.shell"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "begin": "(?:(\\$)(\\{))",
+                                       "end": "\\}",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"punctuation.section.bracket.curly.variable.begin.shell 
punctuation.definition.variable.shell"
+                                               }
+                                       },
+                                       "endCaptures": {
+                                               "0": {
+                                                       "name": 
"punctuation.section.bracket.curly.variable.end.shell 
punctuation.definition.variable.shell"
+                                               }
+                                       },
+                                       "contentName": 
"meta.parameter-expansion",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#special_expansion"
+                                               },
+                                               {
+                                                       "include": 
"#array_access_inline"
+                                               },
+                                               {
+                                                       "match": 
"(?<!\\w)(?:[a-zA-Z_0-9-]+)(?!\\w)",
+                                                       "name": 
"variable.other.normal.shell"
+                                               },
+                                               {
+                                                       "include": "#variable"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               },
+                               {
+                                       "match": "(?:(\\$)((?:\\w+)(?!\\w)))",
+                                       "captures": {
+                                               "1": {
+                                                       "name": 
"punctuation.definition.variable.shell variable.other.normal.shell"
+                                               },
+                                               "2": {
+                                                       "name": 
"variable.other.normal.shell"
+                                               }
+                                       }
+                               }
+                       ]
+               },
+               "while_statement": {
+                       "patterns": [
+                               {
+                                       "begin": "(\\bwhile\\b)",
+                                       "end": 
"(?=;|\\||&|\\n|\\)|\\`|\\{|\\}|[ \\t]*#|\\])(?<!\\\\)",
+                                       "beginCaptures": {
+                                               "1": {
+                                                       "name": 
"keyword.control.while.shell"
+                                               }
+                                       },
+                                       "endCaptures": {},
+                                       "name": "meta.while.shell",
+                                       "patterns": [
+                                               {
+                                                       "include": 
"#line_continuation"
+                                               },
+                                               {
+                                                       "include": 
"#math_operators"
+                                               },
+                                               {
+                                                       "include": "#option"
+                                               },
+                                               {
+                                                       "include": 
"#simple_unquoted"
+                                               },
+                                               {
+                                                       "include": 
"#normal_context"
+                                               },
+                                               {
+                                                       "include": "#string"
+                                               }
+                                       ]
+                               }
+                       ]
+               }
+       }
+}
\ No newline at end of file
diff --git 
a/rcp/src/test/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupportTest.java 
b/rcp/src/test/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupportTest.java
index cca9c3b590..37e9d499a1 100644
--- 
a/rcp/src/test/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupportTest.java
+++ 
b/rcp/src/test/java/org/apache/hop/ui/hopgui/ContentEditorTm4eSupportTest.java
@@ -21,11 +21,74 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.tm4e.core.grammar.IGrammar;
+import org.eclipse.tm4e.core.grammar.ITokenizeLineResult;
+import org.eclipse.tm4e.core.registry.IGrammarSource;
+import org.eclipse.tm4e.core.registry.IRegistryOptions;
+import org.eclipse.tm4e.core.registry.Registry;
 import org.junit.jupiter.api.Test;
 
 class ContentEditorTm4eSupportTest {
 
+  /**
+   * Loads a vendored grammar the same way ContentEditorTm4eSupport does, 
without an SWT Display.
+   */
+  private static IGrammar loadGrammar(String scopeName, String fileName) 
throws Exception {
+    Map<String, String> files = Map.of(scopeName, fileName);
+    Registry registry =
+        new Registry(
+            new IRegistryOptions() {
+              @Override
+              public IGrammarSource getGrammarSource(String scope) {
+                String file = files.get(scope);
+                if (file == null) {
+                  return null;
+                }
+                return new IGrammarSource() {
+                  @Override
+                  public URI getURI() {
+                    return URI.create("hop://grammar/" + scope);
+                  }
+
+                  @Override
+                  public Reader getReader() throws IOException {
+                    InputStream in =
+                        
ContentEditorTm4eSupport.class.getResourceAsStream("grammars/" + file);
+                    if (in == null) {
+                      throw new IOException("Grammar resource not found: 
grammars/" + file);
+                    }
+                    return new InputStreamReader(in, StandardCharsets.UTF_8);
+                  }
+
+                  @Override
+                  public long getLastModified() {
+                    return 0;
+                  }
+
+                  @Override
+                  public IGrammarSource.ContentType getContentType() {
+                    return IGrammarSource.ContentType.JSON;
+                  }
+                };
+              }
+
+              @Override
+              public Collection<String> getInjections(String scope) {
+                return List.of();
+              }
+            });
+    return registry.loadGrammar(scopeName);
+  }
+
   @Test
   void scopeForLanguage_python_returnsSourcePython() {
     assertEquals("source.python", 
ContentEditorTm4eSupport.scopeForLanguage("python"));
@@ -45,6 +108,57 @@ class ContentEditorTm4eSupportTest {
     }
   }
 
+  @Test
+  void scopeForLanguage_shellAliases_returnSourceShell() {
+    assertEquals("source.shell", 
ContentEditorTm4eSupport.scopeForLanguage("shell"));
+    assertEquals("source.shell", 
ContentEditorTm4eSupport.scopeForLanguage("bash"));
+    assertEquals("source.shell", 
ContentEditorTm4eSupport.scopeForLanguage("sh"));
+  }
+
+  @Test
+  void scopeForLanguage_batchAliases_returnSourceBatchfile() {
+    assertEquals("source.batchfile", 
ContentEditorTm4eSupport.scopeForLanguage("bat"));
+    assertEquals("source.batchfile", 
ContentEditorTm4eSupport.scopeForLanguage("cmd"));
+    assertEquals("source.batchfile", 
ContentEditorTm4eSupport.scopeForLanguage("batch"));
+  }
+
+  @Test
+  void shellGrammarResourceIsOnClasspath() throws Exception {
+    try (InputStream in =
+        
ContentEditorTm4eSupport.class.getResourceAsStream("grammars/shell.json")) {
+      assertNotNull(in, "grammars/shell.json should be on the classpath");
+      assertTrue(in.read() >= 0, "shell.json should not be empty");
+    }
+  }
+
+  @Test
+  void batGrammarResourceIsOnClasspath() throws Exception {
+    try (InputStream in = 
ContentEditorTm4eSupport.class.getResourceAsStream("grammars/bat.json")) {
+      assertNotNull(in, "grammars/bat.json should be on the classpath");
+      assertTrue(in.read() >= 0, "bat.json should not be empty");
+    }
+  }
+
+  @Test
+  void shellGrammarLoadsAndTokenizes() throws Exception {
+    IGrammar grammar = loadGrammar("source.shell", "shell.json");
+    assertNotNull(grammar, "TM4E should load the shell grammar");
+    ITokenizeLineResult<org.eclipse.tm4e.core.grammar.IToken[]> result =
+        grammar.tokenizeLine("# comment\necho \"$HOME\"", null, null);
+    assertNotNull(result);
+    assertTrue(result.getTokens().length > 0, "shell line should produce 
tokens");
+  }
+
+  @Test
+  void batGrammarLoadsAndTokenizes() throws Exception {
+    IGrammar grammar = loadGrammar("source.batchfile", "bat.json");
+    assertNotNull(grammar, "TM4E should load the batch grammar");
+    ITokenizeLineResult<org.eclipse.tm4e.core.grammar.IToken[]> result =
+        grammar.tokenizeLine("REM comment\nECHO %PATH%", null, null);
+    assertNotNull(result);
+    assertTrue(result.getTokens().length > 0, "batch line should produce 
tokens");
+  }
+
   @Test
   void scopeForLanguage_yaml_returnsSourceYaml() {
     assertEquals("source.yaml", 
ContentEditorTm4eSupport.scopeForLanguage("yaml"));

Reply via email to