+ // ^
+ let completion = await document.completions({ line: 0, character: 22 })
+
+ expect(completion?.items.length).toBe(12289)
+ },
+})
+
+defineTest({
+ name: 'v4: Completions show after a variant with a bare value',
+ fs: {
+ 'app.css': css`
+ @import 'tailwindcss';
+ `,
+ },
+ prepare: async ({ root }) => ({ client: await createClient({ root }) }),
+ handle: async ({ client }) => {
+ let document = await client.open({
+ lang: 'html',
+ text: '
',
+ })
+
+ //
+ // ^
+ let completion = await document.completions({ line: 0, character: 31 })
+
+ 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 fe43bb68..1579fd93 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -189,16 +189,8 @@ export function completionsFromClassList(
}),
)
} else {
- let shouldSortVariants = !semver.gte(state.version, '2.99.0')
let resultingVariants = [...existingVariants, variant.name]
- if (shouldSortVariants) {
- let allVariants = state.variants.map(({ name }) => name)
- resultingVariants = resultingVariants.sort(
- (a, b) => allVariants.indexOf(b) - allVariants.indexOf(a),
- )
- }
-
let selectors: string[] = []
try {
@@ -223,25 +215,6 @@ export function completionsFromClassList(
.map((selector) => addPixelEquivalentsToMediaQuery(selector))
.join(', '),
textEditText: resultingVariants[resultingVariants.length - 1] + sep,
- additionalTextEdits:
- shouldSortVariants && resultingVariants.length > 1
- ? [
- {
- newText:
- resultingVariants.slice(0, resultingVariants.length - 1).join(sep) + sep,
- range: {
- start: {
- ...classListRange.start,
- character: classListRange.end.character - partialClassName.length,
- },
- end: {
- ...replacementRange.start,
- character: replacementRange.start.character,
- },
- },
- },
- ]
- : [],
}),
)
}
diff --git a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
index b58bb29f..c30e729a 100644
--- a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
+++ b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
@@ -1,5 +1,6 @@
import type { State } from './state'
import * as jit from './jit'
+import { segment } from './segment'
export function getVariantsFromClassName(
state: State,
@@ -13,60 +14,52 @@ export function getVariantsFromClassName(
}
return [variant.name]
})
- let variants = new Set()
- let offset = 0
- let parts = splitAtTopLevelOnly(className, state.separator)
+
+ let parts = segment(className, state.separator)
if (parts.length < 2) {
- return { variants: Array.from(variants), offset }
+ return { variants: [], offset: 0 }
}
+
parts = parts.filter(Boolean)
- for (let part of parts) {
- if (
- allVariants.includes(part) ||
- (state.jit &&
- ((part.includes('[') && part.endsWith(']')) || part.includes('/')) &&
- jit.generateRules(state, [`${part}${state.separator}[color:red]`]).rules.length > 0)
- ) {
- variants.add(part)
- offset += part.length + state.separator.length
- continue
+ function isValidVariant(part: string) {
+ if (allVariants.includes(part)) {
+ return true
}
- break
- }
+ let className = `${part}${state.separator}[color:red]`
- return { variants: Array.from(variants), offset }
-}
+ if (state.v4) {
+ // NOTE: This should never happen
+ if (!state.designSystem) return false
-// https://github.com/tailwindlabs/tailwindcss/blob/a8a2e2a7191fbd4bee044523aecbade5823a8664/src/util/splitAtTopLevelOnly.js
-function splitAtTopLevelOnly(input: string, separator: string): string[] {
- let stack: string[] = []
- let parts: string[] = []
- let lastPos = 0
+ // We don't use `compile()` so there's no overhead from PostCSS
+ let compiled = state.designSystem.candidatesToCss([className])
- for (let idx = 0; idx < input.length; idx++) {
- let char = input[idx]
+ // NOTE: This should never happen
+ if (compiled.length !== 1) return false
- if (stack.length === 0 && char === separator[0]) {
- if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) {
- parts.push(input.slice(lastPos, idx))
- lastPos = idx + separator.length
- }
+ return compiled[0] !== null
}
- if (char === '(' || char === '[' || char === '{') {
- stack.push(char)
- } else if (
- (char === ')' && stack[stack.length - 1] === '(') ||
- (char === ']' && stack[stack.length - 1] === '[') ||
- (char === '}' && stack[stack.length - 1] === '{')
- ) {
- stack.pop()
+ if (state.jit) {
+ if ((part.includes('[') && part.endsWith(']')) || part.includes('/')) {
+ return jit.generateRules(state, [className]).rules.length > 0
+ }
}
+
+ return false
}
- parts.push(input.slice(lastPos))
+ let offset = 0
+ let variants = new Set()
- return parts
+ for (let part of parts) {
+ if (!isValidVariant(part)) break
+
+ variants.add(part)
+ offset += part.length + state.separator!.length
+ }
+
+ return { variants: Array.from(variants), offset }
}
diff --git a/packages/tailwindcss-language-service/src/util/v4/design-system.ts b/packages/tailwindcss-language-service/src/util/v4/design-system.ts
index cce64d4b..3fb3c401 100644
--- a/packages/tailwindcss-language-service/src/util/v4/design-system.ts
+++ b/packages/tailwindcss-language-service/src/util/v4/design-system.ts
@@ -44,6 +44,6 @@ export interface DesignSystem {
export interface DesignSystem {
dependencies(): Set
- compile(classes: string[]): postcss.Root[]
+ compile(classes: string[]): (postcss.Root | null)[]
toCss(nodes: postcss.Root | postcss.Node[]): string
}
diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md
index dd3aa562..7b9e68fa 100644
--- a/packages/vscode-tailwindcss/CHANGELOG.md
+++ b/packages/vscode-tailwindcss/CHANGELOG.md
@@ -3,6 +3,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))
+- v4: Make sure completions show after variants using arbitrary and bare values ([#1263](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1263))
# 0.14.9