diff --git a/packages/tailwindcss-language-server/src/project-locator.ts b/packages/tailwindcss-language-server/src/project-locator.ts index 0bb3947d..e708be0a 100644 --- a/packages/tailwindcss-language-server/src/project-locator.ts +++ b/packages/tailwindcss-language-server/src/project-locator.ts @@ -101,14 +101,23 @@ export class ProjectLocator { configPath: string, selectors: string[], ): Promise { - let config: ConfigEntry = { - type: 'js', - path: configPath, - source: 'js', - entries: [], - content: [], - packageRoot: '', - } + let config: ConfigEntry = configPath.endsWith('.css') + ? { + type: 'css', + path: configPath, + source: 'css', + entries: [], + content: [], + packageRoot: '', + } + : { + type: 'js', + path: configPath, + source: 'js', + entries: [], + content: [], + packageRoot: '', + } let tailwind = await this.detectTailwindVersion(config) diff --git a/packages/tailwindcss-language-server/tests/common.ts b/packages/tailwindcss-language-server/tests/common.ts index e78b94ea..37339159 100644 --- a/packages/tailwindcss-language-server/tests/common.ts +++ b/packages/tailwindcss-language-server/tests/common.ts @@ -261,14 +261,16 @@ export async function init( text, lang = 'html', dir = '', + name = null, settings = {}, }: { text: string lang?: string dir?: string + name?: string settings?: Settings }) { - let uri = resolveUri(dir, `file-${counter++}`) + let uri = resolveUri(dir, name ?? `file-${counter++}`) docSettings.set(uri, settings) let openPromise = openingDocuments.remember(uri, () => { diff --git a/packages/tailwindcss-language-server/tests/env/v4.test.js b/packages/tailwindcss-language-server/tests/env/v4.test.js index 9f14f06a..56de119b 100644 --- a/packages/tailwindcss-language-server/tests/env/v4.test.js +++ b/packages/tailwindcss-language-server/tests/env/v4.test.js @@ -344,3 +344,188 @@ defineTest({ }) }, }) + +defineTest({ + name: 'v4, using local, with explicit CSS entrypoints', + fs: { + 'package.json': json` + { + "dependencies": { + "tailwindcss": "4.0.1" + } + } + `, + 'a/app.css': css` + @import 'tailwindcss'; + @theme { + --color-primary: #000000; + } + `, + 'b/app.css': css` + @import 'tailwindcss'; + @theme { + --color-primary: #ffffff; + } + `, + }, + prepare: async ({ root }) => ({ c: await init(root) }), + handle: async ({ c }) => { + await c.updateSettings({ + tailwindCSS: { + experimental: { + configFile: { + 'a/app.css': 'c/a/**', + 'b/app.css': 'c/b/**', + }, + }, + }, + }) + + let documentA = await c.openDocument({ + lang: 'html', + text: '
', + name: 'c/a/index.html', + }) + + let documentB = await c.openDocument({ + lang: 'html', + text: '
', + name: 'c/b/index.html', + }) + + let hoverA = await c.sendRequest(HoverRequest.type, { + textDocument: documentA, + + //
+ // ^ + position: { line: 0, character: 13 }, + }) + + let hoverB = await c.sendRequest(HoverRequest.type, { + textDocument: documentB, + + //
+ // ^ + position: { line: 0, character: 13 }, + }) + + expect(hoverA).toEqual({ + contents: { + language: 'css', + value: dedent` + .bg-primary { + background-color: var(--color-primary) /* #000000 */; + } + `, + }, + range: { + start: { line: 0, character: 12 }, + end: { line: 0, character: 22 }, + }, + }) + + expect(hoverB).toEqual({ + contents: { + language: 'css', + value: dedent` + .bg-primary { + background-color: var(--color-primary) /* #ffffff */; + } + `, + }, + range: { + start: { line: 0, character: 12 }, + end: { line: 0, character: 22 }, + }, + }) + }, +}) + +defineTest({ + name: 'v4, using fallback, with explicit CSS entrypoints', + fs: { + 'a/app.css': css` + @import 'tailwindcss'; + @theme { + --color-primary: #000000; + } + `, + 'b/app.css': css` + @import 'tailwindcss'; + @theme { + --color-primary: #ffffff; + } + `, + }, + prepare: async ({ root }) => ({ c: await init(root) }), + handle: async ({ c }) => { + await c.updateSettings({ + tailwindCSS: { + experimental: { + configFile: { + 'a/app.css': 'c/a/**', + 'b/app.css': 'c/b/**', + }, + }, + }, + }) + + let documentA = await c.openDocument({ + lang: 'html', + text: '
', + name: 'c/a/index.html', + }) + + let documentB = await c.openDocument({ + lang: 'html', + text: '
', + name: 'c/b/index.html', + }) + + let hoverA = await c.sendRequest(HoverRequest.type, { + textDocument: documentA, + + //
+ // ^ + position: { line: 0, character: 13 }, + }) + + let hoverB = await c.sendRequest(HoverRequest.type, { + textDocument: documentB, + + //
+ // ^ + position: { line: 0, character: 13 }, + }) + + expect(hoverA).toEqual({ + contents: { + language: 'css', + value: dedent` + .bg-primary { + background-color: var(--color-primary) /* #000000 */; + } + `, + }, + range: { + start: { line: 0, character: 12 }, + end: { line: 0, character: 22 }, + }, + }) + + expect(hoverB).toEqual({ + contents: { + language: 'css', + value: dedent` + .bg-primary { + background-color: var(--color-primary) /* #ffffff */; + } + `, + }, + range: { + start: { line: 0, character: 12 }, + end: { line: 0, character: 22 }, + }, + }) + }, +}) diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index 2abdb546..ca62ab97 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -11,6 +11,7 @@ - Support style-rule like completions inside `@variant` ([#1165](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1165)) - Make sure `@slot` isn't considered an unknown at-rule ([#1165](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1165)) - Fix equivalent calculation when using prefixes in v4 ([#1166](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1166)) +- Fix use of `tailwindCSS.experimental.configFile` option when using the bundled version of v4 ([#1167](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1167)) ## 0.14.2 diff --git a/packages/vscode-tailwindcss/README.md b/packages/vscode-tailwindcss/README.md index 24b7ca68..62165308 100644 --- a/packages/vscode-tailwindcss/README.md +++ b/packages/vscode-tailwindcss/README.md @@ -164,15 +164,43 @@ Enable the Node.js inspector agent for the language server and listen on the spe **Default: `null`** -By default the extension will automatically use the first `tailwind.config.{js,cjs,mjs,ts,cts,mts}` file that it can find to provide Tailwind CSS IntelliSense. Use this setting to manually specify the config file(s) yourself instead. +This setting allows you to manually specify the CSS entrypoints (for v4 projects) or the Tailwind configuration file (for v3 projects). By default, the extension attempts to detect your project setup automatically: -If your project contains a single Tailwind config file you can specify a string value: +- **For Tailwind CSS v4**: The extension scans your project for CSS files and determines the "root" CSS file. +- **For Tailwind CSS v3 (and earlier)**: The extension automatically uses the first `tailwind.config.{js,cjs,mjs,ts,cts,mts}` file it finds. + +If IntelliSense is unable to detect your project, you can use this setting to define your config files manually. + +#### Tailwind CSS v4.x (CSS entrypoints) + +For v4 projects, specify the CSS file(s) that serve as your Tailwind entrypoints. + +If your project contains a single CSS entrypoint, set this option to a string: + +```json +"tailwindCSS.experimental.configFile": "src/styles/app.css" +``` + +For projects with multiple CSS entrypoints, use an object where each key is a file path and each value is a glob pattern (or array of patterns) representing the files it applies to: + +```json +"tailwindCSS.experimental.configFile": { + "packages/a/src/app.css": "packages/a/src/**", + "packages/b/src/app.css": "packages/b/src/**" +} +``` + +#### Tailwind CSS v3.x and earlier (config files) + +For v3 projects and below, specify the Tailwind configuration file(s) instead. + +If your project contains a single Tailwind config, set this option to a string: ```json "tailwindCSS.experimental.configFile": ".config/tailwind.config.js" ``` -For projects with multiple config files use an object where each key is a config file path and each value is a glob pattern (or array of glob patterns) representing the set of files that the config file applies to: +For projects with multiple config files, use an object where each key is a config file path and each value is a glob pattern (or array of patterns) representing the files it applies to: ```json "tailwindCSS.experimental.configFile": {