Skip to content

Commit 7419259

Browse files
v4: Show theme key completions in var(…) (#1274)
Closes #1209
1 parent f91a3bc commit 7419259

File tree

5 files changed

+99
-13
lines changed

5 files changed

+99
-13
lines changed

packages/tailwindcss-language-server/tests/completions/completions.test.js

+51
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { test, expect } from 'vitest'
22
import { withFixture } from '../common'
33
import { css, defineTest, html, js } from '../../src/testing'
44
import { createClient } from '../utils/client'
5+
import { CompletionItemKind } from 'vscode-languageserver'
56

67
function buildCompletion(c) {
78
return async function completion({
@@ -798,3 +799,53 @@ defineTest({
798799
expect(completion?.items.length).toBe(12289)
799800
},
800801
})
802+
803+
defineTest({
804+
name: 'v4: Theme key completions show in var(…)',
805+
fs: {
806+
'app.css': css`
807+
@import 'tailwindcss';
808+
809+
@theme {
810+
--color-custom: #000;
811+
}
812+
`,
813+
},
814+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
815+
handle: async ({ client }) => {
816+
let document = await client.open({
817+
settings: {
818+
tailwindCSS: {
819+
classFunctions: ['clsx'],
820+
},
821+
},
822+
lang: 'css',
823+
text: css`
824+
.foo {
825+
color: var();
826+
}
827+
`,
828+
})
829+
830+
// color: var();
831+
// ^
832+
let completion = await document.completions({ line: 1, character: 13 })
833+
834+
expect(completion).toEqual({
835+
isIncomplete: false,
836+
items: expect.arrayContaining([
837+
// From the default theme
838+
expect.objectContaining({ label: '--font-sans' }),
839+
840+
// From the `@theme` block in the CSS file
841+
expect.objectContaining({
842+
label: '--color-custom',
843+
844+
// And it's shown as a color
845+
kind: CompletionItemKind.Color,
846+
documentation: '#000000',
847+
}),
848+
]),
849+
})
850+
},
851+
})

packages/tailwindcss-language-service/src/completionProvider.ts

+45-11
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ function provideCssHelperCompletions(
10141014

10151015
const match = text
10161016
.substr(0, text.length - 1) // don't include that extra character from earlier
1017-
.match(/[\s:;/*(){}](?<helper>config|theme|--theme)\(\s*['"]?(?<path>[^)'"]*)$/)
1017+
.match(/[\s:;/*(){}](?<helper>config|theme|--theme|var)\(\s*['"]?(?<path>[^)'"]*)$/d)
10181018

10191019
if (match === null) {
10201020
return null
@@ -1040,17 +1040,15 @@ function provideCssHelperCompletions(
10401040
end: position,
10411041
}
10421042

1043-
if (state.v4 && match.groups.helper === '--theme') {
1044-
// List known theme keys
1045-
let validThemeKeys = resolveKnownThemeKeys(state.designSystem)
1043+
if (
1044+
state.v4 &&
1045+
(match.groups.helper === '--theme' ||
1046+
match.groups.helper === 'theme' ||
1047+
match.groups.helper === 'var')
1048+
) {
1049+
let items: CompletionItem[] = themeKeyCompletions(state)
10461050

1047-
let items: CompletionItem[] = validThemeKeys.map((themeKey, index) => {
1048-
return {
1049-
label: themeKey,
1050-
sortText: naturalExpand(index, validThemeKeys.length),
1051-
kind: 9,
1052-
}
1053-
})
1051+
editRange.start.character = match.indices.groups.helper[1] + 1
10541052

10551053
return withDefaults(
10561054
{ isIncomplete: false, items },
@@ -1065,6 +1063,8 @@ function provideCssHelperCompletions(
10651063
)
10661064
}
10671065

1066+
if (match.groups.helper === 'var') return null
1067+
10681068
let base = match.groups.helper === 'config' ? state.config : dlv(state.config, 'theme', {})
10691069
let parts = path.split(/([\[\].]+)/)
10701070
let keys = parts.filter((_, i) => i % 2 === 0)
@@ -2486,3 +2486,37 @@ async function knownUtilityFunctionArguments(state: State, fn: UtilityFn): Promi
24862486

24872487
return args
24882488
}
2489+
2490+
export function themeKeyCompletions(state: State): CompletionItem[] {
2491+
if (!state.v4) return null
2492+
if (!state.designSystem) return null
2493+
2494+
let knownThemeKeys = resolveKnownThemeKeys(state.designSystem)
2495+
2496+
return knownThemeKeys.map((themeKey, index) => {
2497+
let value = state.designSystem.resolveThemeValue(themeKey, true)
2498+
let documentation: string | undefined
2499+
2500+
let color = getColorFromValue(value)
2501+
if (color !== null) {
2502+
if (typeof color !== 'string' && (color.alpha ?? 1) !== 0) {
2503+
documentation = formatColor(color)
2504+
}
2505+
2506+
return {
2507+
label: themeKey,
2508+
kind: CompletionItemKind.Color,
2509+
sortText: naturalExpand(index, knownThemeKeys.length),
2510+
detail: value,
2511+
documentation,
2512+
}
2513+
}
2514+
2515+
return {
2516+
label: themeKey,
2517+
kind: CompletionItemKind.Variable,
2518+
sortText: naturalExpand(index, knownThemeKeys.length),
2519+
detail: value,
2520+
}
2521+
})
2522+
}

packages/tailwindcss-language-service/src/util/rewriting/lookup.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ export function resolveVariableValue(design: DesignSystem, name: string) {
88
name = `--${name.slice(prefix.length + 3)}`
99
}
1010

11-
return design.resolveThemeValue?.(name) ?? null
11+
return design.resolveThemeValue?.(name, true) ?? null
1212
}

packages/tailwindcss-language-service/src/util/v4/design-system.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface DesignSystem {
3939
getVariants(): VariantEntry[]
4040

4141
// Optional because it did not exist in earlier v4 alpha versions
42-
resolveThemeValue?(path: string): string | undefined
42+
resolveThemeValue?(path: string, forceInline?: boolean): string | undefined
4343
}
4444

4545
export interface DesignSystem {

packages/vscode-tailwindcss/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- v4: Add support for upcoming `@source inline(…)` feature ([#1262](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1262))
99
- LSP: Refresh internal caches when settings are updated ([#1273](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1273))
1010
- 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))
11+
- v4: Show theme key completions in `var(…)` in CSS ([#1274](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1274))
1112

1213
# 0.14.9
1314

0 commit comments

Comments
 (0)