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 changelogmaster
parent
a13708b995
commit
2caebd1d48
|
@ -3,13 +3,11 @@ import * as cp from 'node:child_process'
|
|||
import * as rpc from 'vscode-jsonrpc'
|
||||
import { beforeAll } from 'vitest'
|
||||
|
||||
async function init(fixture) {
|
||||
let settings = {}
|
||||
let initPromise
|
||||
let childProcess
|
||||
let docSettings = new Map()
|
||||
|
||||
async function init(fixture) {
|
||||
childProcess = cp.fork('./bin/tailwindcss-language-server', { silent: true })
|
||||
let childProcess = cp.fork('./bin/tailwindcss-language-server', { silent: true })
|
||||
|
||||
const capabilities = {
|
||||
textDocument: {
|
||||
|
@ -116,7 +114,7 @@ async function init(fixture) {
|
|||
})
|
||||
})
|
||||
|
||||
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 @@ async function init(fixture) {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -119,3 +119,35 @@ withFixture('basic', (c) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
plugins: [
|
||||
function ({ addVariant, matchVariant }) {
|
||||
matchVariant('custom', (value) => `.custom:${value} &`, { values: { hover: 'hover' } })
|
||||
addVariant('custom-hover', `.custom:hover &:hover`)
|
||||
},
|
||||
],
|
||||
}
|
|
@ -138,6 +138,7 @@ export function completionsFromClassList(
|
|||
}
|
||||
|
||||
let items: CompletionItem[] = []
|
||||
let seenVariants = new Set<string>()
|
||||
|
||||
if (!important) {
|
||||
let variantOrder = 0
|
||||
|
@ -163,9 +164,16 @@ export function completionsFromClassList(
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
seenVariants.add(variant.name)
|
||||
|
||||
if (variant.isArbitrary) {
|
||||
items.push(
|
||||
|
@ -180,7 +188,7 @@ export function completionsFromClassList(
|
|||
// },
|
||||
})
|
||||
)
|
||||
} else if (!existingVariants.includes(variant.name)) {
|
||||
} else {
|
||||
let shouldSortVariants = !semver.gte(state.version, '2.99.0')
|
||||
let resultingVariants = [...existingVariants, variant.name]
|
||||
|
||||
|
@ -204,8 +212,7 @@ export function completionsFromClassList(
|
|||
? [
|
||||
{
|
||||
newText:
|
||||
resultingVariants.slice(0, resultingVariants.length - 1).join(sep) +
|
||||
sep,
|
||||
resultingVariants.slice(0, resultingVariants.length - 1).join(sep) + sep,
|
||||
range: {
|
||||
start: {
|
||||
...classListRange.start,
|
||||
|
@ -223,11 +230,18 @@ export function completionsFromClassList(
|
|||
)
|
||||
}
|
||||
|
||||
if (variant.values.length) {
|
||||
for (let value of variant.values ?? []) {
|
||||
if (existingVariants.includes(`${variant.name}-${value}`)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (seenVariants.has(`${variant.name}-${value}`)) {
|
||||
continue
|
||||
}
|
||||
|
||||
seenVariants.add(`${variant.name}-${value}`)
|
||||
|
||||
items.push(
|
||||
...variant.values
|
||||
.filter((value) => !existingVariants.includes(`${variant.name}-${value}`))
|
||||
.map((value) =>
|
||||
variantItem({
|
||||
label:
|
||||
value === 'DEFAULT'
|
||||
|
@ -236,12 +250,8 @@ export function completionsFromClassList(
|
|||
detail: variant.selectors({ value }).join(', '),
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return items
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.classList) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
## 0.11.x (Pre-Release)
|
||||
|
||||
- Add support for Glimmer (#867)
|
||||
- Ignore duplicate variant + value pairs (#874)
|
||||
|
||||
## 0.10.1
|
||||
|
||||
|
|
Loading…
Reference in New Issue