diff --git a/.gitignore b/.gitignore index f480797..177c940 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ node_modules/ +test/ + *.local.* +*.js +*.yaml diff --git a/.vscodeignore b/.vscodeignore index 2ed8587..3fad453 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,5 +1,9 @@ .vscode/ .git/ +test/ node_modules/ + .gitignore *.local.* +*.js +*.yaml diff --git a/changelog.md b/changelog.md index a9de68b..8c1bd83 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,17 @@ # Changelog +## 1.4.0 +- Added breakpoint snippet. +- Added previous element selector syntax highlighting. +- Added regular expression syntax highlighting +- Added full numeric unit syntax highlighting. +- Changed variable syntax highlighting. +- Changed `!important` syntax highlighting. +- Changed selector separator syntax highlighting. +- Removed static comment inner syntax highlighting. +- Revamped internal syntax highlighting tokenisation. +- Fixed formatter not cleanup up colons and trailing spaces. + ## 1.3.1 - Added angle brackets as auto-enclosing characters. - Changed syntax highlighting of parser constants from `@const` to `@option`. diff --git a/formatters/formatter.js b/formatters/formatter.ts similarity index 83% rename from formatters/formatter.js rename to formatters/formatter.ts index 1c293cc..ce68fbb 100644 --- a/formatters/formatter.js +++ b/formatters/formatter.ts @@ -1,6 +1,6 @@ -var vscode = require("vscode") +import * as vscode from 'vscode'; -function activate(context) { +export function activate(context: vscode.ExtensionContext) { console.log('NovaSheets formatter activated') const formatter = vscode.languages.registerDocumentFormattingEditProvider('novasheets', { provideDocumentFormattingEdits: function (document) { @@ -22,12 +22,14 @@ function activate(context) { .replace(/@const\s+([A-Z]+)\s+(true|false|\d+)/g, '@const $1 $2') // CSS - .replace(/(?<=[{(][^})]*)([a-z-]+)\s*:(?!\/\/) */g, '$1: ') + .replace(/ *{/g, ' {') + .replace(/(?<=[{(][^}]*)([a-z-]+)\s*:(?!\/\/) */g, '$1: ') + .replace(/; *(?!})/g, '; ') .replace(/\s*;/g, ';') .replace(/!\s*important/g, '!important') // General cleanup - .replace(/ +(?=\n)/g, '') + .replace(/ +$/gm, '') const startOfDocument = document.lineAt(0).range.start const endOfDocument = document.lineAt(document.lineCount - 1).range.end @@ -37,6 +39,3 @@ function activate(context) { }); context.subscriptions.push(formatter) } - -exports.__esModule = true -exports.activate = activate diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3145bcb --- /dev/null +++ b/package-lock.json @@ -0,0 +1,294 @@ +{ + "name": "novasheets", + "version": "1.4.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "novasheets", + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "@types/vscode": "^1.54.0", + "typescript": "^4.2.3" + }, + "devDependencies": { + "yamljs": "^0.3.0" + }, + "engines": { + "vscode": "^1.52.0" + } + }, + "node_modules/@types/vscode": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.54.0.tgz", + "integrity": "sha512-sHHw9HG4bTrnKhLGgmEiOS88OLO/2RQytUN4COX9Djv81zc0FSZsSiYaVyjNidDzUSpXsySKBkZ31lk2/FbdCg==" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + } + }, + "dependencies": { + "@types/vscode": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.54.0.tgz", + "integrity": "sha512-sHHw9HG4bTrnKhLGgmEiOS88OLO/2RQytUN4COX9Djv81zc0FSZsSiYaVyjNidDzUSpXsySKBkZ31lk2/FbdCg==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "typescript": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + } + } + } +} diff --git a/package.json b/package.json index 2f62f45..92786b9 100644 --- a/package.json +++ b/package.json @@ -4,15 +4,19 @@ "description": "Syntax highlighter and formatter for NovaSheets files", "publisher": "Nixinova", "repository": "NovaSheets-vscode", - "version": "1.3.1", + "version": "1.4.0", "license": "ISC", "scripts": { - "compile": "yaml2json syntaxes/novasheets.tmLanguage.yaml --save" + "vscode:prepublish": "npm run compile", + "compile": "tsc && npm run tmlang", + "tmlang": "yaml2json syntaxes/novasheets.tmLanguage.yaml --save" }, "engines": { - "vscode": "^1.52.0" + "vscode": "^1.54.0" }, "categories": [ + "Formatters", + "Snippets", "Programming Languages" ], "activationEvents": [ @@ -40,9 +44,17 @@ "scopeName": "source.novasheets", "path": "./syntaxes/novasheets.tmLanguage.json" } + ], + "snippets": [ + { + "language": "novasheets", + "path": "./snippets.json" + } ] }, "devDependencies": { + "@types/vscode": "^1.54.0", + "typescript": "^4.2.3", "yamljs": "^0.3.0" } } diff --git a/readme.md b/readme.md index 4525a02..dcc6fb7 100644 --- a/readme.md +++ b/readme.md @@ -15,3 +15,6 @@ This extension is available in the [VSCode Marketplace](https://marketplace.visu # Usage Just load a NovaSheets file with a `.nvss` file extension in VSCode and NovaSheets syntax highlighting should occur. Format the file using the default formatting command (`Alt+Shift+F` by default). + +## Snippets +- `brkp`: Create a breakpoint using built-in function `$(@breakpoint)`. diff --git a/snippets.json b/snippets.json new file mode 100644 index 0000000..821705b --- /dev/null +++ b/snippets.json @@ -0,0 +1,13 @@ +{ + "Create breakpoint": { + "prefix": "brkp", + "body": [ + "$(@breakpoint | ${1:1000px} |", + "$2", + "|", + "$3", + ")" + ], + "description": "Create breakpoint" + } +} diff --git a/syntaxes/novasheets.tmLanguage.json b/syntaxes/novasheets.tmLanguage.json deleted file mode 100644 index 26e1d01..0000000 --- a/syntaxes/novasheets.tmLanguage.json +++ /dev/null @@ -1,312 +0,0 @@ -{ - "name": "NovaSheets", - "scopeName": "source.novasheets", - "fileTypes": [ - ".nvss" - ], - "patterns": [ - { - "include": "#variables" - }, - { - "include": "#objects" - }, - { - "include": "#parser_constant" - }, - { - "include": "#simple_breakpoint" - }, - { - "include": "#loop_identifier" - }, - { - "include": "#comments" - }, - { - "include": "#css" - }, - { - "include": "#other" - } - ], - "repository": { - "variables": { - "patterns": [ - { - "include": "#variable_declaration" - }, - { - "include": "#variable_ending" - }, - { - "include": "#variable" - }, - { - "include": "#parameter" - } - ] - }, - "variable_declaration": { - "match": "(@var)\\s+((?:[^|=)\\]](?!\\/\\/))+)(\\|(?:[^=)\\]](?!\\/\\/))+)*(=?)", - "captures": { - "1": { - "name": "keyword.variable.declarator.novasheets" - }, - "2": { - "name": "support.type.variable.default.novasheets" - }, - "3": { - "name": "keyword.control.variable.attribute.novasheets" - }, - "4": { - "name": "keyword.variable.declarator.novasheets" - } - } - }, - "variable_ending": { - "match": "@endvar", - "name": "keyword.variable.ending.declarator.novasheets" - }, - "variable": { - "begin": "(\\$\\()", - "beginCaptures": { - "1": { - "name": "constant.character.novasheets" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "constant.character.novasheets" - } - }, - "patterns": [ - { - "match": "(?<=\\()\\s*(@)?([^|=)]+)(?=\\)|\\|)", - "captures": { - "1": { - "name": "keyword.other.unit.variable.default.novasheets" - }, - "2": { - "name": "support.type.variable.default.novasheets" - } - } - }, - { - "match": "(?()]+)(>)", - "captures": { - "1": { - "name": "constant.character.novasheets" - }, - "2": { - "name": "entity.other.attribute-name.class.css" - }, - "3": { - "name": "constant.character.novasheets" - } - } - }, - { - "match": "(?<=>|})\\s*(\\<)(\\w+?)(\\>)", - "captures": { - "1": { - "name": "constant.character.novasheets" - }, - "2": { - "name": "support.type.property-name.css" - }, - "3": { - "name": "constant.character.novasheets" - } - } - } - ] - }, - "parser_constant": { - "match": "(@option)(?:(\\s+[A-Z_]+)(\\s+(?:[0-9]+|true|false)))?", - "captures": { - "1": { - "name": "keyword.variable.declarator.novasheets" - }, - "2": { - "name": "support.type.constant..parsernovasheets" - }, - "3": { - "name": "keyword.control.constant.parser.value.novasheets" - } - } - }, - "simple_breakpoint": { - "match": "(@(?!\\w))|\\.{2,}", - "captures": { - "1": { - "name": "keyword.control.at-rule" - }, - "2": { - "name": "constant.character.novasheets" - } - } - }, - "loop_identifier": { - "match": "\\$i|\\$v\\[?|(?<=\\$v\\[[^\\]]*?)\\]", - "name": "keyword.variable.identifier.loop.novasheets" - }, - "comments": { - "patterns": [ - { - "match": "(?' + endCaptures: + 0: { name: constant.character.substitution.end.novasheets } + patterns: + - name: entity.name.tag.css.substitution.novasheets + match: '[^>]+' - # Declaration substitution - - match: "(\\$<)([\\s\\w.:~+>()]+)(>)" - #example: $<.selector> - captures: - '1': { name: constant.character.novasheets } - '2': { name: entity.other.attribute-name.class.css } - '3': { name: constant.character.novasheets } + # Attribute retrieval + - name: meta.block.attribute.novasheets + begin: '<' + beginCaptures: + 0: { name: constant.character.substitution.begin.novasheets } + end: '>' + endCaptures: + 0: { name: constant.character.substitution.end.novasheets } + patterns: + - name: entity.other.attribute-name.novasheets + match: '[^>]+' - # Object getter - - match: "(?<=>|})\\s*(\\<)(\\w+?)(\\>)" - #example: - captures: - '1': { name: constant.character.novasheets } - '2': { name: support.type.property-name.css } - '3': { name: constant.character.novasheets } - - parser_constant: - match: "(@option)(?:(\\s+[A-Z_]+)(\\s+(?:[0-9]+|true|false)))?" - #example: @option CONST_NAME true - captures: - '1': { name: keyword.variable.declarator.novasheets } - '2': { name: support.type.constant..parsernovasheets } - '3': { name: keyword.control.constant.parser.value.novasheets } - - simple_breakpoint: - match: "(@(?!\\w))|\\.{2,}" - captures: - '1': { name: keyword.control.at-rule } - '2': { name: constant.character.novasheets } - - loop_identifier: - match: "\\$i|\\$v\\[?|(?<=\\$v\\[[^\\]]*?)\\]" - name: keyword.variable.identifier.loop.novasheets + loop-identifier: + patterns: + - name: constant.character.identifier.loop.novasheets + begin: '\$v(\[)' + beginCaptures: + 0: { name: punctuation.definition.identifier.begin.novasheets } + end: '\]' + endCaptures: + 0: { name: punctuation.definition.identifier.end.novasheets } + - name: constant.character.identifier.loop.novasheets + match: '\$i|\$v' comments: patterns: + # Inline comment + - name: comment.line.double-slash.novasheets + begin: '(?\[\]])(?![^}]*$)' + end: '(?=\{)' + patterns: + # Element + - name: entity.name.tag.css.selector.element.css + match: '(?<=\s|^|,)[A-Za-z]+[0-9]?(?=\s|[\[,.#:+~>])' + # Class + - name: entity.name.tag.css.selector.class.css + match: '(\.)(?>\\\s|[^\s,.#:+~>\[\]])+' + captures: + 1: { name: punctuation.accessor.selector.class.css } + # ID + - name: entity.name.tag.css.selector.id.css + match: '(#)[^\s,.#:+~>\[\]]+' + captures: + 1: { name: punctuation.accessor.selector.id.css } + # Pseudo-element/class + - name: entity.name.tag.css.selector.pseudo.css + match: '(::?)[^\s,.#:+~>\[\]]+' + captures: + 1: { name: punctuation.accessor.selector.pseudo.css } + # Attributes + - name: entity.name.tag.css.selector.attribute.css + begin: '\[' + beginCaptures: + 0: { name: punctuation.accessor.selector.attribute.begin.css } + end: '\]' + endCaptures: + 0: { name: punctuation.accessor.selector.attribute.end.css } + # Function + - name: entity.name.tag.css.selector.function.css + begin: '\(' + beginCaptures: + 0: { name: punctuation.accessor.selector.function.begin.css } + end: '\)' + endCaptures: + 0: { name: punctuation.accessor.selector.function.end.css } + # Sliced parts + - name: entity.name.tag.css.selector.sliced.css + match: '(?<=&|%)\S+' + # Wildcard + - name: constant.character.wildcard.css + match: '\*' + # Comma + - name: punctuation.separator.selector.css + match: ',' + # Breakpoint + - name: keyword.control.breakpoint.novasheets + match: '@|\.{2,}' + # Parent selector + - name: constant.character.selector.parent.novasheets + match: '&' + # Previous selector + - name: constant.character.selector.previous.novasheets + match: '%' + # Other + - include: '#novasheets' + - include: '#chars' - # URL - - match: "[a-z]+://\\w+(\\.\\w+)+(/[^\\s)]+)?" - name: string.unquoted markup.underline.link - - # Selector - - match: "(?