From 3b0759f98a5c51bc6d4ef3fd1a2b478eb5c6839f Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 14 Dec 2015 14:31:51 -0800 Subject: [PATCH] Support HTML and CSS syntax in template strings suggesting those formats --- grammars/javascript.cson | 50 +++++++++++++++++++++++++ spec/javascript-spec.coffee | 74 +++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/grammars/javascript.cson b/grammars/javascript.cson index cd0e76b7..b37c984d 100644 --- a/grammars/javascript.cson +++ b/grammars/javascript.cson @@ -1009,6 +1009,56 @@ } ] } + { + 'begin': '((\\w+)?(html|HTML|Html))\\s*(`)' + 'beginCaptures': + '1': + 'name': 'entity.name.function.js' + '4': + 'name': 'punctuation.definition.string.begin.js' + 'end': '`' + 'endCaptures': + '0': + 'name': 'punctuation.definition.string.end.js' + 'name': 'string.quoted.template.html.js' + 'patterns': [ + { + 'match': '\\\\(x\\h{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)' + 'name': 'constant.character.escape.js' + } + { + 'include': '#interpolated_js' + } + { + 'include': 'text.html.basic' + } + ] + } + { + 'begin': '((\\w+)?(css|CSS|Css))\\s*(`)' + 'beginCaptures': + '1': + 'name': 'entity.name.function.js' + '4': + 'name': 'punctuation.definition.string.begin.js' + 'end': '`' + 'endCaptures': + '0': + 'name': 'punctuation.definition.string.end.js' + 'name': 'string.quoted.template.css.js' + 'patterns': [ + { + 'match': '\\\\(x\\h{2}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)' + 'name': 'constant.character.escape.js' + } + { + 'include': '#interpolated_js' + } + { + 'include': 'source.css' + } + ] + } { 'begin': '`' 'beginCaptures': diff --git a/spec/javascript-spec.coffee b/spec/javascript-spec.coffee index a22d2134..2e7d26e3 100644 --- a/spec/javascript-spec.coffee +++ b/spec/javascript-spec.coffee @@ -495,6 +495,80 @@ describe "Javascript grammar", -> expect(tokens[13]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] expect(tokens[14]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.js', 'punctuation.definition.string.end.js'] + describe "ES6 tagged HTML string templates", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('html`hey ${name}`') + expect(tokens[0]).toEqual value: 'html', scopes: [ 'source.js', 'string.quoted.template.html.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[2]).toEqual value: 'hey ', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[3]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[4]).toEqual value: 'name', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source'] + expect(tokens[5]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[6]).toEqual value: '', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[7]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.end.js'] + + describe "ES6 tagged HTML string templates with expanded function name", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('escapeHTML`hey ${name}`') + expect(tokens[0]).toEqual value: 'escapeHTML', scopes: [ 'source.js', 'string.quoted.template.html.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[2]).toEqual value: 'hey ', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[3]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[4]).toEqual value: 'name', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source'] + expect(tokens[5]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[6]).toEqual value: '', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[7]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.end.js'] + + describe "ES6 tagged HTML string templates with expanded function name and white space", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('escapeHTML `hey ${name}`') + expect(tokens[0]).toEqual value: 'escapeHTML', scopes: [ 'source.js', 'string.quoted.template.html.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: ' ', scopes: [ 'source.js', 'string.quoted.template.html.js' ] + expect(tokens[2]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[3]).toEqual value: 'hey ', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[4]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[5]).toEqual value: 'name', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source'] + expect(tokens[6]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.html.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[7]).toEqual value: '', scopes: ['source.js', 'string.quoted.template.html.js'] + expect(tokens[8]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.html.js', 'punctuation.definition.string.end.js'] + + describe "ES6 tagged CSS string templates", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('css`.highlight { border: ${borderSize}; }`') + expect(tokens[0]).toEqual value: 'css', scopes: [ 'source.js', 'string.quoted.template.css.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[2]).toEqual value: '.highlight { border: ', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[3]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[4]).toEqual value: 'borderSize', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source'] + expect(tokens[5]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[6]).toEqual value: '; }', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[7]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.end.js'] + + describe "ES6 tagged CSS string templates with expanded function name", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('escapeCSS`.highlight { border: ${borderSize}; }`') + expect(tokens[0]).toEqual value: 'escapeCSS', scopes: [ 'source.js', 'string.quoted.template.css.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[2]).toEqual value: '.highlight { border: ', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[3]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[4]).toEqual value: 'borderSize', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source'] + expect(tokens[5]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[6]).toEqual value: '; }', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[7]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.end.js'] + + describe "ES6 tagged CSS string templates with expanded function name and white space", -> + it "tokenizes them as strings", -> + {tokens} = grammar.tokenizeLine('escapeCSS `.highlight { border: ${borderSize}; }`') + expect(tokens[0]).toEqual value: 'escapeCSS', scopes: [ 'source.js', 'string.quoted.template.css.js', 'entity.name.function.js' ] + expect(tokens[1]).toEqual value: ' ', scopes: [ 'source.js', 'string.quoted.template.css.js' ] + expect(tokens[2]).toEqual value: '`', scopes: [ 'source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.begin.js' ] + expect(tokens[3]).toEqual value: '.highlight { border: ', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[4]).toEqual value: '${', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[5]).toEqual value: 'borderSize', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source'] + expect(tokens[6]).toEqual value: '}', scopes: ['source.js', 'string.quoted.template.css.js', 'source.js.embedded.source', 'punctuation.section.embedded.js'] + expect(tokens[7]).toEqual value: '; }', scopes: ['source.js', 'string.quoted.template.css.js'] + expect(tokens[8]).toEqual value: '`', scopes: ['source.js', 'string.quoted.template.css.js', 'punctuation.definition.string.end.js'] + describe "ES6 class", -> it "tokenizes class", -> {tokens} = grammar.tokenizeLine('class MyClass')