diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js index f5393a40..15c220bb 100644 --- a/packages/tailwindcss-language-server/tests/completions/completions.test.js +++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js @@ -1,6 +1,6 @@ -import { test, expect, describe } from 'vitest' +import { test, expect } from 'vitest' import { withFixture } from '../common' -import { css, defineTest } from '../../src/testing' +import { css, defineTest, html, js } from '../../src/testing' import { createClient } from '../utils/client' function buildCompletion(c) { @@ -738,3 +738,63 @@ defineTest({ expect(completion?.items.length).toBe(12289) }, }) + +defineTest({ + name: 'v4: Completions show inside class functions in JS/TS files', + fs: { + 'app.css': css` + @import 'tailwindcss'; + `, + }, + prepare: async ({ root }) => ({ client: await createClient({ root }) }), + handle: async ({ client }) => { + let document = await client.open({ + settings: { + tailwindCSS: { + classFunctions: ['clsx'], + }, + }, + lang: 'javascript', + text: js` + let classes = clsx(''); + `, + }) + + // let classes = clsx(''); + // ^ + let completion = await document.completions({ line: 0, character: 20 }) + + expect(completion?.items.length).toBe(12289) + }, +}) + +defineTest({ + name: 'v4: Completions show inside class functions in JS/TS contexts', + fs: { + 'app.css': css` + @import 'tailwindcss'; + `, + }, + prepare: async ({ root }) => ({ client: await createClient({ root }) }), + handle: async ({ client }) => { + let document = await client.open({ + settings: { + tailwindCSS: { + classFunctions: ['clsx'], + }, + }, + lang: 'html', + text: html` + + `, + }) + + // let classes = clsx('') + // ^ + let completion = await document.completions({ line: 1, character: 22 }) + + expect(completion?.items.length).toBe(12289) + }, +}) diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 3cdd511a..62c54594 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -22,7 +22,7 @@ import isObject from './util/isObject' import { braceLevel, parenLevel } from './util/braceLevel' import * as emmetHelper from 'vscode-emmet-helper-bundled' import { isValidLocationForEmmetAbbreviation } from './util/isValidLocationForEmmetAbbreviation' -import { isJsDoc, isJsxContext } from './util/js' +import { isJsContext, isJsDoc, isJsxContext } from './util/js' import { naturalExpand } from './util/naturalExpand' import * as semver from './util/semver' import { getTextWithoutComments } from './util/doc' @@ -986,7 +986,11 @@ async function provideClassNameCompletions( return provideAtApplyCompletions(state, document, position, context) } - if (isHtmlContext(state, document, position) || isJsxContext(state, document, position)) { + if ( + isHtmlContext(state, document, position) || + isJsContext(state, document, position) || + isJsxContext(state, document, position) + ) { return provideClassAttributeCompletions(state, document, position, context) } diff --git a/packages/tailwindcss-language-service/src/util/js.ts b/packages/tailwindcss-language-service/src/util/js.ts index 1197d1e6..0c405a8d 100644 --- a/packages/tailwindcss-language-service/src/util/js.ts +++ b/packages/tailwindcss-language-service/src/util/js.ts @@ -12,6 +12,19 @@ export function isJsDoc(state: State, doc: TextDocument): boolean { return [...jsLanguages, ...userJsLanguages].indexOf(doc.languageId) !== -1 } +export function isJsContext(state: State, doc: TextDocument, position: Position): boolean { + let str = doc.getText({ + start: { line: 0, character: 0 }, + end: position, + }) + + let boundaries = getLanguageBoundaries(state, doc, str) + + return boundaries + ? ['js', 'ts', 'jsx', 'tsx'].includes(boundaries[boundaries.length - 1].type) + : false +} + export function isJsxContext(state: State, doc: TextDocument, position: Position): boolean { let str = doc.getText({ start: { line: 0, character: 0 }, diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index faf20065..468cdd08 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -2,7 +2,7 @@ ## Prerelease -- Detect classes in JS/TS functions and tagged template literals with the `tailwindCSS.classFunctions` setting ([#1258](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1258)) +- Detect classes in JS/TS functions and tagged template literals with the `tailwindCSS.classFunctions` setting ([#1258](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1258), [#1272](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1272)) - v4: Make sure completions show after variants using arbitrary and bare values ([#1263](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1263)) - v4: Add support for upcoming `@source not` feature ([#1262](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1262)) - v4: Add support for upcoming `@source inline(…)` feature ([#1262](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1262))