diff --git a/packages/tailwindcss-language-server/tests/hover/hover.test.js b/packages/tailwindcss-language-server/tests/hover/hover.test.js index 37377340..379f4199 100644 --- a/packages/tailwindcss-language-server/tests/hover/hover.test.js +++ b/packages/tailwindcss-language-server/tests/hover/hover.test.js @@ -1,5 +1,7 @@ -import { test } from 'vitest' +import { expect, test } from 'vitest' import { withFixture } from '../common' +import { css, defineTest } from '../../src/testing' +import { createClient } from '../utils/client' withFixture('basic', (c) => { async function testHover( @@ -396,7 +398,14 @@ withFixture('v4/basic', (c) => { expected: { contents: { kind: 'markdown', - value: ['```plaintext', '80rem /* 1280px */', '```'].join('\n'), + value: [ + // + '```css', + '@theme {', + ' --breakpoint-xl: 80rem /* 1280px */;', + '}', + '```', + ].join('\n'), }, range: { start: { line: 0, character: 23 }, @@ -544,3 +553,72 @@ withFixture('v4/path-mappings', (c) => { }, }) }) + +defineTest({ + name: 'Can hover showing theme values used in var(…) and theme(…) functions', + fs: { + 'app.css': css` + @import 'tailwindcss'; + `, + }, + + prepare: async ({ root }) => ({ client: await createClient({ root }) }), + + handle: async ({ client }) => { + let doc = await client.open({ + lang: 'css', + text: css` + .foo { + color: theme(--color-black); + } + .bar { + color: var(--color-black); + } + `, + }) + + // color: theme(--color-black); + // ^ + let hoverTheme = await doc.hover({ line: 1, character: 18 }) + + // color: var(--color-black); + // ^ + let hoverVar = await doc.hover({ line: 4, character: 16 }) + + expect(hoverTheme).toEqual({ + contents: { + kind: 'markdown', + value: [ + // + '```css', + '@theme {', + ' --color-black: #000;', + '}', + '```', + ].join('\n'), + }, + range: { + start: { line: 1, character: 15 }, + end: { line: 1, character: 28 }, + }, + }) + + expect(hoverVar).toEqual({ + contents: { + kind: 'markdown', + value: [ + // + '```css', + '@theme {', + ' --color-black: #000;', + '}', + '```', + ].join('\n'), + }, + range: { + start: { line: 4, character: 13 }, + end: { line: 4, character: 26 }, + }, + }) + }, +}) diff --git a/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts b/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts index d20655e3..76864281 100644 --- a/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts +++ b/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts @@ -186,6 +186,11 @@ export function getInvalidConfigPathDiagnostics( findHelperFunctionsInDocument(state, document).forEach((helperFn) => { let base = helperFn.helper === 'theme' ? ['theme'] : [] + + // var(…) may not refer to theme values but other values in the cascade + // so they can't be unconditionally validated + if (helperFn.helper === 'var') return + let result = validateConfigPath(state, helperFn.path, base) if (result.isValid === true) { diff --git a/packages/tailwindcss-language-service/src/hoverProvider.ts b/packages/tailwindcss-language-service/src/hoverProvider.ts index 1db68bed..583cc80f 100644 --- a/packages/tailwindcss-language-service/src/hoverProvider.ts +++ b/packages/tailwindcss-language-service/src/hoverProvider.ts @@ -53,6 +53,8 @@ async function provideCssHelperHover( for (let helperFn of helperFns) { if (!isWithinRange(position, helperFn.ranges.path)) continue + if (helperFn.helper === 'var' && !state.v4) continue + let validated = validateConfigPath( state, helperFn.path, @@ -67,8 +69,21 @@ async function provideCssHelperHover( value = addPixelEquivalentsToValue(value, settings.tailwindCSS.rootFontSize) } + let lines = ['```plaintext', value, '```'] + + if (state.v4 && helperFn.path.startsWith('--')) { + lines = [ + // + '```css', + '@theme {', + ` ${helperFn.path}: ${value};`, + '}', + '```', + ] + } + return { - contents: { kind: 'markdown', value: ['```plaintext', value, '```'].join('\n') }, + contents: { kind: 'markdown', value: lines.join('\n') }, range: helperFn.ranges.path, } } diff --git a/packages/tailwindcss-language-service/src/util/find.ts b/packages/tailwindcss-language-service/src/util/find.ts index 03218798..9118403d 100644 --- a/packages/tailwindcss-language-service/src/util/find.ts +++ b/packages/tailwindcss-language-service/src/util/find.ts @@ -405,7 +405,7 @@ export function findHelperFunctionsInRange( ): DocumentHelperFunction[] { const text = getTextWithoutComments(doc, 'css', range) let matches = findAll( - /(?[\W])(?config|theme|--theme)(?\(\s*)(?[^)]*?)\s*\)/g, + /(?[\W])(?config|theme|--theme|var)(?\(\s*)(?[^)]*?)\s*\)/g, text, ) @@ -450,10 +450,12 @@ export function findHelperFunctionsInRange( match.groups.helper.length + match.groups.innerPrefix.length - let helper: 'config' | 'theme' = 'config' + let helper: 'config' | 'theme' | 'var' = 'config' if (match.groups.helper === 'theme' || match.groups.helper === '--theme') { helper = 'theme' + } else if (match.groups.helper === 'var') { + helper = 'var' } return { diff --git a/packages/tailwindcss-language-service/src/util/state.ts b/packages/tailwindcss-language-service/src/util/state.ts index 119e5f59..8c819eb8 100644 --- a/packages/tailwindcss-language-service/src/util/state.ts +++ b/packages/tailwindcss-language-service/src/util/state.ts @@ -161,7 +161,7 @@ export type DocumentClassName = { } export type DocumentHelperFunction = { - helper: 'theme' | 'config' + helper: 'theme' | 'config' | 'var' path: string ranges: { full: Range diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index 421543f5..d55074be 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -5,6 +5,8 @@ - Hide completions from CSS language server inside `@import "…" source(…)` ([#1091](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1091)) - Bump bundled v4 fallback to v4.1.1 ([#1294](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1294)) - Show color swatches for most new v4.1 utilities ([#1294](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1294)) +- Support theme key hovers in the CSS `var()` function ([#1289](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1289)) +- Show theme key hovers inside `@theme` for better context and syntax highlighting ([#1289](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1289)) # 0.14.12