tailwind-ctp-intellisense @master -
refs -
log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
Remove duplicate `variant` + `value` pairs from completions (#874)
* Refactor
* Support using multiple fixtures in a single test file
* Add test
* Remove duplicate `variant` + `value` pairs from completions
* Update changelog
Signature
-----BEGIN PGP SIGNATURE-----
wsBcBAABCAAQBQJlO/bkCRBK7hj4Ov3rIwAA2roIAKryzkWS94Uf75mjpid7nOwq
jicSqaOCymoYyb77bTgjPMpV1jZtuUAa0PQB14tTBAp2yRedDbJUUoNZbTm7Tt3u
ARjMliJMpHWpW9MZuMd3Wmkr0MvPUMMKG+P/DKOBXt9/P7HAtwNKApLgHDdBMFpc
LQyKrSZqxEtGPHs9t89U8fvwy0Pchg51c5ZNi0dn13OBqRFfHe17DOFlvInG1y53
RMieqzA4z0YZ3cBOzb+p//PUM7xxaAi6tJRLm26PQYO3BLWa+OpejO8q5KB1VMJv
c5Z/gz6Bl3o64LYesV7iGvTGStsZjy9sJ+dV7wkNzfNCJj0DjrbPkhEWolQiOgI=
=AqiD
-----END PGP SIGNATURE-----
5 changed files, 133 additions(+), 99 deletions(-)
diff --git a/packages/tailwindcss-language-server/tests/common.js b/packages/tailwindcss-language-server/tests/common.js
index 7202e736a7d31cb032fa0295db23003b992b7b38..abdc8cca62304bd6df48451b22ec95bec81f4ae9 100644
--- a/packages/tailwindcss-language-server/tests/common.js
+++ b/packages/tailwindcss-language-server/tests/common.js
@@ -3,13 +3,11 @@ import * as cp from 'node:child_process'
import * as rpc from 'vscode-jsonrpc'
import { beforeAll } from 'vitest'
-let settings = {}
-let initPromise
-let childProcess
-let docSettings = new Map()
-
async function init(fixture) {
- childProcess = cp.fork('./bin/tailwindcss-language-server', { silent: true })
+ let settings = {}
+ let docSettings = new Map()
+
+ let childProcess = cp.fork('./bin/tailwindcss-language-server', { silent: true })
const capabilities = {
textDocument: {
@@ -116,7 +114,7 @@ return settings[item.section] ?? {}
})
})
- initPromise = new Promise((resolve) => {
+ let initPromise = new Promise((resolve) => {
connection.onRequest(new rpc.RequestType('client/registerCapability'), ({ registrations }) => {
if (registrations.findIndex((r) => r.method === 'textDocument/completion') > -1) {
resolve()
@@ -177,33 +175,18 @@ }
}
export function withFixture(fixture, callback) {
- let c
+ let c = {}
beforeAll(async () => {
- c = await init(fixture)
+ // Using the connection object as the prototype lets us access the connection
+ // without defining getters for all the methods and also lets us add helpers
+ // to the connection object without having to resort to using a Proxy
+ Object.setPrototypeOf(c, await init(fixture))
+
return () => c.connection.end()
})
- callback({
- get connection() {
- return c.connection
- },
- get sendRequest() {
- return c.sendRequest
- },
- get onNotification() {
- return c.onNotification
- },
- get openDocument() {
- return c.openDocument
- },
- get updateSettings() {
- return c.updateSettings
- },
- get updateFile() {
- return c.updateFile
- },
- })
+ callback(c)
}
// let counter = 0
diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js
index df64d38d3d4285aa53282b62302226b8406d93ca..996518a9c2f6227648ed6c606914ec84e2e1fbf8 100644
--- a/packages/tailwindcss-language-server/tests/completions/completions.test.js
+++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js
@@ -119,3 +119,35 @@ },
})
})
})
+
+withFixture('overrides-variants', (c) => {
+ async function completion({
+ lang,
+ text,
+ position,
+ context = {
+ triggerKind: 1,
+ },
+ settings,
+ }) {
+ let textDocument = await c.openDocument({ text, lang, settings })
+
+ return c.sendRequest('textDocument/completion', {
+ textDocument,
+ position,
+ context,
+ })
+ }
+
+ test.concurrent(
+ 'duplicate variant + value pairs do not produce multiple completions',
+ async () => {
+ let result = await completion({
+ text: '<div class="custom-hover"></div>',
+ position: { line: 0, character: 23 },
+ })
+
+ expect(result.items.filter((item) => item.label.endsWith('custom-hover:')).length).toBe(1)
+ }
+ )
+})
diff --git a/packages/tailwindcss-language-server/tests/fixtures/overrides-variants/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/overrides-variants/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..22e28cd6d6ec281c98876ae7988dbc2e4f7b20a2
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/overrides-variants/tailwind.config.js
@@ -0,0 +1,8 @@
+module.exports = {
+ plugins: [
+ function ({ addVariant, matchVariant }) {
+ matchVariant('custom', (value) => `.custom:${value} &`, { values: { hover: 'hover' } })
+ addVariant('custom-hover', `.custom:hover &:hover`)
+ },
+ ],
+}
diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts
index 62ab9e5abe501090663fe01f3aaf7b7fc9745f45..6468b93aa518ae13921f02cd032c5bc4127e1f75 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -138,6 +138,7 @@ replacementRange.start.character += 1
}
let items: CompletionItem[] = []
+ let seenVariants = new Set<string>()
if (!important) {
let variantOrder = 0
@@ -163,85 +164,94 @@ ...item,
}
}
- items.push(
- ...state.variants.flatMap((variant) => {
- let items: CompletionItem[] = []
+ for (let variant of state.variants) {
+ if (existingVariants.includes(variant.name)) {
+ continue
+ }
+
+ if (seenVariants.has(variant.name)) {
+ continue
+ }
- if (variant.isArbitrary) {
- items.push(
- variantItem({
- label: `${variant.name}${variant.hasDash ? '-' : ''}[]${sep}`,
- insertTextFormat: 2,
- textEditText: `${variant.name}${variant.hasDash ? '-' : ''}[\${1}]${sep}\${0}`,
- // command: {
- // title: '',
- // command: 'tailwindCSS.onInsertArbitraryVariantSnippet',
- // arguments: [variant.name, replacementRange],
- // },
- })
- )
- } else if (!existingVariants.includes(variant.name)) {
- let shouldSortVariants = !semver.gte(state.version, '2.99.0')
- let resultingVariants = [...existingVariants, variant.name]
+ seenVariants.add(variant.name)
- if (shouldSortVariants) {
- let allVariants = state.variants.map(({ name }) => name)
- resultingVariants = resultingVariants.sort(
- (a, b) => allVariants.indexOf(b) - allVariants.indexOf(a)
- )
- }
+ if (variant.isArbitrary) {
+ items.push(
+ variantItem({
+ label: `${variant.name}${variant.hasDash ? '-' : ''}[]${sep}`,
+ insertTextFormat: 2,
+ textEditText: `${variant.name}${variant.hasDash ? '-' : ''}[\${1}]${sep}\${0}`,
+ // command: {
+ // title: '',
+ // command: 'tailwindCSS.onInsertArbitraryVariantSnippet',
+ // arguments: [variant.name, replacementRange],
+ // },
+ })
+ )
+ } else {
+ let shouldSortVariants = !semver.gte(state.version, '2.99.0')
+ let resultingVariants = [...existingVariants, variant.name]
- items.push(
- variantItem({
- label: `${variant.name}${sep}`,
- detail: variant
- .selectors()
- .map((selector) => addPixelEquivalentsToMediaQuery(selector, rootFontSize))
- .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,
- },
+ if (shouldSortVariants) {
+ let allVariants = state.variants.map(({ name }) => name)
+ resultingVariants = resultingVariants.sort(
+ (a, b) => allVariants.indexOf(b) - allVariants.indexOf(a)
+ )
+ }
+
+ items.push(
+ variantItem({
+ label: `${variant.name}${sep}`,
+ detail: variant
+ .selectors()
+ .map((selector) => addPixelEquivalentsToMediaQuery(selector, rootFontSize))
+ .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,
},
},
- ]
- : [],
- })
- )
+ },
+ ]
+ : [],
+ })
+ )
+ }
+
+ for (let value of variant.values ?? []) {
+ if (existingVariants.includes(`${variant.name}-${value}`)) {
+ continue
}
- if (variant.values.length) {
- items.push(
- ...variant.values
- .filter((value) => !existingVariants.includes(`${variant.name}-${value}`))
- .map((value) =>
- variantItem({
- label:
- value === 'DEFAULT'
- ? `${variant.name}${sep}`
- : `${variant.name}${variant.hasDash ? '-' : ''}${value}${sep}`,
- detail: variant.selectors({ value }).join(', '),
- })
- )
- )
+ if (seenVariants.has(`${variant.name}-${value}`)) {
+ continue
}
- return items
- })
- )
+ seenVariants.add(`${variant.name}-${value}`)
+
+ items.push(
+ variantItem({
+ label:
+ value === 'DEFAULT'
+ ? `${variant.name}${sep}`
+ : `${variant.name}${variant.hasDash ? '-' : ''}${value}${sep}`,
+ detail: variant.selectors({ value }).join(', '),
+ })
+ )
+ }
+ }
}
if (state.classList) {
diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md
index 176d09b7a22a1ecbdfbdba233869f92abe248a0b..b5a9adb6a916b0aca4dfe927e95dbefbe6bd018a 100644
--- a/packages/vscode-tailwindcss/CHANGELOG.md
+++ b/packages/vscode-tailwindcss/CHANGELOG.md
@@ -3,6 +3,7 @@
## 0.11.x (Pre-Release)
- Add support for Glimmer (#867)
+- Ignore duplicate variant + value pairs (#874)
## 0.10.1