diff --git a/components/prism-groovy.js b/components/prism-groovy.js
index 40bb8e195f..8201523899 100644
--- a/components/prism-groovy.js
+++ b/components/prism-groovy.js
@@ -1,68 +1,65 @@
-Prism.languages.groovy = Prism.languages.extend('clike', {
- 'string': [
- {
+(function (Prism) {
+
+ var interpolation = {
+ pattern: /((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,
+ lookbehind: true,
+ inside: {
+ 'interpolation-punctuation': {
+ pattern: /^\$\{?|\}$/,
+ alias: 'punctuation'
+ },
+ 'expression': {
+ pattern: /[\s\S]+/,
+ inside: null // see below
+ }
+ }
+ };
+
+ Prism.languages.groovy = Prism.languages.extend('clike', {
+ 'string': {
// https://groovy-lang.org/syntax.html#_dollar_slashy_string
- pattern: /("""|''')(?:[^\\]|\\[\s\S])*?\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,
+ pattern: /'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,
greedy: true
},
- {
+ 'keyword': /\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,
+ 'number': /\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,
+ 'operator': {
+ pattern: /(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,
+ lookbehind: true
+ },
+ 'punctuation': /\.+|[{}[\];(),:$]/
+ });
+
+ Prism.languages.insertBefore('groovy', 'string', {
+ 'shebang': {
+ pattern: /#!.+/,
+ alias: 'comment',
+ greedy: true
+ },
+ 'interpolation-string': {
// TODO: Slash strings (e.g. /foo/) can contain line breaks but this will cause a lot of trouble with
// simple division (see JS regex), so find a fix maybe?
- pattern: /(["'/])(?:\\.|(?!\1)[^\\\r\n])*\1/,
- greedy: true
+ pattern: /"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,
+ greedy: true,
+ inside: {
+ 'interpolation': interpolation,
+ 'string': /[\s\S]+/
+ }
}
- ],
- 'keyword': /\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,
- 'number': /\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,
- 'operator': {
- pattern: /(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,
- lookbehind: true
- },
- 'punctuation': /\.+|[{}[\];(),:$]/
-});
-
-Prism.languages.insertBefore('groovy', 'string', {
- 'shebang': {
- pattern: /#!.+/,
- alias: 'comment'
- }
-});
-
-Prism.languages.insertBefore('groovy', 'punctuation', {
- 'spock-block': /\b(?:and|cleanup|expect|given|setup|then|when|where):/
-});
-
-Prism.languages.insertBefore('groovy', 'function', {
- 'annotation': {
- pattern: /(^|[^.])@\w+/,
- lookbehind: true,
- alias: 'punctuation'
- }
-});
+ });
-// Handle string interpolation
-Prism.hooks.add('wrap', function (env) {
- if (env.language === 'groovy' && env.type === 'string') {
- var delimiter = env.content[0];
+ Prism.languages.insertBefore('groovy', 'punctuation', {
+ 'spock-block': /\b(?:and|cleanup|expect|given|setup|then|when|where):/
+ });
- if (delimiter != "'") {
- var pattern = /([^\\])(?:\$(?:\{.*?\}|[\w.]+))/;
- if (delimiter === '$') {
- pattern = /([^\$])(?:\$(?:\{.*?\}|[\w.]+))/;
- }
-
- // To prevent double HTML-encoding we have to decode env.content first
- env.content = env.content.replace(/</g, '<').replace(/&/g, '&');
+ Prism.languages.insertBefore('groovy', 'function', {
+ 'annotation': {
+ pattern: /(^|[^.])@\w+/,
+ lookbehind: true,
+ alias: 'punctuation'
+ }
+ });
- env.content = Prism.highlight(env.content, {
- 'expression': {
- pattern: pattern,
- lookbehind: true,
- inside: Prism.languages.groovy
- }
- });
+ interpolation.inside.expression.inside = Prism.languages.groovy;
- env.classes.push(delimiter === '/' ? 'regex' : 'gstring');
- }
- }
-});
+}(Prism));
diff --git a/components/prism-groovy.min.js b/components/prism-groovy.min.js
index fa3203b359..2242f9f61c 100644
--- a/components/prism-groovy.min.js
+++ b/components/prism-groovy.min.js
@@ -1 +1 @@
-Prism.languages.groovy=Prism.languages.extend("clike",{string:[{pattern:/("""|''')(?:[^\\]|\\[\s\S])*?\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,greedy:!0},{pattern:/(["'/])(?:\\.|(?!\1)[^\\\r\n])*\1/,greedy:!0}],keyword:/\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),Prism.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment"}}),Prism.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:and|cleanup|expect|given|setup|then|when|where):/}),Prism.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),Prism.hooks.add("wrap",function(e){if("groovy"===e.language&&"string"===e.type){var t=e.content[0];if("'"!=t){var n=/([^\\])(?:\$(?:\{.*?\}|[\w.]+))/;"$"===t&&(n=/([^\$])(?:\$(?:\{.*?\}|[\w.]+))/),e.content=e.content.replace(/</g,"<").replace(/&/g,"&"),e.content=Prism.highlight(e.content,{expression:{pattern:n,lookbehind:!0,inside:Prism.languages.groovy}}),e.classes.push("/"===t?"regex":"gstring")}}});
\ No newline at end of file
+!function(e){var n={pattern:/((?:^|[^\\$])(?:\\{2})*)\$(?:\w+|\{[^{}]*\})/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:null}}};e.languages.groovy=e.languages.extend("clike",{string:{pattern:/'''(?:[^\\]|\\[\s\S])*?'''|'(?:\\.|[^\\'\r\n])*'/,greedy:!0},keyword:/\b(?:abstract|as|assert|boolean|break|byte|case|catch|char|class|const|continue|def|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|in|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|trait|transient|try|void|volatile|while)\b/,number:/\b(?:0b[01_]+|0x[\da-f_]+(?:\.[\da-f_p\-]+)?|[\d_]+(?:\.[\d_]+)?(?:e[+-]?\d+)?)[glidf]?\b/i,operator:{pattern:/(^|[^.])(?:~|==?~?|\?[.:]?|\*(?:[.=]|\*=?)?|\.[@&]|\.\.<|\.\.(?!\.)|-[-=>]?|\+[+=]?|!=?|<(?:<=?|=>?)?|>(?:>>?=?|=)?|&[&=]?|\|[|=]?|\/=?|\^=?|%=?)/,lookbehind:!0},punctuation:/\.+|[{}[\];(),:$]/}),e.languages.insertBefore("groovy","string",{shebang:{pattern:/#!.+/,alias:"comment",greedy:!0},"interpolation-string":{pattern:/"""(?:[^\\]|\\[\s\S])*?"""|(["/])(?:\\.|(?!\1)[^\\\r\n])*\1|\$\/(?:[^/$]|\$(?:[/$]|(?![/$]))|\/(?!\$))*\/\$/,greedy:!0,inside:{interpolation:n,string:/[\s\S]+/}}}),e.languages.insertBefore("groovy","punctuation",{"spock-block":/\b(?:and|cleanup|expect|given|setup|then|when|where):/}),e.languages.insertBefore("groovy","function",{annotation:{pattern:/(^|[^.])@\w+/,lookbehind:!0,alias:"punctuation"}}),n.inside.expression.inside=e.languages.groovy}(Prism);
\ No newline at end of file
diff --git a/tests/languages/groovy+sas/groovy_inclusion.test b/tests/languages/groovy+sas/groovy_inclusion.test
index abc69a4464..e421028bbb 100644
--- a/tests/languages/groovy+sas/groovy_inclusion.test
+++ b/tests/languages/groovy+sas/groovy_inclusion.test
@@ -17,57 +17,63 @@ quit;
[
["step", "proc groovy"],
- ["proc-args",
- [
- ["arg", "classpath"],
- ["operator", "="],
- ["arg-value", "cp"],
- ["punctuation", ";"]
- ]
- ],
- [
- "proc-groovy", [
- ["comment", "/* Testing a comment */"],
- ["submit-statement", "submit parseonly"],
- [
- "groovy", [
- ["punctuation", ";"],
- ["keyword", "class"],
- ["class-name", ["Speaker"]],
- ["punctuation", "{"],
- ["keyword", "def"],
- ["function", "say"],
- ["punctuation", "("],
- " word ",
- ["punctuation", ")"],
- ["punctuation", "{"],
- "\r\n println ",
- ["string", "\"----> \\\"${word}\\\"\""],
- ["punctuation", "}"],
- ["punctuation", "}"]
- ]
- ],
- ["submit-statement", "endsubmit"],
- ["punctuation", ";"]
- ]
- ],
+ ["proc-args", [
+ ["arg", "classpath"],
+ ["operator", "="],
+ ["arg-value", "cp"],
+ ["punctuation", ";"]
+ ]],
+ ["proc-groovy", [
+ ["comment", "/* Testing a comment */"],
+
+ ["submit-statement", "submit parseonly"],
+ ["groovy", [
+ ["punctuation", ";"],
+
+ ["keyword", "class"],
+ ["class-name", ["Speaker"]],
+ ["punctuation", "{"],
+
+ ["keyword", "def"],
+ ["function", "say"],
+ ["punctuation", "("],
+ " word ",
+ ["punctuation", ")"],
+ ["punctuation", "{"],
+
+ "\r\n println ",
+ ["interpolation-string", [
+ ["string", "\"----> \\\""],
+ ["interpolation", [
+ ["interpolation-punctuation", "${"],
+ ["expression", ["word"]],
+ ["interpolation-punctuation", "}"]
+ ]],
+ ["string", "\\\"\""]
+ ]],
+
+ ["punctuation", "}"],
+
+ ["punctuation", "}"]
+ ]],
+ ["submit-statement", "endsubmit"],
+ ["punctuation", ";"]
+ ]],
["step", "quit"],
["punctuation", ";"],
+
["step", "proc groovy"],
- ["proc-args",
- [
- ["arg", "classpath"],
- ["operator", "="],
- ["arg-value", "cp"],
- ["punctuation", ";"]
- ]
- ],
- ["proc-groovy",[
+ ["proc-args", [
+ ["arg", "classpath"],
+ ["operator", "="],
+ ["arg-value", "cp"],
+ ["punctuation", ";"]
+ ]],
+ ["proc-groovy", [
["keyword", "eval"],
["string", "\"s = new Speaker(); s.say( \"\"Hi\"\" )\""],
["punctuation", ";"]
- ]
- ],
+ ]],
["step", "quit"],
["punctuation", ";"]
]
diff --git a/tests/languages/groovy/issue1049.html.test b/tests/languages/groovy/issue1049.html.test
index 0f0c6182bd..19e4005a21 100644
--- a/tests/languages/groovy/issue1049.html.test
+++ b/tests/languages/groovy/issue1049.html.test
@@ -7,9 +7,11 @@
----------------------------------------------------
-"&"
-"&&"
-"<"
-"<<"
-"&lt;"
-">"
+"&"
+
+ "&&"
+
+"<"
+"<<"
+"&lt;"
+">"
diff --git a/tests/languages/groovy/string-interpolation_feature.html.test b/tests/languages/groovy/string-interpolation_feature.html.test
index 15541878bd..17c502bd9e 100644
--- a/tests/languages/groovy/string-interpolation_feature.html.test
+++ b/tests/languages/groovy/string-interpolation_feature.html.test
@@ -35,96 +35,92 @@ $/$$foo $${42}/$
----------------------------------------------------
-
- "
-
- $
- foo
+
+ "
+
+ $
+ foo
- "
+ "
-
- "
-
- $
- {
- 42
- }
+
+ "
+
+ ${
+ 42
+ }
- "
+ "
-
- """
-
- $
- foo
+
+ """
+
+ $
+ foo
- """
+ """
-
- """
-
- $
- {
- 42
- }
+
+ """
+
+ ${
+ 42
+ }
- """
+ """
-
- /
-
- $
- foo
+
+ /
+
+ $
+ foo
- /
+ /
-
- /
-
- $
- {
- 42
- }
+
+ /
+
+ ${
+ 42
+ }
- /
+ /
-
- $/
-
- $
- foo
+
+ $/
+
+ $
+ foo
- /$
+ /$
-
- $/
-
- $
- {
- 42
- }
+
+ $/
+
+ ${
+ 42
+ }
- /$
+ /$
-"\$foo \${42}"
+"\$foo \${42}"
-"""\$foo \${42}"""
+"""\$foo \${42}"""
-/\$foo \${42}/
+/\$foo \${42}/
-$/$$foo $${42}/$
+$/$$foo $${42}/$
'$foo ${42}'
diff --git a/tests/languages/groovy/string_feature.test b/tests/languages/groovy/string_feature.test
index 95b0aa2a46..f52e22db82 100644
--- a/tests/languages/groovy/string_feature.test
+++ b/tests/languages/groovy/string_feature.test
@@ -33,29 +33,59 @@ bar"""
----------------------------------------------------
[
- ["string", "\"\"\"\"\"\""],
- ["string", "\"\"\"foo\"\"\""],
- ["string", "\"\"\"foo\r\nbar\"\"\""],
+ ["interpolation-string", [
+ ["string", "\"\"\"\"\"\""]
+ ]],
+ ["interpolation-string", [
+ ["string", "\"\"\"foo\"\"\""]
+ ]],
+ ["interpolation-string", [
+ ["string", "\"\"\"foo\r\nbar\"\"\""]
+ ]],
+
["string", "''''''"],
["string", "'''foo'''"],
["string", "'''foo\r\nbar'''"],
- ["string", "\"\""],
- ["string", "\"fo\\\"o\""],
+ ["interpolation-string", [
+ ["string", "\"\""]
+ ]],
+ ["interpolation-string", [
+ ["string", "\"fo\\\"o\""]
+ ]],
["string", "''"],
["string", "'fo\\'o'"],
- ["string", "/foo/"],
- ["string", "/fo\\/o/"],
+ ["interpolation-string", [
+ ["string", "/foo/"]
+ ]],
+ ["interpolation-string", [
+ ["string", "/fo\\/o/"]
+ ]],
- ["string", "$/fo$/$o/$"],
- ["string", "$/foo\r\nbar/$"],
- ["string", "\"foo /* comment */ bar\""],
+ ["interpolation-string", [
+ ["string", "$/fo$/"],
+ ["interpolation", [
+ ["interpolation-punctuation", "$"],
+ ["expression", ["o"]]
+ ]],
+ ["string", "/$"]
+ ]],
+ ["interpolation-string", [
+ ["string", "$/foo\r\nbar/$"]
+ ]],
+ ["interpolation-string", [
+ ["string", "\"foo /* comment */ bar\""]
+ ]],
["string", "'foo // bar'"],
["string", "'''foo\r\n/* comment */\r\nbar'''"],
["string", "'''hell\\'''o'''"],
- ["string", "\"\"\"foo\r\n// comment\r\nbar\"\"\""],
- ["string", "\"\"\"hell\\\"\"\"o\"\"\""]
+ ["interpolation-string", [
+ ["string", "\"\"\"foo\r\n// comment\r\nbar\"\"\""]
+ ]],
+ ["interpolation-string", [
+ ["string", "\"\"\"hell\\\"\"\"o\"\"\""]
+ ]]
]
----------------------------------------------------