Skip to content

Commit 97cfd2d

Browse files
committed
Add CSS var() hovers when using v4 (#1289)
This adds support for hovering over things like `var(--color-red-500)` or `var(--breakpoint-xl)` and showing the value from the theme like we already support with the `theme()` function. Additionally, I've improved the hovers for v4 theme keys. They now appear in a `@theme` block like you'd see them in your CSS and are also syntax highlighted.
1 parent b92d170 commit 97cfd2d

File tree

6 files changed

+108
-6
lines changed

6 files changed

+108
-6
lines changed

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

+80-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { test } from 'vitest'
1+
import { expect, test } from 'vitest'
22
import { withFixture } from '../common'
3+
import { css, defineTest } from '../../src/testing'
4+
import { createClient } from '../utils/client'
35

46
withFixture('basic', (c) => {
57
async function testHover(
@@ -396,7 +398,14 @@ withFixture('v4/basic', (c) => {
396398
expected: {
397399
contents: {
398400
kind: 'markdown',
399-
value: ['```plaintext', '80rem /* 1280px */', '```'].join('\n'),
401+
value: [
402+
//
403+
'```css',
404+
'@theme {',
405+
' --breakpoint-xl: 80rem /* 1280px */;',
406+
'}',
407+
'```',
408+
].join('\n'),
400409
},
401410
range: {
402411
start: { line: 0, character: 23 },
@@ -544,3 +553,72 @@ withFixture('v4/path-mappings', (c) => {
544553
},
545554
})
546555
})
556+
557+
defineTest({
558+
name: 'Can hover showing theme values used in var(…) and theme(…) functions',
559+
fs: {
560+
'app.css': css`
561+
@import 'tailwindcss';
562+
`,
563+
},
564+
565+
prepare: async ({ root }) => ({ client: await createClient({ root }) }),
566+
567+
handle: async ({ client }) => {
568+
let doc = await client.open({
569+
lang: 'css',
570+
text: css`
571+
.foo {
572+
color: theme(--color-black);
573+
}
574+
.bar {
575+
color: var(--color-black);
576+
}
577+
`,
578+
})
579+
580+
// color: theme(--color-black);
581+
// ^
582+
let hoverTheme = await doc.hover({ line: 1, character: 18 })
583+
584+
// color: var(--color-black);
585+
// ^
586+
let hoverVar = await doc.hover({ line: 4, character: 16 })
587+
588+
expect(hoverTheme).toEqual({
589+
contents: {
590+
kind: 'markdown',
591+
value: [
592+
//
593+
'```css',
594+
'@theme {',
595+
' --color-black: #000;',
596+
'}',
597+
'```',
598+
].join('\n'),
599+
},
600+
range: {
601+
start: { line: 1, character: 15 },
602+
end: { line: 1, character: 28 },
603+
},
604+
})
605+
606+
expect(hoverVar).toEqual({
607+
contents: {
608+
kind: 'markdown',
609+
value: [
610+
//
611+
'```css',
612+
'@theme {',
613+
' --color-black: #000;',
614+
'}',
615+
'```',
616+
].join('\n'),
617+
},
618+
range: {
619+
start: { line: 4, character: 13 },
620+
end: { line: 4, character: 26 },
621+
},
622+
})
623+
},
624+
})

packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts

+5
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ export function getInvalidConfigPathDiagnostics(
186186

187187
findHelperFunctionsInDocument(state, document).forEach((helperFn) => {
188188
let base = helperFn.helper === 'theme' ? ['theme'] : []
189+
190+
// var(…) may not refer to theme values but other values in the cascade
191+
// so they can't be unconditionally validated
192+
if (helperFn.helper === 'var') return
193+
189194
let result = validateConfigPath(state, helperFn.path, base)
190195

191196
if (result.isValid === true) {

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ async function provideCssHelperHover(
5353
for (let helperFn of helperFns) {
5454
if (!isWithinRange(position, helperFn.ranges.path)) continue
5555

56+
if (helperFn.helper === 'var' && !state.v4) continue
57+
5658
let validated = validateConfigPath(
5759
state,
5860
helperFn.path,
@@ -67,8 +69,21 @@ async function provideCssHelperHover(
6769
value = addPixelEquivalentsToValue(value, settings.tailwindCSS.rootFontSize)
6870
}
6971

72+
let lines = ['```plaintext', value, '```']
73+
74+
if (state.v4 && helperFn.path.startsWith('--')) {
75+
lines = [
76+
//
77+
'```css',
78+
'@theme {',
79+
` ${helperFn.path}: ${value};`,
80+
'}',
81+
'```',
82+
]
83+
}
84+
7085
return {
71-
contents: { kind: 'markdown', value: ['```plaintext', value, '```'].join('\n') },
86+
contents: { kind: 'markdown', value: lines.join('\n') },
7287
range: helperFn.ranges.path,
7388
}
7489
}

packages/tailwindcss-language-service/src/util/find.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ export function findHelperFunctionsInRange(
405405
): DocumentHelperFunction[] {
406406
const text = getTextWithoutComments(doc, 'css', range)
407407
let matches = findAll(
408-
/(?<prefix>[\W])(?<helper>config|theme|--theme)(?<innerPrefix>\(\s*)(?<path>[^)]*?)\s*\)/g,
408+
/(?<prefix>[\W])(?<helper>config|theme|--theme|var)(?<innerPrefix>\(\s*)(?<path>[^)]*?)\s*\)/g,
409409
text,
410410
)
411411

@@ -450,10 +450,12 @@ export function findHelperFunctionsInRange(
450450
match.groups.helper.length +
451451
match.groups.innerPrefix.length
452452

453-
let helper: 'config' | 'theme' = 'config'
453+
let helper: 'config' | 'theme' | 'var' = 'config'
454454

455455
if (match.groups.helper === 'theme' || match.groups.helper === '--theme') {
456456
helper = 'theme'
457+
} else if (match.groups.helper === 'var') {
458+
helper = 'var'
457459
}
458460

459461
return {

packages/tailwindcss-language-service/src/util/state.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ export type DocumentClassName = {
161161
}
162162

163163
export type DocumentHelperFunction = {
164-
helper: 'theme' | 'config'
164+
helper: 'theme' | 'config' | 'var'
165165
path: string
166166
ranges: {
167167
full: Range

packages/vscode-tailwindcss/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
- Hide completions from CSS language server inside `@import "…" source(…)` ([#1091](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1091))
66
- Bump bundled v4 fallback to v4.1.1 ([#1294](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1294))
77
- Show color swatches for most new v4.1 utilities ([#1294](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1294))
8+
- Support theme key hovers in the CSS `var()` function ([#1289](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1289))
9+
- Show theme key hovers inside `@theme` for better context and syntax highlighting ([#1289](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1289))
810

911
# 0.14.12
1012

0 commit comments

Comments
 (0)