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 @@ ---------------------------------------------------- -"&amp;" -"&amp;&amp;" -"&lt;" -"&lt;&lt;" -"&amp;lt;" -"&gt;" +"&amp;" + + "&amp;&amp;" + +"&lt;" +"&lt;&lt;" +"&amp;lt;" +"&gt;" 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}/$ ---------------------------------------------------- // Double quoted: interpolation - - " - - $ - foo + + " + + $ + foo - " + " - - " - - $ - { - 42 - } + + " + + ${ + 42 + } - " + " // Triple double quoted: interpolation - - """ - - $ - foo + + """ + + $ + foo - """ + """ - - """ - - $ - { - 42 - } + + """ + + ${ + 42 + } - """ + """ // Slashy string: interpolation - - / - - $ - foo + + / + + $ + foo - / + / - - / - - $ - { - 42 - } + + / + + ${ + 42 + } - / + / // Dollar slashy string: interpolation - - $/ - - $ - foo + + $/ + + $ + foo - /$ + /$ - - $/ - - $ - { - 42 - } + + $/ + + ${ + 42 + } - /$ + /$ // Double quoted: no interpolation (escaped) -"\$foo \${42}" +"\$foo \${42}" // Triple double quoted: no interpolation (escaped) -"""\$foo \${42}""" +"""\$foo \${42}""" // Slashy string: no interpolation (escaped) -/\$foo \${42}/ +/\$foo \${42}/ // Dollar slashy string: no interpolation (escaped) -$/$$foo $${42}/$ +$/$$foo $${42}/$ // Single quoted string: no interpolation '$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\"\"\""] + ]] ] ----------------------------------------------------