parts, boolean case
Styles.StyleCompiler sh = new Styles.StyleCompiler(spec, true);
AttributedStyle style = new StyleResolver(sh::getStyle).resolve("." + reference);
- if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PATTERN) {
- if (parts.size() == 2) {
- highlightRules.get(tokenName).add(new HighlightRule(style, doPattern(".*", caseInsensitive)));
- } else {
- for (int i = 2; i < parts.size(); i++) {
- highlightRules
- .get(tokenName)
- .add(new HighlightRule(style, doPattern(parts.get(i), caseInsensitive)));
+ try {
+ if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PATTERN) {
+ if (parts.size() == 2) {
+ highlightRules.get(tokenName).add(new HighlightRule(style, doPattern(".*", caseInsensitive)));
+ } else {
+ for (int i = 2; i < parts.size(); i++) {
+ highlightRules
+ .get(tokenName)
+ .add(new HighlightRule(style, doPattern(parts.get(i), caseInsensitive)));
+ }
}
+ } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.START_END) {
+ String s = parts.get(2);
+ String e = parts.get(3);
+ highlightRules
+ .get(tokenName)
+ .add(new HighlightRule(
+ style,
+ doPattern(s.substring(7, s.length() - 1), caseInsensitive),
+ doPattern(e.substring(5, e.length() - 1), caseInsensitive)));
+ } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PARSER_START_WITH) {
+ highlightRules
+ .get(tokenName)
+ .add(new HighlightRule(
+ HighlightRule.RuleType.PARSER_START_WITH,
+ style,
+ parts.get(2).substring(10)));
+ } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PARSER_CONTINUE_AS) {
+ highlightRules
+ .get(tokenName)
+ .add(new HighlightRule(
+ HighlightRule.RuleType.PARSER_CONTINUE_AS,
+ style,
+ parts.get(2).substring(11)));
}
- } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.START_END) {
- String s = parts.get(2);
- String e = parts.get(3);
- highlightRules
- .get(tokenName)
- .add(new HighlightRule(
- style,
- doPattern(s.substring(7, s.length() - 1), caseInsensitive),
- doPattern(e.substring(5, e.length() - 1), caseInsensitive)));
- } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PARSER_START_WITH) {
- highlightRules
- .get(tokenName)
- .add(new HighlightRule(
- HighlightRule.RuleType.PARSER_START_WITH,
- style,
- parts.get(2).substring(10)));
- } else if (HighlightRule.evalRuleType(parts) == HighlightRule.RuleType.PARSER_CONTINUE_AS) {
- highlightRules
- .get(tokenName)
- .add(new HighlightRule(
- HighlightRule.RuleType.PARSER_CONTINUE_AS,
- style,
- parts.get(2).substring(11)));
+ } catch (PatternSyntaxException e) {
+ Log.warn("Invalid highlight regex", e);
}
}
private Pattern doPattern(String regex, boolean caseInsensitive) {
+ regex = posixToJavaRegex(regex);
return caseInsensitive ? Pattern.compile(regex, Pattern.CASE_INSENSITIVE) : Pattern.compile(regex);
}
}
+ /**
+ * Posix regex is different from Java regex. This function parses the given Posix regex and escapes according to these rules:
+ *
+ * The first {@code ]} in a bracket expression does not need to be escaped in Posix,translate to {@code \]}.
+ *
+ *
Same as above for a negating bracket expression like {@code [^][]}, translate to {@code [^\]\[]}.
+ *
+ *
Any {@code [} in a bracket expression does not need to be escaped in Posix, translate to {@code \[}.
+ *
+ *
Any {@code ]} not in a bracket expression is valid in both Posix and Java, no translation.
+ *
+ *
A backslash before the closing bracket like {@code [.f\]} is not an escape of the closing bracket,
+ * the backslash needs to be escaped for Java, translate to {@code [.f\\]}.
+ *
+ *
Do not perform the above translations within an escape via {@code \}.
+ *
+ *
Do not perform the above translations for Posix "classes" like {@code [[:word:]]} or {@code [[:digit:]]}
+ * and their negation {@code [-[:word]]}.
+ *
+ *
Do not perform the above translations for single-bracket Posix classes like {@code [:digit:]},
+ * and handle the case of single-bracket Posix classes inside bracket expressions, like
+ * @code {[[:digit:]-.]}.
+ *
+ * @param posix Posix regex
+ * @return Java regex
+ */
+ static String posixToJavaRegex(String posix) {
+ int len = posix.length();
+ StringBuilder java = new StringBuilder();
+
+ boolean inBracketExpression = false;
+
+ int i = 0;
+ char next;
+ try {
+ for (; i < len; i++) {
+ char c = posix.charAt(i);
+
+ switch (c) {
+ case '\\':
+ next = posix.charAt(++i);
+ // Don't translate anything after the \ character escape
+ if (inBracketExpression && next == ']') {
+ inBracketExpression = false;
+ java.append("\\\\").append(next);
+ } else {
+ java.append(c).append(next);
+ }
+ break;
+ case '[':
+ if (i == len - 1) {
+ throw new IllegalArgumentException("Lone [ at the end of (index " + i + "): " + posix);
+ }
+ // Handle "double bracket" Posix "classes" like [[:word:]] or [[:digit:]] and their negations
+ // starting with [-[:
+ if (posix.regionMatches(i, "[[:", 0, 3) || posix.regionMatches(i, "[-[:", 0, 4)) {
+ int afterClass = nextAfterClass(posix, i + 3);
+ if (posix.regionMatches(afterClass, ":]]", 0, 3)) {
+ java.append(posix, i, afterClass + 3);
+ i = afterClass + 2;
+ break;
+ } else if (posix.regionMatches(afterClass, ":]", 0, 2)) {
+ if (inBracketExpression) {
+ throw new IllegalArgumentException("Unclear bracket expression");
+ }
+ // Handles character patterns like [[:alpha:]_-]
+ java.append(posix, i, afterClass + 2);
+ i = afterClass + 1;
+ inBracketExpression = true;
+ break;
+ } else {
+ throw new IllegalArgumentException("Invalid character class");
+ }
+ }
+ // Handle "single bracket" Posix "classes" like [:word:]
+ else if (posix.charAt(i + 1) == ':') {
+ int afterClass = nextAfterClass(posix, i + 2);
+ if (!posix.regionMatches(afterClass, ":]", 0, 2)) {
+ java.append("[:");
+ i++;
+ inBracketExpression = true;
+ } else {
+ java.append(posix, i, afterClass + 2);
+ i = afterClass + 1;
+ }
+ break;
+ }
+ if (inBracketExpression) {
+ // Translate lone [ to \[
+ java.append('\\').append(c);
+ } else {
+ inBracketExpression = true;
+ java.append(c);
+ next = posix.charAt(i + 1);
+ if (next == ']') {
+ i++;
+ java.append("\\]");
+ } else if (next == '^' && posix.charAt(i + 2) == ']') {
+ i += 2;
+ java.append("^\\]");
+ }
+ }
+ break;
+ case ']':
+ if (inBracketExpression) {
+ inBracketExpression = false;
+ }
+ java.append(c);
+ break;
+ default:
+ java.append(c);
+ break;
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "Posix-to-Java regex translation failed around index " + i + " of: " + posix, e);
+ }
+ return java.toString();
+ }
+
+ private static int nextAfterClass(String s, int idx) {
+ if (s.charAt(idx) == ':') {
+ idx++;
+ }
+ while (true) {
+ char c = s.charAt(idx);
+ if (!Character.isLetterOrDigit(c)) {
+ break;
+ }
+ idx++;
+ }
+ return idx;
+ }
+
protected static class RuleSplitter {
protected static List split(String s) {
List out = new ArrayList<>();
diff --git a/builtins/src/test/java/org/jline/builtins/SyntaxHighlighterTest.java b/builtins/src/test/java/org/jline/builtins/SyntaxHighlighterTest.java
new file mode 100644
index 000000000..2d1ae861d
--- /dev/null
+++ b/builtins/src/test/java/org/jline/builtins/SyntaxHighlighterTest.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2002-2017, the original author(s).
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+package org.jline.builtins;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+public class SyntaxHighlighterTest {
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ void checkRegexFix(String posix, String expectedJava) {
+ String java = SyntaxHighlighter.posixToJavaRegex(posix);
+ Assertions.assertEquals(expectedJava, java);
+ // should not throw
+ Pattern.compile(java);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ public void regexFixBrackets(String posix, String expectedJava) {
+ checkRegexFix(posix, expectedJava);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ public void regexFixBackslash(String posix, String expectedJava) {
+ checkRegexFix(posix, expectedJava);
+ }
+
+ @ParameterizedTest
+ @MethodSource("unescaped")
+ public void regexFixUnescaped(String posix) {
+ checkRegexFix(posix, posix);
+ }
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ @ParameterizedTest
+ @MethodSource("unescaped")
+ public void unescapedChecksWork(String posix) {
+ // should not throw
+ Pattern.compile(posix);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ @Disabled("There are two failing expressions, which look suspicious (unclosed groups)")
+ public void failing(String posix) {
+ checkRegexFix(posix, posix);
+ }
+
+ static Stream failing() {
+ return Stream.of(
+ // java.util.regex.PatternSyntaxException: Unmatched closing ')' near index 46
+ // @(encode|end|implementation|interface)|selector)\>
+ // ^
+ "@(encode|end|implementation|interface)|selector)\\>",
+ // java.util.regex.PatternSyntaxException: Unmatched closing ')' near index 100
+ // ^deb(-src)?\s+.*(mirror\+)?(ftp|https?|rsh|ssh|copy|file|in-toto|s3|spacewalk|tor):/\S+|cdrom:\[.+\]/)\s+\S+
+ // ^
+ "^deb(-src)?\\s+.*(mirror\\+)?(ftp|https?|rsh|ssh|copy|file|in-toto|s3|spacewalk|tor):/\\S+|cdrom:\\[.+\\]/)\\s+\\S+");
+ }
+
+ // Code to extract highlight regexes from nanorc files
+ @SuppressWarnings("unused")
+ void dumpNanoRegexes() throws Exception {
+ Files.list(Paths.get("/usr/share/nano")).filter(Files::isRegularFile).forEachOrdered(p -> {
+ try {
+ Files.readAllLines(p).stream()
+ .filter(s -> s.startsWith("color"))
+ .map(s -> {
+ int i = s.indexOf(' ');
+ if (i == -1) {
+ return null;
+ }
+ i = s.indexOf(' ', i + 1);
+ if (i == -1) {
+ return null;
+ }
+ s = s.substring(i + 1).trim();
+ if (s.startsWith("\"") && s.endsWith("\"")) {
+ return s.substring(1, s.length() - 1);
+ }
+ return null;
+ })
+ .filter(Objects::nonNull)
+ .map(s -> s.replace("\\", "\\\\").replace("\"", "\\\""))
+ .map(s -> '\"' + s + "\" ,")
+ .sorted()
+ .forEachOrdered(System.out::println);
+ ;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ static Stream regexFixBrackets() {
+ return Stream.of(
+ arguments("[][]", "[\\]\\[]"),
+ arguments("[]{}[]", "[\\]{}\\[]"),
+ arguments("[][][][]", "[\\]\\[][\\]\\[]"),
+ arguments("\\[[][]", "\\[[\\]\\[]"),
+ arguments("\\[[][]", "\\[[\\]\\[]"),
+ arguments(
+ " 0(o[0-7]+|x[[:xdigit:]]+)( *[]}]|, | +#|$)", " 0(o[0-7]+|x[[:xdigit:]]+)( *[\\]}]|, | +#|$)"),
+ arguments(
+ "[:,] +(Y(es)?|No?|y(es)?|no?|[Tt]rue|[Ff]alse|[Oo](n|ff))( *[]}]|, | +#|$)",
+ "[:,] +(Y(es)?|No?|y(es)?|no?|[Tt]rue|[Ff]alse|[Oo](n|ff))( *[\\]}]|, | +#|$)"),
+ arguments(
+ "[:,] +[+-]?[0-9]+(\\.([0-9]+)?)?( *[]}]|, | +#|$)",
+ "[:,] +[+-]?[0-9]+(\\.([0-9]+)?)?( *[\\]}]|, | +#|$)"),
+ arguments(
+ "\\^[]/4-8@A-Z\\^_`◂▸▴▾-]\" \"[◂▸▴▾]\" \"\\<(M|S[Hh]-[Mm])-[^\")”»“」]\" \"\\ regexFixBackslash() {
+ return Stream.of(
+ arguments(
+ "'([^'\\]|\\\\(\\[\"'\\abfnrtv]|x[[:xdigit:]]{1,2}|[0-3]?[0-7]{1,2}))'",
+ "'([^'\\\\]|\\\\(\\[\"'\\abfnrtv]|x[[:xdigit:]]{1,2}|[0-3]?[0-7]{1,2}))'"),
+ arguments("'([^'\\]|\\\\.)'", "'([^'\\\\]|\\\\.)'"),
+ arguments(
+ "'([^'\\]|\\\\.)*'|\"([^\"\\]|\\\\.)*\"|'''|\"\"\"",
+ "'([^'\\\\]|\\\\.)*'|\"([^\"\\\\]|\\\\.)*\"|'''|\"\"\""),
+ arguments("(^|[[:blank:]])[$%@][/\\]", "(^|[[:blank:]])[$%@][/\\\\]"),
+ arguments("(^|[^\\])%.*", "(^|[^\\\\])%.*"),
+ arguments("<[^= ]*>|\"([^\"\\]|\\\\.)*\"", "<[^= ]*>|\"([^\"\\\\]|\\\\.)*\""),
+ arguments("@\"([^\"\\]|\\\\.)*\"", "@\"([^\"\\\\]|\\\\.)*\""),
+ arguments(
+ "[$%&@]([A-Za-z_][0-9A-Za-z_]*|\\^[][A-Z?\\^_]|[0-9]+)\\>",
+ "[$%&@]([A-Za-z_][0-9A-Za-z_]*|\\^[\\]\\[A-Z?\\^_]|[0-9]+)\\>"),
+ arguments(
+ "[$%&@]([][!\"#'()*+,.:;<=>?`|~-]|\\{[][!-/:-@\\`|~]\\})|\\$[$%&@]",
+ "[$%&@]([\\]\\[!\"#'()*+,.:;<=>?`|~-]|\\{[\\]\\[!-/:-@\\`|~]\\})|\\$[$%&@]"),
+ arguments(
+ "[$%&@]\\{(\\^?[A-Za-z_][0-9A-Za-z_]*|\\^[][?\\^][0-9]+)\\}",
+ "[$%&@]\\{(\\^?[A-Za-z_][0-9A-Za-z_]*|\\^[\\]\\[?\\^][0-9]+)\\}"),
+ arguments("[][{}():;|`$<>!=&\\]", "[\\]\\[{}():;|`$<>!=&\\\\]"),
+ arguments("[][{}():;|`$<>!=&\\]", "[\\]\\[{}():;|`$<>!=&\\\\]"),
+ arguments("\"([^\"\\]|\\\\.)*\"", "\"([^\"\\\\]|\\\\.)*\""),
+ arguments("\"([^\"\\]|\\\\.)*\"|'([^'\\]|\\\\.)*'", "\"([^\"\\\\]|\\\\.)*\"|'([^'\\\\]|\\\\.)*'"),
+ arguments(
+ "\"([^\"\\]|\\\\.)*\"|'([^'\\]|\\\\.)*'|`([^`\\]|\\\\.)*`",
+ "\"([^\"\\\\]|\\\\.)*\"|'([^'\\\\]|\\\\.)*'|`([^`\\\\]|\\\\.)*`"),
+ arguments("\"([^\"\\]|\\\\.)*\"|'([^'\\]|\\\\.)+'", "\"([^\"\\\\]|\\\\.)*\"|'([^'\\\\]|\\\\.)+'"),
+ arguments("\"([^\"\\]|\\\\.)*\"|<[^= ]*>", "\"([^\"\\\\]|\\\\.)*\"|<[^= ]*>"),
+ arguments("\"[^\"\\]*\"", "\"[^\"\\\\]*\""),
+ arguments(
+ "\\\\([abcefnrtv\"\\]|x[[:xdigit:]]{2}|[0-7]{3})",
+ "\\\\([abcefnrtv\"\\\\]|x[[:xdigit:]]{2}|[0-7]{3})"),
+ arguments(
+ "\\^[A-Z^\\]|\\?@\\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:blank:]]+([a-z]+|\".*\")[[:blank:]]+(main|help|search|replace(with)?|yesno|gotoline|writeout|insert|execute|browser|whereisfile|gotodir|spell|linter|all)\\>",
+ "^[[:blank:]]*bind[[:blank:]]+((\\^([A-Za-z]|[\\]/@\\^_`-]|Space)|([Ss][Hh]-)?[Mm]-[A-Za-z]|[Mm]-([\\]\\[!\"#$%&'()*+,./0-9:;<=>?@\\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:blank:]]+([a-z]+|\".*\")[[:blank:]]+(main|help|search|replace(with)?|yesno|gotoline|writeout|insert|execute|browser|whereisfile|gotodir|spell|linter|all)\\>"),
+ arguments(
+ "^[[:blank:]]*unbind[[:blank:]]+((\\^([A-Za-z]|[]/@\\^_`-]|Space)|([Ss][Hh]-)?[Mm]-[A-Za-z]|[Mm]-([][!\"#$%&'()*+,./0-9:;<=>?@\\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:blank:]]+(main|help|search|replace(with)?|yesno|gotoline|writeout|insert|execute|browser|whereisfile|gotodir|spell|linter|all)\\>",
+ "^[[:blank:]]*unbind[[:blank:]]+((\\^([A-Za-z]|[\\]/@\\^_`-]|Space)|([Ss][Hh]-)?[Mm]-[A-Za-z]|[Mm]-([\\]\\[!\"#$%&'()*+,./0-9:;<=>?@\\^_`{|}~-]|Space))|F([1-9]|1[0-9]|2[0-4])|Ins|Del)[[:blank:]]+(main|help|search|replace(with)?|yesno|gotoline|writeout|insert|execute|browser|whereisfile|gotodir|spell|linter|all)\\>"),
+ arguments("^\\[[^][]+\\]$", "^\\[[^\\]\\[]+\\]$"),
+ arguments("!?\\[[^]]+\\]", "!?\\[[^\\]]+\\]"),
+ arguments(
+ "'([^']|\\\\')*'|%[qw](\\{[^}]*\\}|\\([^)]*\\)|<[^>]*>|\\[[^]]*\\]|\\$[^$]*\\$|\\^[^^]*\\^|![^!]*!)",
+ "'([^']|\\\\')*'|%[qw](\\{[^}]*\\}|\\([^)]*\\)|<[^>]*>|\\[[^\\]]*\\]|\\$[^$]*\\$|\\^[^^]*\\^|![^!]*!)"),
+ arguments(
+ "\"([^\"]|\\\\\")*\"|%[QW]?(\\{[^}]*\\}|\\([^)]*\\)|<[^>]*>|\\[[^]]*\\]|\\$[^$]*\\$|\\^[^^]*\\^|![^!]*!)",
+ "\"([^\"]|\\\\\")*\"|%[QW]?(\\{[^}]*\\}|\\([^)]*\\)|<[^>]*>|\\[[^\\]]*\\]|\\$[^$]*\\$|\\^[^^]*\\^|![^!]*!)"),
+ arguments("\\[:space:],.]", "\\[:space:],.]"),
+ arguments("\\[[^][:blank:]]*\\]", "\\[[^\\][:blank:]]*\\]"),
+ arguments("\\[[^]]+\\]\\([^)]+\\)", "\\[[^\\]]+\\]\\([^)]+\\)"));
+ }
+
+ static Stream unescaped() {
+ return Stream.of(
+ " $",
+ " !!(binary|bool|float|int|map|null|omap|seq|set|str)( |,|$)",
+ " ![^! ][^ ]*( |$)",
+ " (:?:|\\+|\\?)?= ",
+ " (no-)?[-[:alpha:]]+-format(,|$)",
+ " + +",
+ " [&*](\\w|-)+( |$)",
+ " [12][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])",
+ " [|>]([1-9]?[+-]|[+-][1-9]?)?$",
+ " \\(|\\) ",
+ " fuzzy(,|$)",
+ "##([^{].*|$)",
+ "#([^{#].*|$)",
+ "#.*",
+ "#?'\\<(\\w|-)+\\>",
+ "#?:(\\w|[?-])+",
+ "#\\\\(.|\\w+)",
+ "#\\{[^}]*\\}",
+ "#~.*",
+ "%([1-9]\\$)?[#0 +'I-]?(\\*([1-9]\\$)?|[1-9](\\.[0-9]?)?)?[hlLjzt]?[diouxXeEfFgGaAcspnm%]",
+ "&(amp|apos|gt|lt|quot);",
+ "&[^; ]+;",
+ "&[^;[:space:]]*;",
+ "'''|\"\"\"",
+ "'([^']|\\\\')*'",
+ "'(\\^|M-)'",
+ "'\\<(\\w|-)+\\>",
+ "(#t|#f)\\>",
+ "(--|//).*",
+ "(/([^/]|\\\\/)*/|%r\\{([^}]|\\\\\\})*\\})[iomx]*",
+ "(<\\?(php|=)?|\\?>)",
+ "(BZ|bug|patch)[ ]#[0-9]+|PR [[:alnum:]]+/[0-9]+",
+ "([ ]|^):[0-9A-Za-z_]+\\>",
+ "(\"([^\"]|\\\\\")+\"|'[^']+')",
+ "(\\$|@)[[:alpha:]_-][[:alnum:]_.-]*",
+ "(\\w|::|[/.-])+:( |$)",
+ "(^\\.)?\\\\\".*",
+ "(^| )#.*",
+ "(^|[[:blank:]])#.*",
+ "(^|[[:blank:]])//.*",
+ "(^|[[:blank:]]);.*",
+ "(^|[[:blank:]])\\[.*[[:blank:]].*\\]",
+ "(^|[[:blank:]]+)#.*",
+ "(^|[[:blank:]]+)(//|#).*",
+ "(^|[[:blank:]]+)//.*",
+ "(https?|ftp)://\\S+\\.\\S+[^[:space:].)]",
+ "-(eq|ne|gt|lt|ge|le|ef|ot|nt)\\>",
+ "--.*",
+ "->|<-|=>",
+ ".",
+ ".*",
+ "//.*",
+ "//[[:blank:]]*\\+build[[:blank:]]+(([a-zA-Z_0-9]+[[:blank:]]*)+,[[:blank:]]*)*[a-zA-Z_0-9]+",
+ "//[^\"]*$|(^|[[:blank:]])//.*",
+ ":(\\w|[?-])+",
+ ":(active|checked|focus|hover|link|visited|after|before)\\>",
+ ":(close|flush|lines|read|seek|setvbuf|write)\\>",
+ ":[[:alnum:]]*",
+ ":[[:blank:]]*$",
+ ":[[:blank:]]*\"#[[:xdigit:]]+\"",
+ ":[[:blank:]]*\\-?(0|[1-9][0-9]*)(\\.[0-9]+)?([Ee]?[-+]?[0-9]+)?",
+ ":|\\*|/|%|\\+|-|\\^|>|>=|<|<=|~=|=|\\.\\.|#|\\<(not|and|or)\\>",
+ ";|:|\\{|\\}",
+ "<-[[:blank:]]*chan\\>|\\",
+ "<[[:alnum:].%_+-]+@[[:alnum:].-]+\\.[[:alpha:]]{2,}>",
+ "<[[:alpha:]/!?][^>]*>",
+ "<[^> ]+|/?>",
+ "<[^>]*@[^>]*>",
+ "<[^>]+>",
+ "<[^@]+@[^@]+>",
+ "<\\?.+\\?>|]+>|\\]>",
+ "==|/=|&&|\\|\\||<|>|<=|>=",
+ "=|!=|&&|\\|\\|",
+ "@([a-z]+|,|H|U)\\{([^}]|@\\}|@[a-z]+\\{[^}]*\\})*\\}",
+ "@[!\"'&*./:=?@\\^`{}~-]",
+ "@[[:alpha:]_][[:alnum:]_.]*",
+ "@\\|",
+ "@c(omment)?[[:space:]]+.*",
+ "Copyright|\\(C\\)",
+ "XXX|TODO|FIXME|\\?\\?\\?",
+ "XXX|TODO|FIXME|\\?\\?\\?",
+ "[!$&();<=>\\`|]",
+ "[.-]tar\\>",
+ "[:,]( |$)",
+ "[A-Z][A-Z_0-9]+",
+ "[A-Z][A-Za-z0-9]+",
+ "[[:alnum:]]*:",
+ "[[:blank:]]",
+ "[[:blank:]](-[A-Za-z]|--\\<[A-Za-z-]+)\\>",
+ "[[:blank:]](OR|AND|IS_NEWER_THAN|MATCHES|(STR|VERSION_)?(LESS|GREATER|EQUAL))[[:blank:]]",
+ "[[:blank:]](start=)?\".+\"",
+ "[[:blank:]]-[a-zA-Z\\$]|--[8a-z-]+",
+ "[[:cntrl:]]",
+ "[[:cntrl:]]| +$",
+ "[[:space:]]+$",
+ "[a-z_]+!",
+ "[smy]/.*/",
+ "[{},:]",
+ "[{}]",
+ "\"",
+ "\"([^\"]|\\\\\")*\"",
+ "\"([^\"]|\\\\\")*\"|#[[:blank:]]*include[[:blank:]]*<[^>]+>",
+ "\".*\"|qq\\|.*\\|",
+ "\".+\"",
+ "\"[[:alpha:]_][[:alnum:]_$]*\"",
+ "\"[^\"]*\"",
+ "\"[^\"]*\"",
+ "\"[^\"]*\"|'[^']*'",
+ "\"[^\"]+\"[[:blank:]]*:",
+ "\\$([-@*#?$!0-9]|[[:alpha:]_][[:alnum:]_]*)",
+ "\\$+[{(][a-zA-Z0-9_-]+[})]",
+ "\\$[0-9A-Za-z_!@#$*?-]+",
+ "\\$[A-Za-z_][A-Za-z_0-9]*",
+ "\\$\\{?[0-9A-Za-z_!@#$*?-]+\\}?",
+ "\\$\\{[#!]?([-@*#?$!]|[0-9]+|[[:alpha:]_][[:alnum:]_]*)(\\[([[:blank:]]*[[:alnum:]_]+[[:blank:]]*|@)\\])?(([#%/]|:?[-=?+])[^}]*\\}|\\[|\\})",
+ "\\(M-(\\)|\")\\)",
+ "\\(|\\)|\\[|\\]|\\{|\\}",
+ "\\*[^* ][^*]*\\*|_[^_ ][^_]*_",
+ "\\*\\*[^*]+\\*\\*|__[^_]+__",
+ "\\.(align|file|globl|global|hidden|section|size|type|weak)",
+ "\\.(ascii|asciz|byte|double|float|hword|int|long|short|single|struct|word)",
+ "\\.(data|subsection|text)",
+ "\\.\\.\\.",
+ "\\.|\\$",
+ "\\<((Sh-)?Tab|Enter|Ins|(Sh-\\^?)?Del|Space|Bsp|Up|Down|Left|Right|Home|End|PgUp|PgDn)\\>",
+ "\\<(([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|glob|gmtime|grep|hex|import|index|int|ioctl|join)\\>",
+ "\\<((pre|rc)?[0-9]+|[0-9]bit)\\>",
+ "\\<(APPLE|UNIX|WIN32|CYGWIN|BORLAND|MINGW|MSVC(_IDE|60|71|80|90)?)\\>",
+ "\\<(ARGC|ARGIND|ARGV|BINMODE|CONVFMT|ENVIRON|ERRNO|FIELDWIDTHS)\\>",
+ "\\<(BEGIN|END|alias|and|begin|break|case|class|def|defined\\?|do|else|elsif|end|ensure|false|for|if|in|module)\\>",
+ "\\<(Bounded|Data|Enum|Eq|Floating|Fractional|Functor|Integral|Monad|MonadPlus|Num|Ord|Read|Real|RealFloat|RealFrac|Show|Typeable)\\>",
+ "\\<(FILENAME|FNR|FS|IGNORECASE|LINT|NF|NR|OFMT|OFS|ORS)\\>",
+ "\\<(FIXME|TODO|XXX)\\>",
+ "\\<(False|None|True)\\>",
+ "\\<(GNU )?[Nn]ano [1-8]\\.[0-9][-.[:alnum:]]*\\>",
+ "\\<(NOT|COMMAND|POLICY|TARGET|EXISTS|IS_(DIRECTORY|ABSOLUTE)|DEFINED)[[:blank:]]",
+ "\\<(POT-Creation-Date|PO-Revision-Date|MIME-Version|Content-Type|Content-Transfer-Encoding)\\>",
+ "\\<(PROCINFO|RS|RT|RSTART|RLENGTH|SUBSEP|TEXTDOMAIN)\\>",
+ "\\<(Project-Id-Version|Report-Msgid-Bugs-To|Last-Translator|Language(-Team)?|X-Bugs|X-Generator|Plural-Forms)\\>",
+ "\\<(SQL|pl(java|perlu?|pgsql|py|pythonu?|r|ruby|scheme|sh|tcl))\\>",
+ "\\<(True|False|Nothing|Just|Left|Right|LT|EQ|GT)\\>",
+ "\\<(UTF|ISO|Windows|Mac|IBM)-[0-9]+",
+ "\\<([0-9]+|0x[[:xdigit:]]+)\\>",
+ "\\<([1-9][0-9]*|0[0-7]*|0[xX][[:xdigit:]]+)\\>",
+ "\\<([[:lower:]][[:lower:]_]*|(u_?)?int(8|16|32|64))_t\\>",
+ "\\<(_(Alignas|Alignof|Atomic|Bool|Complex|Generic|Imaginary|Noreturn|Static_assert|Thread_local))\\>",
+ "\\<(_G|_VERSION|assert|collectgarbage|dofile|error|getfenv|getmetatable|ipairs|load|loadfile|module|next|pairs|pcall|print|rawequal|rawget|rawlen|rawset|require|select|setfenv|setmetatable|tonumber|tostring|type|unpack|xpcall)[[:blank:]]*\\(",
+ "\\<(__FILE__|__LINE__)\\>",
+ "\\<(abbr|accept(-charset)?|accesskey|action|alink|align|alt|archive|axis|background|bgcolor|border)=",
+ "\\<(abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|false|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|true|try|type|typeof|unsafe|unsized|use|virtual|where|while|yield)\\>",
+ "\\<(abstract|as|class|clone|(end)?declare|extends|function|implements|include(_once)?|inst(ance|ead)of|interface|namespace|new|private|protected|public|require(_once)?|static|trait|use|yield)\\>",
+ "\\<(abstract|class|extends|final|implements|import|instanceof|interface|native)\\>",
+ "\\<(abs|accept|alarm|atan2|bin(d|mode)|bless|caller|ch(dir|mod|op|omp|own|r|root)|close(dir)?|connect|cos|crypt)\\>",
+ "\\<(accept|continue|(d|s)nat|goto|jump|masquerade|return)\\>",
+ "\\<(add|delete|flush|insert|remove|replace)\\>",
+ "\\<(after|append|array|auto_(execok|import|load(_index)?|qualify)|binary|break)\\>",
+ "\\<(alarm|auto_load_pkg|bsearch|cat(close|gets|open)|ccollate|cconcat|cequal|chgrp|chmod|chown|chroot)\\>",
+ "\\<(and|as|assert|async|await|break|class|continue)\\>",
+ "\\<(and|cmp|eq|ge|gt|isa|le|lt|ne|not|or|x|xor)\\>",
+ "\\<(and|compl|lshift|or|rshift|xor)\\>",
+ "\\<(and|or|xor)\\>",
+ "\\<(append|cap|close|complex|copy|delete|imag|len|make|new|panic|print|println|real|recover)\\>",
+ "\\<(arp|bridge|inet|ingress|ip6?|netdev)\\>",
+ "\\<(array|bool|callable|const|float|global|int|object|string|var)\\>",
+ "\\<(asort|asorti|gensub|gsub|index|length|match)\\>",
+ "\\<(async|class|const|extends|function|let|this|typeof|var|void)\\>",
+ "\\<(as|case|of|class|data|default|deriving|do|forall|foreign|hiding|if|then|else|import|infix(l|r)?|instance|let|in|mdo|module|newtype|qualified|type|where)\\>",
+ "\\<(as|when|of)\\>",
+ "\\<(atan2|cos|exp|int|log|rand|sin|sqrt|srand)\\>",
+ "\\<(auto|bool|char|const|double|enum|extern|float|inline|int|long|restrict|short|signed|sizeof|static|struct|typedef|union|unsigned|void)\\>",
+ "\\<(await|export|import|throw|try|catch|finally|new|delete)\\>",
+ "\\<(awk|cat|cd|ch(grp|mod|own)|cp|cut|echo|env|grep|head|install|ln|make|mkdir|mv|popd|printf|pushd|rm|rmdir|sed|set|sort|tail|tar|touch|umask|unset)\\>",
+ "\\<(begin|end|object|struct|sig|for|while|do|done|to|downto)\\>",
+ "\\<(bindtextdomain|dcgettext|dcngettext)\\>",
+ "\\<(boolean|byte|char|double|float|int|long|new|short|this|transient|void)\\>",
+ "\\<(bool|u?int(8|16|32|64)?|float(32|64)|complex(64|128)|byte|rune|uintptr|string|error)\\>",
+ "\\<(break|case|catch|continue|default|do|else|finally|for|if|return|switch|throw|try|while)\\>",
+ "\\<(break|case|continue|do|done|elif|else|esac|exit|fi|for|function|if|in|read|return|select|shift|then|time|until|while)\\>",
+ "\\<(break|continue|fallthrough|goto|return)\\>",
+ "\\<(break|continue|goto|return)\\>",
+ "\\<(break|continue|goto|return)\\>",
+ "\\<(break|continue|return)\\>",
+ "\\<(break|continue|return|yield)\\>",
+ "\\<(case|catch|cd|clock|close|concat|continue|encoding|eof|error|eval|exec|exit|expr)\\>",
+ "\\<(case|catch|default|do|echo|else(if)?|end(for(each)?|if|switch|while)|final(ly)?|for(each)?|if|print|switch|throw|try|while)\\>",
+ "\\<(case|default|defer|else|for|go|if|range|select|switch)\\>",
+ "\\<(cell(padding|spacing)|char(off|set)?|checked|cite|class(id)?|compact|code(base|tag)?|cols(pan)?)=",
+ "\\<(chain|hook|policy|priority|ruleset|set|table|type|v?map)\\>",
+ "\\<(chan|const|func|interface|map|struct|type|var)\\>",
+ "\\<(cindex|clength|cmdtrace|commandloop|crange|csubstr|ctoken|ctype|dup|echo|execl)\\>",
+ "\\<(class|explicit|friend|mutable|namespace|override|private|protected|public|register|template|this|typename|using|virtual|volatile)\\>",
+ "\\<(class|namespace|template|public|protected|private|typename|this|friend|virtual|using|mutable|volatile|register|explicit)\\>",
+ "\\<(close|fflush|getline|next|nextfile|print|printf|system)\\>",
+ "\\<(content(editable)?|contextmenu|coords|data|datetime|declare|defer|dir|disabled|enctype)=",
+ "\\<(continue|die|do|else|elsif|exit|for(each)?|fork|goto|if|last|next|return|unless|until|while)\\>",
+ "\\<(dbm(close|open)|defined|delete|dump|each|eof|eval(bytes)?|exec|exists|exp|fc|fcntl|fileno|flock|fork|format|formline)\\>",
+ "\\<(declare|eval|exec|export|let|local)\\>",
+ "\\<(define|include)\\>",
+ "\\<(def|del|elif|else|except|finally|for|from)\\>",
+ "\\<(dofile|require)\\>",
+ "\\<(do|end|while|repeat|until|if|elseif|then|else|for|in|function|local|return|break)\\>",
+ "\\<(do|if|lambda|let(rec)?|map|unless|when)\\>",
+ "\\<(do|while|if|else|switch|case|default|for|each|in|of|with)\\>",
+ "\\<(drop|reject)\\>",
+ "\\<(exec|print)([[:blank:]]|$)",
+ "\\<(false|nil|true)\\>",
+ "\\<(fblocked|fconfigure|fcopy|file(event)?|flush|for|foreach|format|gets|glob|global|history)\\>",
+ "\\<(fcntl|flock|fork|fstat|ftruncate|funlock|host_info|id|infox|keyl(del|get|keys|set)|kill)\\>",
+ "\\<(float|double|BOOL|bool|char|int|short|long|id|sizeof|enum|void|static|const|struct|union|typedef|extern|(un)?signed|inline)\\>",
+ "\\<(for|frame(border)?|headers|height|hidden|href(lang)?|hspace|http-equiv|id|ismap)=",
+ "\\<(for|if|while|do|else|case|default|switch)\\>",
+ "\\<(for|if|while|do|else|in|delete|exit)\\>",
+ "\\<(function|extension|BEGIN|END)\\>",
+ "\\<(fun|function|functor|match|try|with)\\>",
+ "\\<(get(c|login|peername|pgrp|ppid|priority|(gr|pw)nam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport))\\>",
+ "\\<(global|if|import|in|is|lambda|nonlocal|not|or)\\>",
+ "\\<(goto|continue|break|return)\\>",
+ "\\<(if|else|for|while|do|switch|case|default)\\>",
+ "\\<(if|incr|info|interp|join|lappend|lindex|linsert|list|llength|load|lrange|lreplace|lsearch|lset|lsort)\\>",
+ "\\<(if|test|then|elif|else|fi|for|in|do|done)\\>",
+ "\\<(if|then|else)\\>",
+ "\\<(if|when|unless|cond|and|or|lambda|let|progn|while|dolist|dotimes)\\>",
+ "\\<(include|inherit|initializer)\\>",
+ "\\<(keys|kill|lc|lcfirst|length|link|listen|local(time)?|lock|log|lstat|map|mkdir|msg(ctl|get|snd|rcv)|oct)\\>",
+ "\\<(label|lang|link|longdesc|margin(height|width)|maxlength|media|method|multiple)=",
+ "\\<(lassign|lcontain|lempty|lgets|link|lmatch|loadlibindex|loop|lvar(cat|pop|push)|max|min|nice)\\>",
+ "\\<(let|val|method|in|and|rec|private|virtual|constraint)\\>",
+ "\\<(mktime|strftime|systime)\\>",
+ "\\<(my|no|our|package|sub|use)\\>",
+ "\\<(namespace|open|package|pid|puts|pwd|read|regexp|regsub|rename|return)\\>",
+ "\\<(name|nohref|noresize|noshade|object|onclick|onfocus|onload|onmouseover|profile|readonly|rel|rev)=",
+ "\\<(new|ref|mutable|lazy|assert|raise)\\>",
+ "\\<(next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)\\>",
+ "\\<(open(dir)?|ord|pack|pipe|pop|pos|printf?|prototype|push|q|qq|qr|qx|qw|quotemeta|rand|read(dir|line|link|pipe)?)\\>",
+ "\\<(package|import)\\>",
+ "\\<(package|private|protected|public|static|strictfp|super|synchronized|throws|volatile)\\>",
+ "\\<(pass|raise|return|try|while|with|yield)\\>",
+ "\\<(pg_catalog|public)\\>",
+ "\\<(pipe|profile|random|readdir|replicate|scan(context|file|match)|select|server_(accept|create)|signal)\\>",
+ "\\<(recv|redo|ref|rename|require|reset|reverse|rewinddir|rindex|rmdir|say|scalar|seek(dir)?|select|sem(ctl|get|op))\\>",
+ "\\<(require|provide)\\>",
+ "\\<(rows(pan)?|rules|scheme|scope|scrolling|selected|shape|size|span|src|standby|start|style|summary)=",
+ "\\<(scan|seek|set|socket|source|split|string|subst|switch|tclLog|tell|time|trace)\\>",
+ "\\<(send|set(pgrp|priority|sockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|splice|split)\\>",
+ "\\<(setq(-default|-local)?|setf|push|pop|declare(-function)?)\\>",
+ "\\<(sleep|sync|system|tclx_(findinit|fork|load_tndxs|sleep|system|wait)|times|translit|try_eval|umask|wait)\\>",
+ "\\<(split|sprintf|strtonum|sub|substr|tolower|toupper)\\>",
+ "\\<(sprintf|sqrt|srand|state?|study|substr|symlink|sys(call|open|read|seek|tem|write)|tell(dir)?|tied?|times?|try?)\\>",
+ "\\<(tabindex|target|text|title|type|usemap|valign|value(type)?|vlink|vspace|width|xmlns|xml:space)=",
+ "\\<(true|false)\\>",
+ "\\<(true|false|nil|iota|_)\\>",
+ "\\<(true|false|null)\\>",
+ "\\<(true|false|null)\\>",
+ "\\<(true|false|null|undefined)\\>",
+ "\\<(truncate|uc|ucfirst|umask|un(def|link|pack|shift|tie)|utime|values|vec|wait(pid)?|wantarray|warn|write)\\>",
+ "\\<(try|throw|catch|operator|new|delete)\\>",
+ "\\<(try|throw|catch|operator|new|delete)\\>",
+ "\\<(type|open|class|module|exception|external)\\>",
+ "\\<(t|nil)\\>",
+ "\\<(unknown|unset|update|uplevel|upvar|variable|vwait|while)\\>",
+ "\\<0x[[:xdigit:]]+(\\.[[:xdigit:]]*)?([Pp][+-]?[0-9]+)?\\>",
+ "\\<[-_.0-9]+\\>",
+ "\\<[0-9]+(\\.[0-9]*)?([Ee][+-]?[0-9]+)?\\>",
+ "\\<[0-9]+[eE][+-]?[0-9]+i?\\>",
+ "\\<[0-9]+\\.[0-9]*([eE][+-]?[0-9]+)?i?\\>",
+ "\\<[0-9]+i\\>",
+ "\\<[12][0-9]{3}\\.(0[1-9]|1[012])\\.(0[1-9]|[12][0-9]|3[01])\\>",
+ "\\<[A-Z]+[0-9A-Z_a-z]*|(\\$|@|@@)[0-9A-Z_a-z]+",
+ "\\<[A-Z][0-9a-z_]{2,}\\>",
+ "\\<[A-Z_][0-9A-Z_]*\\>",
+ "\\<[A-Z_]{2,}\\>",
+ "\\<[A-Za-z_][A-Za-z_0-9]*\\(",
+ "\\<[Nn]ano [1-8]\\.[0-9][-.[:alnum:]]* \"[^\"]+\"",
+ "\\<[[:alpha:]_][[:alnum:]_]*_t\\>",
+ "\\<[[:upper:]_[:digit:]]+\\>",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\",
+ "\\