From b14128e0d95d19a65df45ff8320a5ddcb7455442 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 20:10:00 -0400 Subject: [PATCH 01/13] Add syntax highlighting tests wip --- .github/workflows/ci.yml | 12 + .../scripts/build.mjs | 11 +- .../tailwindcss-language-syntax/package.json | 16 + .../syntaxes/css.json | 1871 +++++++++++++++++ .../tests/__snapshots__/syntax.test.ts.snap | 1114 ++++++++++ .../tests/default-map.ts | 20 + .../tests/scopes.ts | 41 + .../tests/syntax.test.ts | 282 +++ .../tests/utils.ts | 150 ++ .../tailwindcss-language-syntax/tsconfig.json | 14 + .../vitest.config.ts | 7 + pnpm-lock.yaml | 221 ++ 12 files changed, 3757 insertions(+), 2 deletions(-) create mode 100644 packages/tailwindcss-language-syntax/package.json create mode 100644 packages/tailwindcss-language-syntax/syntaxes/css.json create mode 100644 packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap create mode 100644 packages/tailwindcss-language-syntax/tests/default-map.ts create mode 100644 packages/tailwindcss-language-syntax/tests/scopes.ts create mode 100644 packages/tailwindcss-language-syntax/tests/syntax.test.ts create mode 100644 packages/tailwindcss-language-syntax/tests/utils.ts create mode 100755 packages/tailwindcss-language-syntax/tsconfig.json create mode 100644 packages/tailwindcss-language-syntax/vitest.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e572b9a86..e5d753c62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,18 @@ jobs: - name: Install dependencies run: pnpm install + - name: Run syntax tests + run: | + cd packages/tailwindcss-language-syntax && + pnpm run build && + pnpm run test + + - name: Run service tests + run: | + cd packages/tailwindcss-language-service && + pnpm run build && + pnpm run test + - name: Run tests run: | cd packages/tailwindcss-language-server && diff --git a/packages/tailwindcss-language-service/scripts/build.mjs b/packages/tailwindcss-language-service/scripts/build.mjs index 128426bed..68ba778bb 100644 --- a/packages/tailwindcss-language-service/scripts/build.mjs +++ b/packages/tailwindcss-language-service/scripts/build.mjs @@ -3,8 +3,9 @@ import { spawnSync } from 'node:child_process' import esbuild from 'esbuild' import minimist from 'minimist' import { nodeExternalsPlugin } from 'esbuild-node-externals' +import { fileURLToPath } from 'node:url' -const __dirname = new URL('.', import.meta.url).pathname +const __dirname = path.dirname(fileURLToPath(import.meta.url)) const args = minimist(process.argv.slice(2), { boolean: ['watch', 'minify'], @@ -30,7 +31,13 @@ let build = await esbuild.context({ // Call the tsc command to generate the types spawnSync( 'tsc', - ['-p', path.resolve(__dirname, './tsconfig.build.json'), '--emitDeclarationOnly', '--outDir', path.resolve(__dirname, '../dist')], + [ + '-p', + path.resolve(__dirname, './tsconfig.build.json'), + '--emitDeclarationOnly', + '--outDir', + path.resolve(__dirname, '../dist'), + ], { stdio: 'inherit', }, diff --git a/packages/tailwindcss-language-syntax/package.json b/packages/tailwindcss-language-syntax/package.json new file mode 100644 index 000000000..5c2166f22 --- /dev/null +++ b/packages/tailwindcss-language-syntax/package.json @@ -0,0 +1,16 @@ +{ + "name": "@tailwindcss/language-syntax", + "version": "0.0.0", + "private": true, + "scripts": { + "test": "vitest", + "build": " " + }, + "devDependencies": { + "@types/node": "^18.19.33", + "dedent": "^1.5.3", + "vitest": "^3.1.4", + "vscode-oniguruma": "^2.0.1", + "vscode-textmate": "^9.2.0" + } +} diff --git a/packages/tailwindcss-language-syntax/syntaxes/css.json b/packages/tailwindcss-language-syntax/syntaxes/css.json new file mode 100644 index 000000000..79ef22eb4 --- /dev/null +++ b/packages/tailwindcss-language-syntax/syntaxes/css.json @@ -0,0 +1,1871 @@ +{ + "__tailwind_notes__": [ + "This was copied from VSCode and is used for testing purposes", + "https://github.com/microsoft/vscode/blob/2e59a779912bc1b7b2505ae52aff3a7648c24857/extensions/css/syntaxes/css.tmLanguage.json", + "It is covered by the MIT license:", + "https://github.com/microsoft/vscode/blob/2e59a779912bc1b7b2505ae52aff3a7648c24857/LICENSE.txt" + ], + "information_for_contributors": [ + "This file has been converted from https://github.com/microsoft/vscode-css/blob/master/grammars/css.cson", + "If you want to provide a fix or improvement, please create a pull request against the original repository.", + "Once accepted there, we are happy to receive an update request." + ], + "version": "https://github.com/microsoft/vscode-css/commit/a927fe2f73927bf5c25d0b0c4dd0e63d69fd8887", + "name": "CSS", + "scopeName": "source.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#combinators" + }, + { + "include": "#selector" + }, + { + "include": "#at-rules" + }, + { + "include": "#rule-list" + } + ], + "repository": { + "at-rules": { + "patterns": [ + { + "begin": "\\A(?:\\xEF\\xBB\\xBF)?(?i:(?=\\s*@charset\\b))", + "end": ";|(?=$)", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.charset.css", + "patterns": [ + { + "captures": { + "1": { + "name": "invalid.illegal.not-lowercase.charset.css" + }, + "2": { + "name": "invalid.illegal.leading-whitespace.charset.css" + }, + "3": { + "name": "invalid.illegal.no-whitespace.charset.css" + }, + "4": { + "name": "invalid.illegal.whitespace.charset.css" + }, + "5": { + "name": "invalid.illegal.not-double-quoted.charset.css" + }, + "6": { + "name": "invalid.illegal.unclosed-string.charset.css" + }, + "7": { + "name": "invalid.illegal.unexpected-characters.charset.css" + } + }, + "match": "(?x) # Possible errors:\n\\G\n((?!@charset)@\\w+) # Not lowercase (@charset is case-sensitive)\n|\n\\G(\\s+) # Preceding whitespace\n|\n(@charset\\S[^;]*) # No whitespace after @charset\n|\n(?<=@charset) # Before quoted charset name\n(\\x20{2,}|\\t+) # More than one space used, or a tab\n|\n(?<=@charset\\x20) # Beginning of charset name\n([^\";]+) # Not double-quoted\n|\n(\"[^\"]+$) # Unclosed quote\n|\n(?<=\") # After charset name\n([^;]+) # Unexpected junk instead of semicolon" + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.charset.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "((@)charset)(?=\\s)" + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.css" + } + }, + "end": "\"|$", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.css" + } + }, + "name": "string.quoted.double.css", + "patterns": [ + { + "begin": "(?:\\G|^)(?=(?:[^\"])+$)", + "end": "$", + "name": "invalid.illegal.unclosed.string.css" + } + ] + } + ] + }, + { + "begin": "(?i)((@)import)(?:\\s+|$|(?=['\"]|/\\*))", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.import.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.import.css", + "patterns": [ + { + "begin": "\\G\\s*(?=/\\*)", + "end": "(?<=\\*/)\\s*", + "patterns": [ + { + "include": "#comment-block" + } + ] + }, + { + "include": "#string" + }, + { + "include": "#url" + }, + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "(?i)((@)font-face)(?=\\s*|{|/\\*|$)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.font-face.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?!\\G)", + "name": "meta.at-rule.font-face.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(@)page(?=[\\s:{]|/\\*|$)", + "captures": { + "0": { + "name": "keyword.control.at-rule.page.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*($|[:{;]))", + "name": "meta.at-rule.page.css", + "patterns": [ + { + "include": "#rule-list" + } + ] + }, + { + "begin": "(?i)(?=@media(\\s|\\(|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)media", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.media.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.media.header.css", + "patterns": [ + { + "include": "#media-query-list" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.media.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.media.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.media.body.css", + "patterns": [ + { + "include": "$self" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@counter-style([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)counter-style", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.counter-style.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*{)", + "name": "meta.at-rule.counter-style.header.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "captures": { + "0": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(?:[-a-zA-Z_] | [^\\x00-\\x7F]) # First letter\n(?:[-a-zA-Z0-9_] | [^\\x00-\\x7F] # Remainder of identifier\n |\\\\(?:[0-9a-fA-F]{1,6}|.)\n)*", + "name": "variable.parameter.style-name.css" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.property-list.begin.bracket.curly.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.property-list.end.bracket.curly.css" + } + }, + "name": "meta.at-rule.counter-style.body.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#rule-list-innards" + } + ] + } + ] + }, + { + "begin": "(?i)(?=@document([\\s'\"{;]|/\\*|$))", + "end": "(?<=})(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)document", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.document.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": "(?=\\s*[{;])", + "name": "meta.at-rule.document.header.css", + "patterns": [ + { + "begin": "(?i)(?>>", + "name": "invalid.deprecated.combinator.css" + }, + { + "match": ">>|>|\\+|~", + "name": "keyword.operator.combinator.css" + } + ] + }, + "commas": { + "match": ",", + "name": "punctuation.separator.list.comma.css" + }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.css" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.css" + } + }, + "name": "comment.block.css" + }, + "escapes": { + "patterns": [ + { + "match": "\\\\[0-9a-fA-F]{1,6}", + "name": "constant.character.escape.codepoint.css" + }, + { + "begin": "\\\\$\\s*", + "end": "^(?<:=]|\\)|/\\*) # Terminates cleanly" + }, + "media-feature-keywords": { + "match": "(?xi)\n(?<=^|\\s|:|\\*/)\n(?: portrait # Orientation\n | landscape\n | progressive # Scan types\n | interlace\n | fullscreen # Display modes\n | standalone\n | minimal-ui\n | browser\n | hover\n)\n(?=\\s|\\)|$)", + "name": "support.constant.property-value.css" + }, + "media-query": { + "begin": "\\G", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#escapes" + }, + { + "include": "#media-types" + }, + { + "match": "(?i)(?<=\\s|^|,|\\*/)(only|not)(?=\\s|{|/\\*|$)", + "name": "keyword.operator.logical.$1.media.css" + }, + { + "match": "(?i)(?<=\\s|^|\\*/|\\))and(?=\\s|/\\*|$)", + "name": "keyword.operator.logical.and.media.css" + }, + { + "match": ",(?:(?:\\s*,)+|(?=\\s*[;){]))", + "name": "invalid.illegal.comma.css" + }, + { + "include": "#commas" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.css" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.css" + } + }, + "patterns": [ + { + "include": "#media-features" + }, + { + "include": "#media-feature-keywords" + }, + { + "match": ":", + "name": "punctuation.separator.key-value.css" + }, + { + "match": ">=|<=|=|<|>", + "name": "keyword.operator.comparison.css" + }, + { + "captures": { + "1": { + "name": "constant.numeric.css" + }, + "2": { + "name": "keyword.operator.arithmetic.css" + }, + "3": { + "name": "constant.numeric.css" + } + }, + "match": "(\\d+)\\s*(/)\\s*(\\d+)", + "name": "meta.ratio.css" + }, + { + "include": "#numeric-values" + }, + { + "include": "#comment-block" + } + ] + } + ] + }, + "media-query-list": { + "begin": "(?=\\s*[^{;])", + "end": "(?=\\s*[{;])", + "patterns": [ + { + "include": "#media-query" + } + ] + }, + "media-types": { + "captures": { + "1": { + "name": "support.constant.media.css" + }, + "2": { + "name": "invalid.deprecated.constant.media.css" + } + }, + "match": "(?xi)\n(?<=^|\\s|,|\\*/)\n(?:\n # Valid media types\n (all|print|screen|speech)\n |\n # Deprecated in Media Queries 4: http://dev.w3.org/csswg/mediaqueries/#media-types\n (aural|braille|embossed|handheld|projection|tty|tv)\n)\n(?=$|[{,\\s;]|/\\*)" + }, + "numeric-values": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.constant.css" + } + }, + "match": "(#)(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\\b", + "name": "constant.other.color.rgb-value.hex.css" + }, + { + "captures": { + "1": { + "name": "keyword.other.unit.percentage.css" + }, + "2": { + "name": "keyword.other.unit.${2:/downcase}.css" + } + }, + "match": "(?xi) (?+~|] # - Followed by another selector\n | /\\* # - Followed by a block comment\n )\n |\n # Name contains unescaped ASCII symbol\n (?: # Check for acceptable preceding characters\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # - Valid selector character\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # - Escape sequence\n )*\n (?: # Invalid punctuation\n [!\"'%&(*;+~|] # - Another selector\n | /\\* # - A block comment\n)", + "name": "entity.other.attribute-name.class.css" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.entity.css" + }, + "2": { + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(\\#)\n(\n -?\n (?![0-9])\n (?:[-a-zA-Z0-9_]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n)\n(?=$|[\\s,.\\#)\\[:{>+~|]|/\\*)", + "name": "entity.other.attribute-name.id.css" + }, + { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.definition.entity.begin.bracket.square.css" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.definition.entity.end.bracket.square.css" + } + }, + "name": "meta.attribute-selector.css", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#string" + }, + { + "captures": { + "1": { + "name": "storage.modifier.ignore-case.css" + } + }, + "match": "(?<=[\"'\\s]|^|\\*/)\\s*([iI])\\s*(?=[\\s\\]]|/\\*|$)" + }, + { + "captures": { + "1": { + "name": "string.unquoted.attribute-value.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)(?<==)\\s*((?!/\\*)(?:[^\\\\\"'\\s\\]]|\\\\.)+)" + }, + { + "include": "#escapes" + }, + { + "match": "[~|^$*]?=", + "name": "keyword.operator.pattern.css" + }, + { + "match": "\\|", + "name": "punctuation.separator.css" + }, + { + "captures": { + "1": { + "name": "entity.other.namespace-prefix.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n# Qualified namespace prefix\n( -?(?!\\d)(?:[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+\n| \\*\n)\n# Lookahead to ensure there's a valid identifier ahead\n(?=\n \\| (?!\\s|=|$|\\])\n (?: -?(?!\\d)\n | [\\\\\\w-]\n | [^\\x00-\\x7F]\n )\n)" + }, + { + "captures": { + "1": { + "name": "entity.other.attribute-name.css", + "patterns": [ + { + "include": "#escapes" + } + ] + } + }, + "match": "(?x)\n(-?(?!\\d)(?>[\\w-]|[^\\x00-\\x7F]|\\\\(?:[0-9a-fA-F]{1,6}|.))+)\n\\s*\n(?=[~|^\\]$*=]|/\\*)" + } + ] + }, + { + "include": "#pseudo-classes" + }, + { + "include": "#pseudo-elements" + }, + { + "include": "#functional-pseudo-classes" + }, + { + "match": "(?x) (?\\s,.\\#|){:\\[]|/\\*|$)", + "name": "entity.name.tag.css" + }, + "unicode-range": { + "captures": { + "0": { + "name": "constant.other.unicode-range.css" + }, + "1": { + "name": "punctuation.separator.dash.unicode-range.css" + } + }, + "match": "(? extends Map { + constructor(private factory: (key: T, self: DefaultMap) => V) { + super() + } + + get(key: T): V { + let value = super.get(key) + + if (value === undefined) { + value = this.factory(key, this) + this.set(key, value) + } + + return value + } +} diff --git a/packages/tailwindcss-language-syntax/tests/scopes.ts b/packages/tailwindcss-language-syntax/tests/scopes.ts new file mode 100644 index 000000000..eec85ef51 --- /dev/null +++ b/packages/tailwindcss-language-syntax/tests/scopes.ts @@ -0,0 +1,41 @@ +export interface ScopeEntry { + content: Promise<{ default: object }> + inject: string[] +} + +export const KNOWN_SCOPES: Record = { + 'source.css': { + content: import('../syntaxes/css.json'), + inject: [ + 'tailwindcss.at-rules.injection', + 'tailwindcss.at-apply.injection', + 'tailwindcss.theme-fn.injection', + 'tailwindcss.screen-fn.injection', + ], + }, + + 'source.css.tailwind': { + content: import('../../vscode-tailwindcss/syntaxes/source.css.tailwind.tmLanguage.json'), + inject: [], + }, + + 'tailwindcss.at-apply.injection': { + content: import('../../vscode-tailwindcss/syntaxes/at-apply.tmLanguage.json'), + inject: [], + }, + + 'tailwindcss.at-rules.injection': { + content: import('../../vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json'), + inject: [], + }, + + 'tailwindcss.theme-fn.injection': { + content: import('../../vscode-tailwindcss/syntaxes/theme-fn.tmLanguage.json'), + inject: [], + }, + + 'tailwindcss.screen-fn.injection': { + content: import('../../vscode-tailwindcss/syntaxes/screen-fn.tmLanguage.json'), + inject: [], + }, +} diff --git a/packages/tailwindcss-language-syntax/tests/syntax.test.ts b/packages/tailwindcss-language-syntax/tests/syntax.test.ts new file mode 100644 index 000000000..fa68eab3a --- /dev/null +++ b/packages/tailwindcss-language-syntax/tests/syntax.test.ts @@ -0,0 +1,282 @@ +import { test } from 'vitest' +import dedent, { type Dedent } from 'dedent' +import { loadGrammar } from './utils' + +const css: Dedent = dedent + +let grammar = await loadGrammar() + +test('@theme', async ({ expect }) => { + let result = await grammar.tokenize(css` + @theme { + --color: red; + } + @theme static { + --color: red; + } + @theme inline deprecated { + --color: red; + } + @theme prefix(tw) inline { + --color: red; + } + + @theme { + --spacing: initial; + --color-*: initial; + --animate-pulse: 1s pulse infinite; + + @keyframes pulse { + 0%, + 100% { + opacity: 0; + } + 50% { + opacity: 1; + } + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@import', async ({ expect }) => { + let result = await grammar.tokenize(css` + @import './test.css'; + + @import './test.css' prefix(tw); + @import './test.css' layer(utilities) prefix(tw); + + @import './test.css' source(none); + @import './test.css' source('./foo'); + @import './test.css' layer(utilities) source('./foo'); + + @import './test.css' theme(static); + @import './test.css' theme(static default inline); + @import './test.css' theme(reference deprecated); + @import './test.css' theme(prefix(tw) reference); + @import './test.css' theme(default invalid reference); + + @reference './test.css'; + + @reference './test.css' prefix(tw); + @reference './test.css' layer(utilities) prefix(tw); + + @reference './test.css' source(none); + @reference './test.css' source('./foo'); + @reference './test.css' layer(utilities) source('./foo'); + + @reference './test.css' theme(static); + @reference './test.css' theme(static default inline); + @reference './test.css' theme(reference deprecated); + @reference './test.css' theme(prefix(tw) reference); + @reference './test.css' theme(default invalid reference); + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@plugin statement', async ({ expect }) => { + let result = await grammar.tokenize(css` + @plugin "./foo"; + @plugin "./bar"; + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@plugin with options', async ({ expect }) => { + let result = await grammar.tokenize(css` + @import 'tailwindcss'; + @plugin "testing" { + color: red; + } + + html, + body { + color: red; + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@config statement', async ({ expect }) => { + let result = await grammar.tokenize(css` + @config "./foo"; + @config "./bar"; + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@tailwind', async ({ expect }) => { + let result = await grammar.tokenize(css` + @tailwind base; + @tailwind components; + @tailwind utilities; + @tailwind utilities source(none); + @tailwind utilities source("./**/*"); + @tailwind screens; + @tailwind variants; + @tailwind unknown; + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@source', async ({ expect }) => { + let result = await grammar.tokenize(css` + @source "./dir"; + @source "./file.ts"; + @source "./dir/**/file-{a,b}.ts"; + @source not "./dir"; + @source not "./file.ts"; + @source not "./dir/**/file-{a,b}.ts"; + + @source inline("flex"); + @source inline("flex bg-red-{50,{100..900..100},950}"); + @source not inline("flex"); + @source not inline("flex bg-red-{50,{100..900..100},950}"); + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@layer', async ({ expect }) => { + let result = await grammar.tokenize(css` + @layer theme, base, components, utilities; + @layer utilities { + .custom { + width: 12px; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@utility', async ({ expect }) => { + let result = await grammar.tokenize(css` + @utility custom { + width: 12px; + } + + @utility functional-* { + width: calc(--value(number) * 1px); + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('--value(…)', async ({ expect }) => { + let result = await grammar.tokenize(css` + @utility functional-* { + width: --value( + --size, + 'literal', + integer, + number, + percentage, + ratio, + [integer], + [number], + [percentage], + [ratio] + ); + + height: --modifier( + --size, + 'literal', + integer, + number, + percentage, + ratio, + [integer], + [number], + [percentage], + [ratio] + ); + + color: --alpha(--value([color]) / --modifier(number)); + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@variant', async ({ expect }) => { + let result = await grammar.tokenize(css` + @variant dark { + .foo { + color: white; + } + } + + .bar { + @variant dark { + color: white; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('@custom-variant', async ({ expect }) => { + let result = await grammar.tokenize(css` + @custom-variant dark (&:is(.dark, .dark *)); + @custom-variant dark { + &:is(.dark, .dark *) { + @slot; + } + } + @custom-variant around { + color: ''; + &::before, + &::after { + @slot; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('legacy: @responsive', async ({ expect }) => { + let result = await grammar.tokenize(css` + @responsive { + .foo { + color: red; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('legacy: @variants', async ({ expect }) => { + let result = await grammar.tokenize(css` + @variants hover, focus { + .foo { + color: red; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) + +test('legacy: @screen', async ({ expect }) => { + let result = await grammar.tokenize(css` + @screen sm { + .foo { + color: red; + } + } + `) + + expect(result.toString()).toMatchSnapshot() +}) diff --git a/packages/tailwindcss-language-syntax/tests/utils.ts b/packages/tailwindcss-language-syntax/tests/utils.ts new file mode 100644 index 000000000..cd6d3ccd1 --- /dev/null +++ b/packages/tailwindcss-language-syntax/tests/utils.ts @@ -0,0 +1,150 @@ +import { readFile } from 'node:fs/promises' +import path from 'node:path' +import vsctm from 'vscode-textmate' +import oniguruma from 'vscode-oniguruma' +import { createRequire } from 'node:module' +import { fileURLToPath } from 'node:url' +import { KNOWN_SCOPES } from './scopes' +import { DefaultMap } from './default-map' + +const require = createRequire(import.meta.url) + +export interface TokenizeResult { + toString(): string +} + +export interface TokenizedScope { + /** + * The name of the scope + */ + name: string + + /** + * An ordered list of ranges as they appear, one per token + */ + ranges: [start: number, end: number][] +} + +export interface Grammar { + tokenize(text: string, scope?: string): Promise +} + +// 1. Each line has a list of scopes +// 2. Each scope has a set of ranges, one per token +// 3. If two consecutive scopes have identical range lists they can be merged + +// @utility custom { +// ^^^^^^^^^^^^^^^^^ 11 tok: source.css.tailwind +// ^^^^^^^^ 2 tok: keyword.control.at-rule.utility.tailwind +// ^ 1 tok: punctuation.definition.keyword.css +// ^^^^^^ 6 tok: variable.parameter.utility.tailwind +// ^ 1 tok: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind + +function tokenizeText(grammar: vsctm.IGrammar, text: string): TokenizeResult { + let str = '' + + let results: [string, vsctm.ITokenizeLineResult][] = [] + + let ruleStack = vsctm.INITIAL + let maxEndIndex = 0 + for (let line of text.split(/\r\n|\r|\n/g)) { + let result = grammar.tokenizeLine(line, ruleStack) + ruleStack = result.ruleStack + maxEndIndex = Math.max(maxEndIndex, ...result.tokens.map((t) => t.endIndex)) + results.push([line, result]) + } + + for (let [line, result] of results) { + // 1. Collect the scope information for this line + let scopes = new DefaultMap((name) => ({ name, ranges: [] })) + + for (let token of result.tokens) { + let range = [token.startIndex, token.endIndex] as [number, number] + for (let name of token.scopes) { + scopes.get(name).ranges.push(range) + } + } + + let maxTokenCount = Math.max(...Array.from(scopes.values(), (s) => s.ranges.length)) + let tokenCountSpace = Math.max(2, maxTokenCount.toString().length) + + // 2. Write information to the output + str += '\n' + str += line + + let lastRangeKey = '' + + for (let scope of scopes.values()) { + let currentRangeKey = scope.ranges.map((r) => `${r[0]}:${r[1]}`).join(',') + if (lastRangeKey === currentRangeKey) { + str += ' ' + str += scope.name + continue + } + lastRangeKey = currentRangeKey + + str += '\n' + + let lastRangeEnd = 0 + for (let range of scope.ranges) { + str += ' '.repeat(range[0] - lastRangeEnd) + str += '^'.repeat(range[1] - range[0]) + lastRangeEnd = range[1] + } + str += ' '.repeat(maxEndIndex - lastRangeEnd) + + str += ' ' + str += scope.ranges.length.toString().padStart(tokenCountSpace) + str += ': ' + str += scope.name + } + + str += '\n' + } + + return { + toString: () => str, + } +} + +export async function loadGrammar() { + let wasm = await readFile(require.resolve('vscode-oniguruma/release/onig.wasm')) + await oniguruma.loadWASM(wasm) + + let registry = new vsctm.Registry({ + onigLib: Promise.resolve({ + createOnigScanner: (patterns) => new oniguruma.OnigScanner(patterns), + createOnigString: (s) => new oniguruma.OnigString(s), + }), + + async loadGrammar(scope) { + let meta = KNOWN_SCOPES[scope] + if (!meta) throw new Error(`Unknown scope name: ${scope}`) + + let grammar = await meta.content.then((m) => m.default) + + return vsctm.parseRawGrammar(JSON.stringify(grammar), `${scope}.json`) + }, + + getInjections(scope) { + let parts = scope.split('.') + + let injections: string[] = [] + for (let i = 1; i <= parts.length; i++) { + let subscope = parts.slice(0, i).join('.') + injections.push(...(KNOWN_SCOPES[subscope]?.inject ?? [])) + } + + return injections + }, + }) + + async function tokenize(text: string, scope?: string): Promise { + let grammar = await registry.loadGrammar(scope ?? 'source.css.tailwind') + return tokenizeText(grammar, text) + } + + return { + tokenize, + } +} diff --git a/packages/tailwindcss-language-syntax/tsconfig.json b/packages/tailwindcss-language-syntax/tsconfig.json new file mode 100755 index 000000000..7d01f0c54 --- /dev/null +++ b/packages/tailwindcss-language-syntax/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ES2022", + "lib": ["ES2022"], + "rootDir": "..", + "moduleResolution": "node", + "esModuleInterop": true, + "allowJs": true, + "resolveJsonModule": true, + "baseUrl": ".." + }, + "include": ["tests"] +} diff --git a/packages/tailwindcss-language-syntax/vitest.config.ts b/packages/tailwindcss-language-syntax/vitest.config.ts new file mode 100644 index 000000000..a079f2e6c --- /dev/null +++ b/packages/tailwindcss-language-syntax/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + testTimeout: 15000, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 207b8cc96..bba85f894 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -367,6 +367,24 @@ importers: specifier: ^3.0.9 version: 3.0.9(@types/node@18.19.43) + packages/tailwindcss-language-syntax: + devDependencies: + '@types/node': + specifier: ^18.19.33 + version: 18.19.43 + dedent: + specifier: ^1.5.3 + version: 1.5.3 + vitest: + specifier: ^3.1.4 + version: 3.1.4(@types/node@18.19.43) + vscode-oniguruma: + specifier: ^2.0.1 + version: 2.0.1 + vscode-textmate: + specifier: ^9.2.0 + version: 9.2.0 + packages/vscode-tailwindcss: devDependencies: '@tailwindcss/language-server': @@ -1148,6 +1166,9 @@ packages: '@vitest/expect@3.0.9': resolution: {integrity: sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==} + '@vitest/expect@3.1.4': + resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==} + '@vitest/mocker@3.0.9': resolution: {integrity: sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==} peerDependencies: @@ -1159,21 +1180,47 @@ packages: vite: optional: true + '@vitest/mocker@3.1.4': + resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@3.0.9': resolution: {integrity: sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==} + '@vitest/pretty-format@3.1.4': + resolution: {integrity: sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==} + '@vitest/runner@3.0.9': resolution: {integrity: sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==} + '@vitest/runner@3.1.4': + resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==} + '@vitest/snapshot@3.0.9': resolution: {integrity: sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==} + '@vitest/snapshot@3.1.4': + resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==} + '@vitest/spy@3.0.9': resolution: {integrity: sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==} + '@vitest/spy@3.1.4': + resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==} + '@vitest/utils@3.0.9': resolution: {integrity: sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==} + '@vitest/utils@3.1.4': + resolution: {integrity: sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==} + '@vscode/l10n@0.0.18': resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} @@ -1554,6 +1601,9 @@ packages: es-module-lexer@1.6.0: resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + esbuild-node-externals@1.14.0: resolution: {integrity: sha512-jMWnTlCII3cLEjR5+u0JRSTJuP+MgbjEHKfwSIAI41NgLQ0ZjfzjchlbEn0r7v2u5gCBMSEYvYlkO7GDG8gG3A==} engines: {node: '>=12'} @@ -1589,6 +1639,10 @@ packages: resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} engines: {node: '>=12.0.0'} + expect-type@1.2.1: + resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + engines: {node: '>=12.0.0'} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -1607,6 +1661,14 @@ packages: picomatch: optional: true + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -2484,6 +2546,9 @@ packages: std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2576,6 +2641,10 @@ packages: resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + tinypool@1.0.2: resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -2696,6 +2765,11 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + vite-node@3.1.4: + resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + vite-tsconfig-paths@4.3.2: resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: @@ -2763,6 +2837,34 @@ packages: jsdom: optional: true + vitest@3.1.4: + resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.1.4 + '@vitest/ui': 3.1.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vscode-css-languageservice@6.3.3: resolution: {integrity: sha512-xXa+ftMPv6JxRgzkvPwZuDCafIdwDW3kyijGcfij1a2qBVScr2qli6MfgJzYm/AMYdbHq9I/4hdpKV0Thim2EA==} @@ -2814,6 +2916,12 @@ packages: resolution: {integrity: sha512-eUt8f1z2N2IEUDBsKaNapkz7jl5QpskN2Y0G01T/ItMxBxw1fJwvtySGB9QMecatne8jFIWJGWI61dWjyTLQsw==} hasBin: true + vscode-oniguruma@2.0.1: + resolution: {integrity: sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ==} + + vscode-textmate@9.2.0: + resolution: {integrity: sha512-rkvG4SraZQaPSN/5XjwKswdU0OP9MF28QjrYzUBbhb8QyG3ljB1Ky996m++jiI7KdiAP2CkBiQZd9pqEDTClqA==} + vscode-uri@3.0.2: resolution: {integrity: sha512-jkjy6pjU1fxUvI51P+gCsxg1u2n8LSt0W6KrCNQceaziKzff74GoWmjVG46KieVzybO1sttPQmYfrwSHey7GUA==} @@ -3388,6 +3496,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/expect@3.1.4': + dependencies: + '@vitest/spy': 3.1.4 + '@vitest/utils': 3.1.4 + chai: 5.2.0 + tinyrainbow: 2.0.0 + '@vitest/mocker@3.0.9(vite@5.4.14(@types/node@18.19.43))': dependencies: '@vitest/spy': 3.0.9 @@ -3396,31 +3511,64 @@ snapshots: optionalDependencies: vite: 5.4.14(@types/node@18.19.43) + '@vitest/mocker@3.1.4(vite@5.4.14(@types/node@18.19.43))': + dependencies: + '@vitest/spy': 3.1.4 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.14(@types/node@18.19.43) + '@vitest/pretty-format@3.0.9': dependencies: tinyrainbow: 2.0.0 + '@vitest/pretty-format@3.1.4': + dependencies: + tinyrainbow: 2.0.0 + '@vitest/runner@3.0.9': dependencies: '@vitest/utils': 3.0.9 pathe: 2.0.3 + '@vitest/runner@3.1.4': + dependencies: + '@vitest/utils': 3.1.4 + pathe: 2.0.3 + '@vitest/snapshot@3.0.9': dependencies: '@vitest/pretty-format': 3.0.9 magic-string: 0.30.17 pathe: 2.0.3 + '@vitest/snapshot@3.1.4': + dependencies: + '@vitest/pretty-format': 3.1.4 + magic-string: 0.30.17 + pathe: 2.0.3 + '@vitest/spy@3.0.9': dependencies: tinyspy: 3.0.2 + '@vitest/spy@3.1.4': + dependencies: + tinyspy: 3.0.2 + '@vitest/utils@3.0.9': dependencies: '@vitest/pretty-format': 3.0.9 loupe: 3.1.3 tinyrainbow: 2.0.0 + '@vitest/utils@3.1.4': + dependencies: + '@vitest/pretty-format': 3.1.4 + loupe: 3.1.3 + tinyrainbow: 2.0.0 + '@vscode/l10n@0.0.18': {} '@vscode/vsce@2.21.1': @@ -3807,6 +3955,8 @@ snapshots: es-module-lexer@1.6.0: {} + es-module-lexer@1.7.0: {} + esbuild-node-externals@1.14.0(esbuild@0.25.0): dependencies: esbuild: 0.25.0 @@ -3880,6 +4030,8 @@ snapshots: expect-type@1.2.0: {} + expect-type@1.2.1: {} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3900,6 +4052,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -4770,6 +4926,8 @@ snapshots: std-env@3.8.0: {} + std-env@3.9.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -4899,6 +5057,11 @@ snapshots: fdir: 6.4.3(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + tinypool@1.0.2: {} tinyrainbow@2.0.0: {} @@ -5001,6 +5164,24 @@ snapshots: - supports-color - terser + vite-node@3.1.4(@types/node@18.19.43): + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 5.4.14(@types/node@18.19.43) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@5.4.14(@types/node@18.19.43)): dependencies: debug: 4.3.6 @@ -5056,6 +5237,42 @@ snapshots: - supports-color - terser + vitest@3.1.4(@types/node@18.19.43): + dependencies: + '@vitest/expect': 3.1.4 + '@vitest/mocker': 3.1.4(vite@5.4.14(@types/node@18.19.43)) + '@vitest/pretty-format': 3.1.4 + '@vitest/runner': 3.1.4 + '@vitest/snapshot': 3.1.4 + '@vitest/spy': 3.1.4 + '@vitest/utils': 3.1.4 + chai: 5.2.0 + debug: 4.4.0 + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 5.4.14(@types/node@18.19.43) + vite-node: 3.1.4(@types/node@18.19.43) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 18.19.43 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vscode-css-languageservice@6.3.3: dependencies: '@vscode/l10n': 0.0.18 @@ -5110,6 +5327,10 @@ snapshots: dependencies: vscode-languageserver-protocol: 3.17.3 + vscode-oniguruma@2.0.1: {} + + vscode-textmate@9.2.0: {} + vscode-uri@3.0.2: {} vscode-uri@3.0.8: {} From b55dfdd726215f25148ed4d690c6f82c2e4abd77 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 17:18:36 -0400 Subject: [PATCH 02/13] Fix syntax highlighting of `@plugin` with options --- .../tests/__snapshots__/syntax.test.ts.snap | 19 +++++++++++-------- .../syntaxes/at-rules.tmLanguage.json | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index b929c6dcb..4f233a08e 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -488,37 +488,40 @@ exports[`@plugin with options 1`] = ` ^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css - ^ 1: meta.at-rule.plugin.body.tailwind punctuation.section.plugin.begin.bracket.curly.tailwind + ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css color: red; -^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.plugin.body.tailwind +^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css ^^^^^ 1: meta.property-name.css support.type.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.at-rule.plugin.body.tailwind punctuation.section.plugin.end.bracket.curly.tailwind +^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css ^ 1: source.css.tailwind html, -^^^^^^ 1: source.css.tailwind +^^^^^ 2: source.css.tailwind meta.selector.css +^^^^ 1: entity.name.tag.css + ^ 1: punctuation.separator.list.comma.css body { -^^^^^^ 2: source.css.tailwind - ^ 1: meta.at-rule.plugin.body.tailwind punctuation.section.plugin.begin.bracket.curly.tailwind +^^^^^^ 3: source.css.tailwind +^^^^ 1: meta.selector.css entity.name.tag.css + ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css color: red; -^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.plugin.body.tailwind +^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css ^^^^^ 1: meta.property-name.css support.type.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.at-rule.plugin.body.tailwind punctuation.section.plugin.end.bracket.curly.tailwind +^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css " `; diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 6f09958f8..6e2c51953 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -204,7 +204,7 @@ "name": "punctuation.definition.keyword.tailwind" } }, - "end": ";", + "end": ";|(?=[@{])", "endCaptures": { "0": { "name": "punctuation.terminator.rule.css" From 13dde9b57cf3f5df6f5071db146071ff770e65b4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 17:19:46 -0400 Subject: [PATCH 03/13] Split highlighting of theme properties by whitespace --- .../tests/__snapshots__/syntax.test.ts.snap | 12 ++++++------ .../syntaxes/at-rules.tmLanguage.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 4f233a08e..142042c46 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -239,7 +239,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.terminator.rule.css @import './test.css' theme(default invalid reference); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 14: source.css.tailwind meta.at-rule.import.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 16: source.css.tailwind meta.at-rule.import.css ^^^^^^^ 2: keyword.control.at-rule.import.css ^ 1: punctuation.definition.keyword.css ^^^^^^^^^^^^ 3: string.quoted.single.css @@ -247,8 +247,8 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^ 2: variable.other.css - ^^^^^^^^^^^^^^^^^ 1: invalid.illegal.invalid-source.css + ^^^^^^^^ ^^^^^^^^^^ 4: variable.other.css + ^^^^^^^ 1: invalid.illegal.invalid-source.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -393,7 +393,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.terminator.rule.css @reference './test.css' theme(default invalid reference); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 14: source.css.tailwind meta.at-rule.import.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 16: source.css.tailwind meta.at-rule.import.css ^^^^^^^^^^ 2: keyword.control.at-rule.import.css ^ 1: punctuation.definition.keyword.css ^^^^^^^^^^^^ 3: string.quoted.single.css @@ -401,8 +401,8 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^ 2: variable.other.css - ^^^^^^^^^^^^^^^^^ 1: invalid.illegal.invalid-source.css + ^^^^^^^^ ^^^^^^^^^^ 4: variable.other.css + ^^^^^^^ 1: invalid.illegal.invalid-source.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css " diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 6e2c51953..1ad957451 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -605,7 +605,7 @@ "name": "variable.other.css" }, { - "match": "[^)]+", + "match": "[^)\\s]+", "name": "invalid.illegal.invalid-source.css" } ] From 9977843586d3809fc3625eea6ee076955be79938 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 17:20:00 -0400 Subject: [PATCH 04/13] Fix highlighting of `@theme` params --- .../tests/__snapshots__/syntax.test.ts.snap | 74 ++++++++++--------- .../syntaxes/at-rules.tmLanguage.json | 50 ++++++++++++- 2 files changed, 90 insertions(+), 34 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 142042c46..9baa0822c 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -698,65 +698,72 @@ exports[`@theme 1`] = ` ^^^^^^^^ 4: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css + ^ 1: variable.other.css + ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; -^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css - ^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind punctuation.section.theme.end.bracket.curly.tailwind @theme static { -^^^^^^^^^^^^^^^ 4: source.css.tailwind +^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css + ^^^^^^^^ 3: variable.other.css + ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; -^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css - ^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind punctuation.section.theme.end.bracket.curly.tailwind @theme inline deprecated { -^^^^^^^^^^^^^^^^^^^^^^^^^^ 4: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^ 8: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css + ^^^^^^^^^^^^^^^^^^^ 5: variable.other.css + ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; -^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css - ^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind punctuation.section.theme.end.bracket.curly.tailwind @theme prefix(tw) inline { -^^^^^^^^^^^^^^^^^^^^^^^^^^ 4: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^ 11: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css + ^^^^^^ 1: support.function.prefix.css + ^ 1: punctuation.section.function.begin.bracket.round.css + ^^ ^^^^^^^^ 4: variable.other.css + ^ 1: punctuation.section.function.end.bracket.round.css + ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; -^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css - ^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^ 1: meta.property-value.css support.constant.color.w3c-standard-color-name.css ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.property-list.css punctuation.section.property-list.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind punctuation.section.theme.end.bracket.curly.tailwind ^ 1: source.css.tailwind @@ -765,25 +772,26 @@ exports[`@theme 1`] = ` ^^^^^^^^ 4: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css + ^ 1: variable.other.css + ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --spacing: initial; -^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css - ^^^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^^^^^ 1: meta.property-value.css support.constant.property-value.css ^ 1: punctuation.terminator.rule.css --color-*: initial; -^^^^^^^^^^^^^^^^^^^^^ 7: source.css.tailwind meta.property-list.css - ^^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^^^^^^^ 7: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^^^^^ 1: meta.property-value.css support.constant.property-value.css ^ 1: punctuation.terminator.rule.css --animate-pulse: 1s pulse infinite; -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind meta.property-list.css - ^^^^^^^^^^^^^^^ 1: variable.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind meta.at-rule.theme.body.tailwind + ^^^^^^^^^^^^^^^ 1: meta.property-name.css ^ 1: punctuation.separator.key-value.css ^^^^^^^^^^^^^^^^^ 4: meta.property-value.css ^^ 2: constant.numeric.css @@ -792,28 +800,28 @@ exports[`@theme 1`] = ` ^ 1: punctuation.terminator.rule.css -^ 1: source.css.tailwind meta.property-list.css +^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind @keyframes pulse { -^^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.property-list.css +^^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.theme.body.tailwind ^^^^^^^^^ ^^^^^ 2: meta.property-name.css 0%, -^^^^^^^^ 1: source.css.tailwind meta.property-list.css +^^^^^^^^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind 100% { -^^^^^^^^^^^ 1: source.css.tailwind meta.property-list.css +^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.theme.body.tailwind opacity: 0; -^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.property-list.css +^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.theme.body.tailwind ^^^^^^^ 1: meta.property-name.css support.type.property-name.css ^ 1: punctuation.separator.key-value.css ^ 1: meta.property-value.css constant.numeric.css ^ 1: punctuation.terminator.rule.css } -^^^^^ 2: source.css.tailwind meta.property-list.css - ^ 1: punctuation.section.property-list.end.bracket.curly.css +^^^^^ 2: source.css.tailwind meta.at-rule.theme.body.tailwind + ^ 1: punctuation.section.theme.end.bracket.curly.tailwind 50% { ^^^^^^^^^ 2: source.css.tailwind diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 1ad957451..33bc0a63e 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -190,7 +190,55 @@ "end": "(?<=}|;)(?!\\G)", "patterns": [ { - "include": "source.css#rule-list" + "include": "#prefix-meta-fn" + }, + { + "match": "\\s+", + "name": "variable.other.css" + }, + { + "match": "reference", + "name": "variable.other.css" + }, + { + "match": "inline", + "name": "variable.other.css" + }, + { + "match": "static", + "name": "variable.other.css" + }, + { + "match": "default", + "name": "variable.other.css" + }, + { + "match": "deprecated", + "name": "variable.other.css" + }, + { + "match": "[^{\\s]+", + "name": "invalid.illegal.invalid-theme.css" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.theme.begin.bracket.curly.tailwind" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.theme.end.bracket.curly.tailwind" + } + }, + "name": "meta.at-rule.theme.body.tailwind", + "patterns": [ + { + "include": "#property-list" + } + ] } ] }, From a0eccc584992b2ad00de3d1a8673297e75ba6323 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 17:20:14 -0400 Subject: [PATCH 05/13] =?UTF-8?q?Fix=20highlighting=20of=20`prefix(?= =?UTF-8?q?=E2=80=A6)`=20inside=20`theme(=E2=80=A6)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/__snapshots__/syntax.test.ts.snap | 18 ++++++++++-------- .../syntaxes/at-rules.tmLanguage.json | 3 +++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 9baa0822c..9eca1c0bb 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -226,16 +226,17 @@ exports[`@import 1`] = ` ^ 1: punctuation.terminator.rule.css @import './test.css' theme(prefix(tw) reference); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13: source.css.tailwind meta.at-rule.import.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind meta.at-rule.import.css ^^^^^^^ 2: keyword.control.at-rule.import.css ^ 1: punctuation.definition.keyword.css ^^^^^^^^^^^^ 3: string.quoted.single.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css - ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^ 1: invalid.illegal.invalid-source.css - ^ 1: punctuation.section.function.end.bracket.round.css + ^ ^ 2: punctuation.section.function.begin.bracket.round.css + ^^^^^^ 1: support.function.prefix.css + ^^ ^^^^^^^^^^ 3: variable.other.css + ^ ^ 2: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @import './test.css' theme(default invalid reference); @@ -380,16 +381,17 @@ exports[`@import 1`] = ` ^ 1: punctuation.terminator.rule.css @reference './test.css' theme(prefix(tw) reference); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13: source.css.tailwind meta.at-rule.import.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind meta.at-rule.import.css ^^^^^^^^^^ 2: keyword.control.at-rule.import.css ^ 1: punctuation.definition.keyword.css ^^^^^^^^^^^^ 3: string.quoted.single.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css - ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^ 1: invalid.illegal.invalid-source.css - ^ 1: punctuation.section.function.end.bracket.round.css + ^ ^ 2: punctuation.section.function.begin.bracket.round.css + ^^^^^^ 1: support.function.prefix.css + ^^ ^^^^^^^^^^ 3: variable.other.css + ^ ^ 2: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @reference './test.css' theme(default invalid reference); diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 33bc0a63e..09ff9d575 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -652,6 +652,9 @@ "match": "deprecated", "name": "variable.other.css" }, + { + "include": "#prefix-meta-fn" + }, { "match": "[^)\\s]+", "name": "invalid.illegal.invalid-source.css" From a48e5e04a0981ca776b1a48201634baba881cb75 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 18:49:09 -0400 Subject: [PATCH 06/13] Consume layer/utility/variant names as one token --- .../tests/__snapshots__/syntax.test.ts.snap | 64 +++++++++---------- .../syntaxes/at-rules.tmLanguage.json | 12 ++-- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 9eca1c0bb..e0d019804 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -413,18 +413,18 @@ exports[`@import 1`] = ` exports[`@layer 1`] = ` " @layer theme, base, components, utilities; -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 38: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 14: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.layer.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^ ^^^^ ^^^^^^^^^^ ^^^^^^^^^ 28: variable.parameter.layer.tailwind + ^^^^^ ^^^^ ^^^^^^^^^^ ^^^^^^^^^ 4: variable.parameter.layer.tailwind ^ ^ ^ 3: punctuation.separator.list.comma.css ^ 1: punctuation.terminator.rule.css @layer utilities { -^^^^^^^^^^^^^^^^^^ 14: source.css.tailwind +^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.layer.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^ 9: variable.parameter.layer.tailwind + ^^^^^^^^^ 1: variable.parameter.layer.tailwind ^ 1: meta.at-rule.layer.body.tailwind punctuation.section.layer.begin.bracket.curly.tailwind .custom { @@ -627,31 +627,31 @@ exports[`@source 1`] = ` exports[`@tailwind 1`] = ` " @tailwind base; -^^^^^^^^^^^^^^^ 8: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^ 4: variable.parameter.tailwind.tailwind + ^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind @tailwind components; -^^^^^^^^^^^^^^^^^^^^^ 14: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^^ 10: variable.parameter.tailwind.tailwind + ^^^^^^^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind @tailwind utilities; -^^^^^^^^^^^^^^^^^^^^ 13: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^ 9: variable.parameter.tailwind.tailwind + ^^^^^^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind @tailwind utilities source(none); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 18: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^ 9: variable.parameter.tailwind.tailwind + ^^^^^^^^^ 1: variable.parameter.tailwind.tailwind ^^^^^^ 1: support.function.source.css ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^ 1: support.constant.none.css @@ -659,10 +659,10 @@ exports[`@tailwind 1`] = ` ^ 1: punctuation.terminator.tailwind.tailwind @tailwind utilities source("./**/*"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 20: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^ 9: variable.parameter.tailwind.tailwind + ^^^^^^^^^ 1: variable.parameter.tailwind.tailwind ^^^^^^ 1: support.function.source.css ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^^^^^ 3: string.quoted.double.css @@ -672,24 +672,24 @@ exports[`@tailwind 1`] = ` ^ 1: punctuation.terminator.tailwind.tailwind @tailwind screens; -^^^^^^^^^^^^^^^^^^ 11: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^ 7: variable.parameter.tailwind.tailwind + ^^^^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind @tailwind variants; -^^^^^^^^^^^^^^^^^^^ 12: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^ 8: variable.parameter.tailwind.tailwind + ^^^^^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind @tailwind unknown; -^^^^^^^^^^^^^^^^^^ 11: source.css.tailwind meta.at-rule.tailwind.css +^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.tailwind.css ^^^^^^^^^ 2: keyword.control.at-rule.tailwind.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^ 7: variable.parameter.tailwind.tailwind + ^^^^^^^ 1: variable.parameter.tailwind.tailwind ^ 1: punctuation.terminator.tailwind.tailwind " `; @@ -851,10 +851,10 @@ exports[`@theme 1`] = ` exports[`@utility 1`] = ` " @utility custom { -^^^^^^^^^^^^^^^^^ 11: source.css.tailwind +^^^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^ 6: variable.parameter.utility.tailwind + ^^^^^^ 1: variable.parameter.utility.tailwind ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: 12px; @@ -867,10 +867,10 @@ exports[`@utility 1`] = ` ^ 1: source.css.tailwind @utility functional-* { -^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^^^^ 12: variable.parameter.utility.tailwind + ^^^^^^^^^^^^ 1: variable.parameter.utility.tailwind ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: calc(--value(number) * 1px); @@ -884,10 +884,10 @@ exports[`@utility 1`] = ` exports[`@variant 1`] = ` " @variant dark { -^^^^^^^^^^^^^^^ 9: source.css.tailwind +^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^^^ 2: keyword.control.at-rule.variant.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^ 4: variable.parameter.variant.tailwind + ^^^^ 1: variable.parameter.variant.tailwind ^ 1: meta.at-rule.variant.body.tailwind punctuation.section.variant.begin.bracket.curly.tailwind .foo { @@ -920,10 +920,10 @@ exports[`@variant 1`] = ` ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css @variant dark { -^^^^^^^^^^^^^^^^^ 10: source.css.tailwind meta.property-list.css +^^^^^^^^^^^^^^^^^ 7: source.css.tailwind meta.property-list.css ^^^^^^^^ 2: keyword.control.at-rule.variant.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^ 4: variable.parameter.variant.tailwind + ^^^^ 1: variable.parameter.variant.tailwind ^ 1: meta.at-rule.variant.body.tailwind punctuation.section.variant.begin.bracket.curly.tailwind color: white; @@ -1066,10 +1066,10 @@ exports[`legacy: @responsive 1`] = ` exports[`legacy: @screen 1`] = ` " @screen sm { -^^^^^^^^^^^^ 7: source.css.tailwind +^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.screen.tailwind ^ 1: punctuation.definition.keyword.css - ^^ 2: variable.parameter.screen.tailwind + ^^ 1: variable.parameter.screen.tailwind ^ 1: meta.at-rule.screen.body.tailwind punctuation.section.screen.begin.bracket.curly.tailwind .foo { @@ -1097,10 +1097,10 @@ exports[`legacy: @screen 1`] = ` exports[`legacy: @variants 1`] = ` " @variants hover, focus { -^^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind ^^^^^^^^^ 2: keyword.control.at-rule.variants.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^ ^^^^^ 10: variable.parameter.variants.tailwind + ^^^^^ ^^^^^ 2: variable.parameter.variants.tailwind ^ 1: punctuation.separator.list.comma.css ^ 1: meta.at-rule.variants.body.tailwind punctuation.section.variants.begin.bracket.curly.tailwind diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 09ff9d575..2d83ddffb 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -82,7 +82,7 @@ "include": "#source-fn" }, { - "match": "[^\\s;]+?", + "match": "[^\\s;]+", "name": "variable.parameter.tailwind.tailwind" } ] @@ -103,7 +103,7 @@ "include": "source.css#comment-block" }, { - "match": "[^\\s{]+?", + "match": "[^\\s{]+", "name": "variable.parameter.screen.tailwind" }, { @@ -144,7 +144,7 @@ "include": "source.css#comment-block" }, { - "match": "[^\\s{;,]+?", + "match": "[^\\s{;,]+", "name": "variable.parameter.layer.tailwind" }, { @@ -351,7 +351,7 @@ "include": "source.css#commas" }, { - "match": "[^\\s{,]+?", + "match": "[^\\s{,]+", "name": "variable.parameter.variants.tailwind" }, { @@ -389,7 +389,7 @@ "end": "(?<=})(?!\\G)", "patterns": [ { - "match": "[^\\s{,]+?", + "match": "[^\\s{,]+", "name": "variable.parameter.utility.tailwind" }, { @@ -427,7 +427,7 @@ "end": "(?<=[};])(?!\\G)", "patterns": [ { - "match": "[^\\s({;,]+?", + "match": "[^\\s({;,]+", "name": "variable.parameter.variant.tailwind" }, { From e21123bca006d6828eaf7d21644149746b07ff36 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 17:21:06 -0400 Subject: [PATCH 07/13] Fix highlighting of `@utility` body --- .../tests/__snapshots__/syntax.test.ts.snap | 45 ++++++++++++------- .../syntaxes/at-rules.tmLanguage.json | 2 +- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index e0d019804..ef22509ae 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -851,33 +851,48 @@ exports[`@theme 1`] = ` exports[`@utility 1`] = ` " @utility custom { -^^^^^^^^^^^^^^^^^ 6: source.css.tailwind -^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind -^ 1: punctuation.definition.keyword.css - ^^^^^^ 1: variable.parameter.utility.tailwind - ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind +^^^^^^^^^^^^^^^^^ 6: source.css.tailwind +^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind +^ 1: punctuation.definition.keyword.css + ^^^^^^ 1: variable.parameter.utility.tailwind + ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: 12px; -^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^ 7: source.css.tailwind meta.at-rule.utility.body.tailwind + ^^^^^ 1: meta.property-name.css support.type.property-name.css + ^ 1: punctuation.separator.key-value.css + ^^^^ 2: meta.property-value.css constant.numeric.css + ^^ 1: keyword.other.unit.px.css + ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind +^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind -^ 1: source.css.tailwind +^ 1: source.css.tailwind @utility functional-* { -^^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind -^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind -^ 1: punctuation.definition.keyword.css - ^^^^^^^^^^^^ 1: variable.parameter.utility.tailwind - ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind +^^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind +^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind +^ 1: punctuation.definition.keyword.css + ^^^^^^^^^^^^ 1: variable.parameter.utility.tailwind + ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: calc(--value(number) * 1px); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13: source.css.tailwind meta.at-rule.utility.body.tailwind + ^^^^^ 1: meta.property-name.css support.type.property-name.css + ^ 1: punctuation.separator.key-value.css + ^^^^^^^^^^^^^^^^^^^^^^^^^^ 7: meta.property-value.css + ^^^^^^^^^^^^^^^^^^^^ 4: meta.function.calc.css + ^^^^ 1: support.function.calc.css + ^ 1: punctuation.section.function.begin.bracket.round.css + ^ 1: punctuation.section.function.end.bracket.round.css + ^^^ 2: constant.numeric.css + ^^ 1: keyword.other.unit.px.css + ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind +^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind " `; diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 2d83ddffb..45471ca5e 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -408,7 +408,7 @@ "name": "meta.at-rule.utility.body.tailwind", "patterns": [ { - "include": "source.css#rule-list" + "include": "source.css#rule-list-innards" } ] } From 7000d1c11f31c696d0e40dd83ea59706256591a9 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 18:24:55 -0400 Subject: [PATCH 08/13] Fix highlighting of `@custom-variant` --- .../tests/__snapshots__/syntax.test.ts.snap | 52 +++++++++++-------- .../syntaxes/at-rules.tmLanguage.json | 2 +- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index ef22509ae..19bb6d269 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -25,20 +25,30 @@ exports[`@config statement 1`] = ` exports[`@custom-variant 1`] = ` " @custom-variant dark (&:is(.dark, .dark *)); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4: source.css.tailwind meta.at-rule.header.css -^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.css +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21: source.css.tailwind +^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.variant.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: punctuation.terminator.rule.css + ^^^^ 1: variable.parameter.variant.tailwind + ^^^^^^^^^^^^^^^^^^^^^^ 15: meta.selector.tailwind + ^ 1: punctuation.section.variant.begin.bracket.paren.tailwind + ^^^ 2: entity.other.attribute-name.pseudo-class.css + ^ ^ ^ 3: punctuation.definition.entity.css + ^ 1: punctuation.section.function.begin.bracket.round.css + ^^^^^ ^^^^^ 4: entity.other.attribute-name.class.css + ^ 1: punctuation.separator.list.comma.css + ^ 1: entity.name.tag.wildcard.css + ^ 1: punctuation.section.function.end.bracket.round.css + ^ 1: punctuation.section.variant.end.bracket.paren.tailwind @custom-variant dark { -^^^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind -^^^^^^^^^^^^^^^^^^^^ 3: meta.at-rule.header.css -^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.css +^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind +^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.variant.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.at-rule.body.css punctuation.section.begin.bracket.curly.css + ^^^^ 1: variable.parameter.variant.tailwind + ^ 1: meta.at-rule.variant.body.tailwind punctuation.section.variant.begin.bracket.curly.tailwind &:is(.dark, .dark *) { -^^^^^^^^^^^^^^^^^^^^^^^^ 15: source.css.tailwind meta.at-rule.body.css +^^^^^^^^^^^^^^^^^^^^^^^^ 15: source.css.tailwind meta.at-rule.variant.body.tailwind ^^^^^^^^^^^^^^^^^^^ 12: meta.selector.css ^^^ 2: entity.other.attribute-name.pseudo-class.css ^ ^ ^ 3: punctuation.definition.entity.css @@ -50,52 +60,52 @@ exports[`@custom-variant 1`] = ` ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css @slot; -^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.body.css meta.property-list.css +^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.variant.body.tailwind meta.property-list.css ^^^^ 1: meta.property-name.css ^ 1: punctuation.terminator.rule.css } -^^^ 2: source.css.tailwind meta.at-rule.body.css meta.property-list.css +^^^ 2: source.css.tailwind meta.at-rule.variant.body.tailwind meta.property-list.css ^ 1: punctuation.section.property-list.end.bracket.curly.css } -^ 1: source.css.tailwind meta.at-rule.body.css punctuation.section.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.variant.body.tailwind punctuation.section.variant.end.bracket.curly.tailwind @custom-variant around { -^^^^^^^^^^^^^^^^^^^^^^^^ 5: source.css.tailwind -^^^^^^^^^^^^^^^^^^^^^^ 3: meta.at-rule.header.css -^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.css +^^^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind +^^^^^^^^^^^^^^^ 2: keyword.control.at-rule.variant.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: meta.at-rule.body.css punctuation.section.begin.bracket.curly.css + ^^^^^^ 1: variable.parameter.variant.tailwind + ^ 1: meta.at-rule.variant.body.tailwind punctuation.section.variant.begin.bracket.curly.tailwind color: ''; -^^^^^^^^^^^^^ 2: source.css.tailwind meta.at-rule.body.css +^^^^^^^^^^^^^ 2: source.css.tailwind meta.at-rule.variant.body.tailwind ^^^^^^^^^^^ 1: meta.selector.css &::before, -^^^^^^^^^^^^ 4: source.css.tailwind meta.at-rule.body.css meta.selector.css +^^^^^^^^^^^^ 4: source.css.tailwind meta.at-rule.variant.body.tailwind meta.selector.css ^^^^^^^^ 2: entity.other.attribute-name.pseudo-element.css ^^ 1: punctuation.definition.entity.css ^ 1: punctuation.separator.list.comma.css &::after { -^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.body.css +^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.variant.body.tailwind ^^^^^^^^^^ 3: meta.selector.css ^^^^^^^ 2: entity.other.attribute-name.pseudo-element.css ^^ 1: punctuation.definition.entity.css ^ 1: meta.property-list.css punctuation.section.property-list.begin.bracket.curly.css @slot; -^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.body.css meta.property-list.css +^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.variant.body.tailwind meta.property-list.css ^^^^ 1: meta.property-name.css ^ 1: punctuation.terminator.rule.css } -^^^ 2: source.css.tailwind meta.at-rule.body.css meta.property-list.css +^^^ 2: source.css.tailwind meta.at-rule.variant.body.tailwind meta.property-list.css ^ 1: punctuation.section.property-list.end.bracket.curly.css } -^ 1: source.css.tailwind meta.at-rule.body.css punctuation.section.end.bracket.curly.css +^ 1: source.css.tailwind meta.at-rule.variant.body.tailwind punctuation.section.variant.end.bracket.curly.tailwind " `; diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 45471ca5e..0b48ccca0 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -415,7 +415,7 @@ ] }, { - "begin": "(?i)((@)variant)(?=[\\s{(]|$)", + "begin": "(?i)((@)(?:custom-)?variant)(?=[\\s{(]|$)", "beginCaptures": { "1": { "name": "keyword.control.at-rule.variant.tailwind" From e5b243cbf5bf54a41e642ac1ae9118db9145bbe3 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 19:17:42 -0400 Subject: [PATCH 09/13] =?UTF-8?q?Highlight=20`not`=20in=20`@source=20not?= =?UTF-8?q?=20=E2=80=A6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/__snapshots__/syntax.test.ts.snap | 15 ++++++++++----- .../syntaxes/at-rules.tmLanguage.json | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 19bb6d269..0365606dd 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -567,27 +567,30 @@ exports[`@source 1`] = ` ^ 1: punctuation.terminator.rule.css @source not "./dir"; -^^^^^^^^^^^^^^^^^^^^ 8: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^ 1: support.constant.not.css ^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css ^ 1: punctuation.terminator.rule.css @source not "./file.ts"; -^^^^^^^^^^^^^^^^^^^^^^^^ 8: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^ 1: support.constant.not.css ^^^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css ^ 1: punctuation.terminator.rule.css @source not "./dir/**/file-{a,b}.ts"; -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^ 1: support.constant.not.css ^^^^^^^^^^^^^^^^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css @@ -615,18 +618,20 @@ exports[`@source 1`] = ` ^ 1: punctuation.terminator.rule.css @source not inline("flex"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^ 1: support.constant.not.css ^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css ^ 1: punctuation.terminator.rule.css @source not inline("flex bg-red-{50,{100..900..100},950}"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^ 1: support.constant.not.css ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 0b48ccca0..7fb6a3c23 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -305,6 +305,10 @@ "match": "none(?=;)", "name": "invalid.illegal.invalid-source.css" }, + { + "match": "not(?=\\s)", + "name": "support.constant.not.css" + }, { "include": "source.css#string" } From 8b5daeeac70a72a81e0e3ae412b75dcc4fbd95ec Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 19:17:57 -0400 Subject: [PATCH 10/13] =?UTF-8?q?Highlight=20`inline(=E2=80=A6)`=20in=20`@?= =?UTF-8?q?source=20inline(=E2=80=A6)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/__snapshots__/syntax.test.ts.snap | 20 ++++++++--- .../syntaxes/at-rules.tmLanguage.json | 33 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 0365606dd..1d3f77f63 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -600,41 +600,53 @@ exports[`@source 1`] = ` ^ 1: source.css.tailwind @source inline("flex"); -^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^^^^ 1: support.function.inline.css + ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @source inline("flex bg-red-{50,{100..900..100},950}"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind + ^^^^^^ 1: support.function.inline.css + ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @source not inline("flex"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind ^^^ 1: support.constant.not.css + ^^^^^^ 1: support.function.inline.css + ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @source not inline("flex bg-red-{50,{100..900..100},950}"); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 10: source.css.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12: source.css.tailwind ^^^^^^^ 2: keyword.control.at-rule.source.tailwind ^ 1: punctuation.definition.keyword.tailwind ^^^ 1: support.constant.not.css + ^^^^^^ 1: support.function.inline.css + ^ 1: punctuation.section.function.begin.bracket.round.css ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3: string.quoted.double.css ^ 1: punctuation.definition.string.begin.css ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css " `; diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 7fb6a3c23..768adda79 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -311,6 +311,9 @@ }, { "include": "source.css#string" + }, + { + "include": "#inline-fn" } ] }, @@ -613,6 +616,36 @@ } ] }, + "inline-fn": { + "patterns": [ + { + "begin": "(?i)(?:\\s*)(? Date: Mon, 26 May 2025 19:19:49 -0400 Subject: [PATCH 11/13] Highlight theme options as constants --- .../tests/__snapshots__/syntax.test.ts.snap | 35 ++++---- .../syntaxes/at-rules.tmLanguage.json | 90 +++++++------------ 2 files changed, 52 insertions(+), 73 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index 1d3f77f63..d351994bb 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -205,7 +205,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^ 1: variable.other.css + ^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -218,7 +218,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^^^^^^^^^^^^^ 5: variable.other.css + ^^^^^^ ^^^^^^^ ^^^^^^ 3: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -231,7 +231,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^^^^^^^^^^^^ 3: variable.other.css + ^^^^^^^^^ ^^^^^^^^^^ 2: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -245,8 +245,9 @@ exports[`@import 1`] = ` ^^^^^ 1: support.function.theme.css ^ ^ 2: punctuation.section.function.begin.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ ^^^^^^^^^^ 3: variable.other.css + ^^ 1: variable.other.css ^ ^ 2: punctuation.section.function.end.bracket.round.css + ^^^^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.terminator.rule.css @import './test.css' theme(default invalid reference); @@ -258,8 +259,8 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^ ^^^^^^^^^^ 4: variable.other.css - ^^^^^^^ 1: invalid.illegal.invalid-source.css + ^^^^^^^ ^^^^^^^^^ 2: support.constant.theme-option.css + ^^^^^^^ 1: invalid.illegal.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -360,7 +361,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^ 1: variable.other.css + ^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -373,7 +374,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^^^^^^^^^^^^^ 5: variable.other.css + ^^^^^^ ^^^^^^^ ^^^^^^ 3: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -386,7 +387,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^^^^^^^^^^^^^ 3: variable.other.css + ^^^^^^^^^ ^^^^^^^^^^ 2: support.constant.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -400,8 +401,9 @@ exports[`@import 1`] = ` ^^^^^ 1: support.function.theme.css ^ ^ 2: punctuation.section.function.begin.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ ^^^^^^^^^^ 3: variable.other.css + ^^ 1: variable.other.css ^ ^ 2: punctuation.section.function.end.bracket.round.css + ^^^^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.terminator.rule.css @reference './test.css' theme(default invalid reference); @@ -413,8 +415,8 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^ 1: support.function.theme.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^^^^^^^ ^^^^^^^^^^ 4: variable.other.css - ^^^^^^^ 1: invalid.illegal.invalid-source.css + ^^^^^^^ ^^^^^^^^^ 2: support.constant.theme-option.css + ^^^^^^^ 1: invalid.illegal.theme-option.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css " @@ -727,7 +729,6 @@ exports[`@theme 1`] = ` ^^^^^^^^ 4: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: variable.other.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; @@ -744,7 +745,7 @@ exports[`@theme 1`] = ` ^^^^^^^^^^^^^^^ 6: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^ 3: variable.other.css + ^^^^^^ 1: support.constant.theme-option.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; @@ -761,7 +762,7 @@ exports[`@theme 1`] = ` ^^^^^^^^^^^^^^^^^^^^^^^^^^ 8: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^^^^^^^^^^^^^^^^^^^ 5: variable.other.css + ^^^^^^ ^^^^^^^^^^ 2: support.constant.theme-option.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; @@ -780,8 +781,9 @@ exports[`@theme 1`] = ` ^ 1: punctuation.definition.keyword.css ^^^^^^ 1: support.function.prefix.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^ ^^^^^^^^ 4: variable.other.css + ^^ 1: variable.other.css ^ 1: punctuation.section.function.end.bracket.round.css + ^^^^^^ 1: support.constant.theme-option.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --color: red; @@ -801,7 +803,6 @@ exports[`@theme 1`] = ` ^^^^^^^^ 4: source.css.tailwind ^^^^^^ 2: keyword.control.at-rule.theme.tailwind ^ 1: punctuation.definition.keyword.css - ^ 1: variable.other.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind --spacing: initial; diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 768adda79..7bd2bf96a 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -189,36 +189,10 @@ }, "end": "(?<=}|;)(?!\\G)", "patterns": [ - { - "include": "#prefix-meta-fn" - }, - { - "match": "\\s+", - "name": "variable.other.css" - }, - { - "match": "reference", - "name": "variable.other.css" - }, - { - "match": "inline", - "name": "variable.other.css" - }, - { - "match": "static", - "name": "variable.other.css" - }, - { - "match": "default", - "name": "variable.other.css" - }, - { - "match": "deprecated", - "name": "variable.other.css" - }, + { "include": "#theme-options" }, { "match": "[^{\\s]+", - "name": "invalid.illegal.invalid-theme.css" + "name": "invalid.illegal.theme-option.css" }, { "begin": "{", @@ -646,6 +620,36 @@ } ] }, + "theme-options": { + "patterns": [ + { + "match": "\\s+" + }, + { + "match": "reference", + "name": "support.constant.theme-option.css" + }, + { + "match": "inline", + "name": "support.constant.theme-option.css" + }, + { + "match": "static", + "name": "support.constant.theme-option.css" + }, + { + "match": "default", + "name": "support.constant.theme-option.css" + }, + { + "match": "deprecated", + "name": "support.constant.theme-option.css" + }, + { + "include": "#prefix-meta-fn" + } + ] + }, "theme-meta-fn": { "patterns": [ { @@ -665,36 +669,10 @@ } }, "patterns": [ - { - "match": "\\s+", - "name": "variable.other.css" - }, - { - "match": "reference", - "name": "variable.other.css" - }, - { - "match": "inline", - "name": "variable.other.css" - }, - { - "match": "static", - "name": "variable.other.css" - }, - { - "match": "default", - "name": "variable.other.css" - }, - { - "match": "deprecated", - "name": "variable.other.css" - }, - { - "include": "#prefix-meta-fn" - }, + { "include": "#theme-options" }, { "match": "[^)\\s]+", - "name": "invalid.illegal.invalid-source.css" + "name": "invalid.illegal.theme-option.css" } ] } From 36aae5a94818b0e393a528f09a86133f0cb5c1d6 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 19:20:07 -0400 Subject: [PATCH 12/13] Tweak theme prefix highlight scope --- .../tests/__snapshots__/syntax.test.ts.snap | 14 +++++++------- .../syntaxes/at-rules.tmLanguage.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index d351994bb..dadf8eb2e 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -132,7 +132,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^^ 1: support.function.prefix.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -148,7 +148,7 @@ exports[`@import 1`] = ` ^^^^^^^^^ 1: support.constant.layer-name.css ^ ^ 2: punctuation.section.function.end.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ 1: punctuation.terminator.rule.css @@ -245,7 +245,7 @@ exports[`@import 1`] = ` ^^^^^ 1: support.function.theme.css ^ ^ 2: punctuation.section.function.begin.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ ^ 2: punctuation.section.function.end.bracket.round.css ^^^^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.terminator.rule.css @@ -288,7 +288,7 @@ exports[`@import 1`] = ` ^ 1: punctuation.definition.string.end.css ^^^^^^ 1: support.function.prefix.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ 1: punctuation.section.function.end.bracket.round.css ^ 1: punctuation.terminator.rule.css @@ -304,7 +304,7 @@ exports[`@import 1`] = ` ^^^^^^^^^ 1: support.constant.layer-name.css ^ ^ 2: punctuation.section.function.end.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ 1: punctuation.terminator.rule.css @@ -401,7 +401,7 @@ exports[`@import 1`] = ` ^^^^^ 1: support.function.theme.css ^ ^ 2: punctuation.section.function.begin.bracket.round.css ^^^^^^ 1: support.function.prefix.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ ^ 2: punctuation.section.function.end.bracket.round.css ^^^^^^^^^ 1: support.constant.theme-option.css ^ 1: punctuation.terminator.rule.css @@ -781,7 +781,7 @@ exports[`@theme 1`] = ` ^ 1: punctuation.definition.keyword.css ^^^^^^ 1: support.function.prefix.css ^ 1: punctuation.section.function.begin.bracket.round.css - ^^ 1: variable.other.css + ^^ 1: variable.parameter.prefix.css ^ 1: punctuation.section.function.end.bracket.round.css ^^^^^^ 1: support.constant.theme-option.css ^ 1: meta.at-rule.theme.body.tailwind punctuation.section.theme.begin.bracket.curly.tailwind diff --git a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json index 7bd2bf96a..0e074444d 100644 --- a/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/at-rules.tmLanguage.json @@ -699,11 +699,11 @@ "patterns": [ { "match": "[a-z]+", - "name": "variable.other.css" + "name": "variable.parameter.prefix.css" }, { "match": "[^a-z]+", - "name": "invalid.illegal.invalid-source.css" + "name": "invalid.illegal.prefix.css" } ] } From 1b4602735c72e0f42aa3efd3396b562b2ef757cc Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 26 May 2025 19:31:16 -0400 Subject: [PATCH 13/13] =?UTF-8?q?Improve=20highlighting=20of=20`--value()`?= =?UTF-8?q?,=20`--modifier()`,=20and=20`=E2=80=94alpha()`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/__snapshots__/syntax.test.ts.snap | 165 ++++++++++++++---- .../syntaxes/theme-fn.tmLanguage.json | 136 ++++++++++++++- 2 files changed, 261 insertions(+), 40 deletions(-) diff --git a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap index dadf8eb2e..073bc3a8d 100644 --- a/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap +++ b/packages/tailwindcss-language-syntax/tests/__snapshots__/syntax.test.ts.snap @@ -907,14 +907,16 @@ exports[`@utility 1`] = ` ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: calc(--value(number) * 1px); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind meta.at-rule.utility.body.tailwind ^^^^^ 1: meta.property-name.css support.type.property-name.css ^ 1: punctuation.separator.key-value.css - ^^^^^^^^^^^^^^^^^^^^^^^^^^ 7: meta.property-value.css - ^^^^^^^^^^^^^^^^^^^^ 4: meta.function.calc.css + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12: meta.property-value.css meta.function.calc.css ^^^^ 1: support.function.calc.css - ^ 1: punctuation.section.function.begin.bracket.round.css - ^ 1: punctuation.section.function.end.bracket.round.css + ^ ^ 2: punctuation.section.function.begin.bracket.round.css + ^^^^^^^ 1: support.function.value.tailwind + ^^^^^^ 1: support.constant.utility.data-type.css + ^ ^ 2: punctuation.section.function.end.bracket.round.css + ^ 1: keyword.operator.arithmetic.css ^^^ 2: constant.numeric.css ^^ 1: keyword.other.unit.px.css ^ 1: punctuation.terminator.rule.css @@ -984,95 +986,182 @@ exports[`@variant 1`] = ` exports[`--value(…) 1`] = ` " @utility functional-* { -^^^^^^^^^^^^^^^^^^^^^^^ 17: source.css.tailwind -^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind -^ 1: punctuation.definition.keyword.css - ^^^^^^^^^^^^ 12: variable.parameter.utility.tailwind - ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind +^^^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind +^^^^^^^^ 2: keyword.control.at-rule.utility.tailwind +^ 1: punctuation.definition.keyword.css + ^^^^^^^^^^^^ 1: variable.parameter.utility.tailwind + ^ 1: meta.at-rule.utility.body.tailwind punctuation.section.utility.begin.bracket.curly.tailwind width: --value( -^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.utility.body.tailwind + ^^^^^ 1: meta.property-name.css support.type.property-name.css + ^ 1: punctuation.separator.key-value.css + ^^^^^^^^ 2: meta.property-value.css + ^^^^^^^ 1: support.function.value.tailwind + ^ 1: punctuation.section.function.begin.bracket.round.css --size, -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^ 1: variable.theme-namespace.css + ^ 1: punctuation.separator.list.comma.css 'literal', -^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^^^ 3: string.quoted.single.css + ^ 1: punctuation.definition.string.begin.css + ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.separator.list.comma.css integer, -^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css number, -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css percentage, -^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css ratio, -^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css [integer], -^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [number], -^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [percentage], -^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [ratio] -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 4: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css ); -^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^ 2: meta.property-value.css + ^ 1: punctuation.section.function.end.bracket.round.css + ^ 1: punctuation.terminator.rule.css -^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind height: --modifier( -^^^^^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^^^^^ 6: source.css.tailwind meta.at-rule.utility.body.tailwind + ^^^^^^ 1: meta.property-name.css support.type.property-name.css + ^ 1: punctuation.separator.key-value.css + ^^^^^^^^^^^ 2: meta.property-value.css + ^^^^^^^^^^ 1: support.function.modifier.tailwind + ^ 1: punctuation.section.function.begin.bracket.round.css --size, -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^ 1: variable.theme-namespace.css + ^ 1: punctuation.separator.list.comma.css 'literal', -^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^^^ 3: string.quoted.single.css + ^ 1: punctuation.definition.string.begin.css + ^ 1: punctuation.definition.string.end.css + ^ 1: punctuation.separator.list.comma.css integer, -^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css number, -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css percentage, -^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css ratio, -^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.separator.list.comma.css [integer], -^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [number], -^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [percentage], -^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^ 5: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ 1: punctuation.separator.list.comma.css [ratio] -^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^ 4: source.css.tailwind meta.at-rule.utility.body.tailwind meta.property-value.css + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^ 1: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css ); -^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^ 3: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^ 2: meta.property-value.css + ^ 1: punctuation.section.function.end.bracket.round.css + ^ 1: punctuation.terminator.rule.css -^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind color: --alpha(--value([color]) / --modifier(number)); -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21: source.css.tailwind meta.at-rule.utility.body.tailwind + ^^^^^ 1: meta.property-name.css support.type.property-name.css + ^ 1: punctuation.separator.key-value.css + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 16: meta.property-value.css + ^^^^^^^ 1: support.function.alpha.tailwind + ^ ^ ^ 3: punctuation.section.function.begin.bracket.round.css + ^^^^^^^ 1: support.function.value.tailwind + ^ 1: punctuation.definition.arbitrary.begin.bracket.square.css + ^^^^^ ^^^^^^ 2: support.constant.utility.data-type.css + ^ 1: punctuation.definition.arbitrary.end.bracket.square.css + ^ ^^ 3: punctuation.section.function.end.bracket.round.css + ^ 1: variable.parameter.alpha.tailwind + ^^^^^^^^^^ 1: support.function.modifier.tailwind + ^ 1: punctuation.terminator.rule.css } -^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind +^ 1: source.css.tailwind meta.at-rule.utility.body.tailwind punctuation.section.utility.end.bracket.curly.tailwind " `; diff --git a/packages/vscode-tailwindcss/syntaxes/theme-fn.tmLanguage.json b/packages/vscode-tailwindcss/syntaxes/theme-fn.tmLanguage.json index eab0467f5..0e02015f8 100644 --- a/packages/vscode-tailwindcss/syntaxes/theme-fn.tmLanguage.json +++ b/packages/vscode-tailwindcss/syntaxes/theme-fn.tmLanguage.json @@ -1,7 +1,10 @@ { "scopeName": "tailwindcss.theme-fn.injection", "fileTypes": [], - "injectionSelector": "L:meta.property-list.css -comment", + "injectionSelector": [ + "L:meta.property-list.css -comment", + "L:meta.at-rule.utility.body.tailwind -comment" + ], "name": "TailwindCSS", "patterns": [ { @@ -55,6 +58,135 @@ "name": "variable.parameter.screen.tailwind" } ] + }, + { + "begin": "(?i)(?