Home

tailwind-ctp-intellisense @master - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tree log patch
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-----
Jordan Pittman <jordan@cryptica.me>
1 year ago
5 changed files, 133 additions(+), 99 deletions(-)
M packages/tailwindcss-language-server/tests/common.jspackages/tailwindcss-language-server/tests/common.js
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
M packages/tailwindcss-language-server/tests/completions/completions.test.jspackages/tailwindcss-language-server/tests/completions/completions.test.js
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)
+    }
+  )
+})
Ipackages/tailwindcss-language-server/tests/fixtures/overrides-variants/tailwind.config.js
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`)
+    },
+  ],
+}
M packages/tailwindcss-language-service/src/completionProvider.tspackages/tailwindcss-language-service/src/completionProvider.ts
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) {
M packages/vscode-tailwindcss/CHANGELOG.mdpackages/vscode-tailwindcss/CHANGELOG.md
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