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', + }), + ]), + }) + }, +}) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 62c54594..978f118c 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 @@ -1040,17 +1040,15 @@ function provideCssHelperCompletions( end: position, } - if (state.v4 && match.groups.helper === '--theme') { - // List known theme keys - let validThemeKeys = resolveKnownThemeKeys(state.designSystem) + if ( + state.v4 && + (match.groups.helper === '--theme' || + match.groups.helper === 'theme' || + match.groups.helper === 'var') + ) { + 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 }, @@ -1065,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) @@ -2486,3 +2486,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, true) + 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, + } + }) +} 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 { diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index 32733ec8..7b4d62bb 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -8,6 +8,7 @@ - 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)) - LSP: Improve error message when a workspace folder does not exist or is inaccesible to the current user ([#1276](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1276)) +- v4: Show theme key completions in `var(…)` in CSS ([#1274](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1274)) # 0.14.9