From 79b926609cd386af98f0f3ec9209f5f02f3a997c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 19 Mar 2025 16:13:18 -0400 Subject: [PATCH 1/5] =?UTF-8?q?Improve=20theme=20key=20completions=20in=20?= =?UTF-8?q?`--theme(=E2=80=A6)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/completionProvider.ts | 47 +++++++++++++++---- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 62c54594..7e221dc0 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -1014,7 +1014,7 @@ function provideCssHelperCompletions( const match = text .substr(0, text.length - 1) // don't include that extra character from earlier - .match(/[\s:;/*(){}](?config|theme|--theme)\(\s*['"]?(?[^)'"]*)$/) + .match(/[\s:;/*(){}](?config|theme|--theme|var)\(\s*['"]?(?[^)'"]*)$/d) if (match === null) { return null @@ -1041,16 +1041,9 @@ function provideCssHelperCompletions( } if (state.v4 && match.groups.helper === '--theme') { - // List known theme keys - let validThemeKeys = resolveKnownThemeKeys(state.designSystem) + let items: CompletionItem[] = themeKeyCompletions(state) - let items: CompletionItem[] = validThemeKeys.map((themeKey, index) => { - return { - label: themeKey, - sortText: naturalExpand(index, validThemeKeys.length), - kind: 9, - } - }) + editRange.start.character = match.indices.groups.helper[1] + 1 return withDefaults( { isIncomplete: false, items }, @@ -2486,3 +2479,37 @@ async function knownUtilityFunctionArguments(state: State, fn: UtilityFn): Promi return args } + +export function themeKeyCompletions(state: State): CompletionItem[] { + if (!state.v4) return null + if (!state.designSystem) return null + + let knownThemeKeys = resolveKnownThemeKeys(state.designSystem) + + return knownThemeKeys.map((themeKey, index) => { + let value = state.designSystem.resolveThemeValue(themeKey) + let documentation: string | undefined + + let color = getColorFromValue(value) + if (color !== null) { + if (typeof color !== 'string' && (color.alpha ?? 1) !== 0) { + documentation = formatColor(color) + } + + return { + label: themeKey, + kind: CompletionItemKind.Color, + sortText: naturalExpand(index, knownThemeKeys.length), + detail: value, + documentation, + } + } + + return { + label: themeKey, + kind: CompletionItemKind.Variable, + sortText: naturalExpand(index, knownThemeKeys.length), + detail: value, + } + }) +} From 6e5870e90c42954a6d4252a83dd0c7752804b0e0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 19 Mar 2025 16:15:54 -0400 Subject: [PATCH 2/5] =?UTF-8?q?Show=20theme=20key=20completions=20inside?= =?UTF-8?q?=20`theme(=E2=80=A6)`=20and=20`var(=E2=80=A6)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/completionProvider.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 7e221dc0..71818944 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -1040,7 +1040,12 @@ function provideCssHelperCompletions( end: position, } - if (state.v4 && match.groups.helper === '--theme') { + if ( + state.v4 && + (match.groups.helper === '--theme' || + match.groups.helper === 'theme' || + match.groups.helper === 'var') + ) { let items: CompletionItem[] = themeKeyCompletions(state) editRange.start.character = match.indices.groups.helper[1] + 1 @@ -1058,6 +1063,8 @@ function provideCssHelperCompletions( ) } + if (match.groups.helper === 'var') return null + let base = match.groups.helper === 'config' ? state.config : dlv(state.config, 'theme', {}) let parts = path.split(/([\[\].]+)/) let keys = parts.filter((_, i) => i % 2 === 0) From 9ef6fc14abd5e4867bb95223727df345fce1303f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 19 Mar 2025 16:17:59 -0400 Subject: [PATCH 3/5] Specify `forceInline` when resolving theme keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In v4.1 `—theme(…)` will resolve to `var(…)` as a way to generate the correct var() calls without needing to know the prefix. We want the actual, inlined values instead of the `var(…)` calls --- packages/tailwindcss-language-service/src/completionProvider.ts | 2 +- .../tailwindcss-language-service/src/util/rewriting/lookup.ts | 2 +- .../tailwindcss-language-service/src/util/v4/design-system.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 71818944..978f118c 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -2494,7 +2494,7 @@ export function themeKeyCompletions(state: State): CompletionItem[] { let knownThemeKeys = resolveKnownThemeKeys(state.designSystem) return knownThemeKeys.map((themeKey, index) => { - let value = state.designSystem.resolveThemeValue(themeKey) + let value = state.designSystem.resolveThemeValue(themeKey, true) let documentation: string | undefined let color = getColorFromValue(value) diff --git a/packages/tailwindcss-language-service/src/util/rewriting/lookup.ts b/packages/tailwindcss-language-service/src/util/rewriting/lookup.ts index ae8e70e7..2dbb7146 100644 --- a/packages/tailwindcss-language-service/src/util/rewriting/lookup.ts +++ b/packages/tailwindcss-language-service/src/util/rewriting/lookup.ts @@ -8,5 +8,5 @@ export function resolveVariableValue(design: DesignSystem, name: string) { name = `--${name.slice(prefix.length + 3)}` } - return design.resolveThemeValue?.(name) ?? null + return design.resolveThemeValue?.(name, true) ?? null } diff --git a/packages/tailwindcss-language-service/src/util/v4/design-system.ts b/packages/tailwindcss-language-service/src/util/v4/design-system.ts index 3fb3c401..20b7ff32 100644 --- a/packages/tailwindcss-language-service/src/util/v4/design-system.ts +++ b/packages/tailwindcss-language-service/src/util/v4/design-system.ts @@ -39,7 +39,7 @@ export interface DesignSystem { getVariants(): VariantEntry[] // Optional because it did not exist in earlier v4 alpha versions - resolveThemeValue?(path: string): string | undefined + resolveThemeValue?(path: string, forceInline?: boolean): string | undefined } export interface DesignSystem { From 00e647b28361eef6f179cad5cd490a219d1dac84 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 19 Mar 2025 16:19:39 -0400 Subject: [PATCH 4/5] Update changelog --- packages/vscode-tailwindcss/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index fa2d07c3..7bf90d04 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -7,6 +7,7 @@ - v4: Add support for upcoming `@source not` feature ([#1262](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1262)) - v4: Add support for upcoming `@source inline(…)` feature ([#1262](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1262)) - LSP: Refresh internal caches when settings are updated ([#1273](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1273)) +- v4: Show theme key completions in `var(…)` in CSS ([#1274](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1274)) # 0.14.9 From 5e02daea80416a980b3e1ed2be4ca312ad6005d5 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 19 Mar 2025 16:24:17 -0400 Subject: [PATCH 5/5] Add test --- .../tests/completions/completions.test.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js index 15c220bb..024213cb 100644 --- a/packages/tailwindcss-language-server/tests/completions/completions.test.js +++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js @@ -2,6 +2,7 @@ import { test, expect } from 'vitest' import { withFixture } from '../common' import { css, defineTest, html, js } from '../../src/testing' import { createClient } from '../utils/client' +import { CompletionItemKind } from 'vscode-languageserver' function buildCompletion(c) { return async function completion({ @@ -798,3 +799,53 @@ defineTest({ expect(completion?.items.length).toBe(12289) }, }) + +defineTest({ + name: 'v4: Theme key completions show in var(…)', + fs: { + 'app.css': css` + @import 'tailwindcss'; + + @theme { + --color-custom: #000; + } + `, + }, + prepare: async ({ root }) => ({ client: await createClient({ root }) }), + handle: async ({ client }) => { + let document = await client.open({ + settings: { + tailwindCSS: { + classFunctions: ['clsx'], + }, + }, + lang: 'css', + text: css` + .foo { + color: var(); + } + `, + }) + + // color: var(); + // ^ + let completion = await document.completions({ line: 1, character: 13 }) + + expect(completion).toEqual({ + isIncomplete: false, + items: expect.arrayContaining([ + // From the default theme + expect.objectContaining({ label: '--font-sans' }), + + // From the `@theme` block in the CSS file + expect.objectContaining({ + label: '--color-custom', + + // And it's shown as a color + kind: CompletionItemKind.Color, + documentation: '#000000', + }), + ]), + }) + }, +})