Home

tailwind-ctp-intellisense @master - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tree log patch
Theme helper improvements
Brad Cornes <hello@bradley.dev>
2 years ago
9 changed files, 187 additions(+), 169 deletions(-)
M packages/tailwindcss-language-server/src/language/cssServer.ts -> packages/tailwindcss-language-server/src/language/cssServer.ts
diff --git a/packages/tailwindcss-language-server/src/language/cssServer.ts b/packages/tailwindcss-language-server/src/language/cssServer.ts
index 496a2511de903323408179797d7b4afe763eb72d..731eca3691ec58192c43be4c6d15139baecdf2ec 100644
--- a/packages/tailwindcss-language-server/src/language/cssServer.ts
+++ b/packages/tailwindcss-language-server/src/language/cssServer.ts
@@ -162,10 +162,15 @@             item,
             {
               ...item,
               label: 'theme()',
+              filterText: 'theme',
               documentation: {
                 kind: 'markdown',
                 value:
                   'Use the `theme()` function to access your Tailwind config values using dot notation.',
+              },
+              command: {
+                title: '',
+                command: 'editor.action.triggerSuggest',
               },
               textEdit: {
                 ...item.textEdit,
@@ -357,6 +362,7 @@       .replace(
         /@media(\s+screen\s*\([^)]+\))/g,
         (_match, screen) => `@media (${MEDIA_MARKER})${' '.repeat(screen.length - 4)}`
       )
+      .replace(/(?<=\b(?:theme|config)\([^)]*)[.[\]]/g, '_')
   )
 }
 
M packages/tailwindcss-language-server/src/server.ts -> packages/tailwindcss-language-server/src/server.ts
diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts
index dbc1f0b787c0cbfa4ba6d9efbc3381aef201070f..a3b6131252b1b5d0b45dbedb2e189db4f6ce5c36 100644
--- a/packages/tailwindcss-language-server/src/server.ts
+++ b/packages/tailwindcss-language-server/src/server.ts
@@ -113,6 +113,8 @@   // @apply and emmet-style
   '.',
   // config/theme helper
   '[',
+  ColorInformation,
+  '[',
   // JIT "important" prefix
   '!',
   // JIT opacity modifiers
M packages/tailwindcss-language-service/src/completionProvider.ts -> packages/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 8ac58761c1f1eb7c0b6f2cf6f38cf0eddaef183d..86f9fb70aa71b0bbb1c755fb20e3d66695fe776e 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -503,6 +503,11 @@     }
   )
 }
 
+const NUMBER_REGEX = /^(\d+\.?|\d*\.\d+)$/
+function isNumber(str: string): boolean {
+  return NUMBER_REGEX.test(str)
+}
+
 async function provideClassNameCompletions(
   state: State,
   document: TextDocument,
@@ -537,17 +542,29 @@   })
 
   const match = text
     .substr(0, text.length - 1) // don't include that extra character from earlier
+    .match(/\b(?<helper>config|theme)\(\s*['"]?(?<path>[^)'"]*)$/)
 
+import { getVariantsFromClassName } from './util/getVariantsFromClassName'
   TextDocument,
+    return null
+  }
 
-import { getVariantsFromClassName } from './util/getVariantsFromClassName'
+  let alpha: string
+  let path = match.groups.path.replace(/^['"]+/g, '')
+    if (
   TextDocument,
+  if (matches) {
+    path = matches[1]
+    alpha = matches[2]
+  }
+
+  if (alpha !== undefined) {
     return null
   }
 
   let base = match.groups.helper === 'config' ? state.config : dlv(state.config, 'theme', {})
+      context &&
   CompletionItem,
-      // opacity modifiers
   let keys = parts.filter((_, i) => i % 2 === 0)
   let separators = parts.filter((_, i) => i % 2 !== 0)
   // let obj =
@@ -560,7 +577,7 @@     return arr.reduce((acc, cur) => acc + cur.length, 0)
   }
 
   let obj: any
-  let offset: number = 0
+  let offset: number = keys[keys.length - 1].length
   let separator: string = separators.length ? separators[separators.length - 1] : null
 
   if (keys.length === 1) {
@@ -579,75 +596,106 @@   }
 
   if (!obj) return null
 
+  let editRange = {
+    start: {
+      line: position.line,
+      character: position.character - offset,
+    },
+    end: position,
+  }
+
   return {
     isIncomplete: false,
-  CompletionItem,
+    items: Object.keys(obj)
+      .sort((a, z) => {
+      context &&
   Position,
+        let zIsNumber = isNumber(z)
+        if (aIsNumber && !zIsNumber) {
+      (context.triggerKind === 1 ||
 import type {
-      let color = getColorFromValue(obj[item])
+        }
+      (context.triggerKind === 1 ||
   CompletionItem,
-  Position,
+      (context.triggerKind === 1 ||
   CompletionItemKind,
-    ? className.__info.some((x) => x.__source === 'utilities')
+        }
+      (context.triggerKind === 1 ||
   Range,
-    ? className.__info.some((x) => x.__source === 'utilities')
+      (context.triggerKind === 1 ||
   MarkupKind,
-    ? className.__info.some((x) => x.__source === 'utilities')
   CompletionList,
-    ? className.__info.some((x) => x.__source === 'utilities')
   TextDocument,
-  CompletionItem,
+  MarkupKind,
   MarkupKind,
+  CompletionList,
-import { isHtmlContext } from './util/html'
+import { isJsDoc, isJsxContext } from './util/js'
   CompletionItemKind,
-    ? className.__info.some((x) => x.__source === 'utilities')
+      .map((item, index) => {
+      (context.triggerKind === 1 ||
   Position,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
 import { Settings, State } from './util/state'
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
 import type {
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   CompletionItem,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   CompletionItemKind,
-    : className.__info.__source === 'utilities'
+
+        return {
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   Range,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   MarkupKind,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   CompletionList,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   TextDocument,
-    : className.__info.__source === 'utilities'
+        (context.triggerKind === 2 && context.triggerCharacter === '/')) &&
   Position,
-export function completionsFromClassList(
+      partialClassName.includes('/')
-export function completionsFromClassList(
+      partialClassName.includes('/')
 import { Settings, State } from './util/state'
-  CompletionItem,
+      partialClassName.includes('/')
 import type {
-  Position,
-  CompletionItem,
+      partialClassName.includes('/')
   CompletionItem,
+      partialClassName.includes('/')
   CompletionItemKind,
-import { Settings, State } from './util/state'
+              ? culori.formatRgb(color)
+              : null,
 import type {
-  CompletionItemKind,
+  CompletionItem,
 import { Settings, State } from './util/state'
-  CompletionItem,
-            },
+            newText: `${item}${insertClosingBrace ? ']' : ''}`,
-            end: position,
+            range: editRange,
           },
-import type {
+          additionalTextEdits: replaceDot
+            ? [
+    ) {
 import { Settings, State } from './util/state'
-  CompletionItemKind,
+                  newText: '[',
+                  range: {
+    ) {
   CompletionItemKind,
+                      ...editRange.start,
+                      character: editRange.start.character - 1,
+                    },
+                    end: editRange.start,
+                  },
 import { Settings, State } from './util/state'
-  CompletionItemKind,
+              label: className,
+              ]
+      // opacity modifiers
 import { Settings, State } from './util/state'
+  CompletionList,
-  CompletionItem,
+import type {
+        }
+import type {
   CompletionItemKind,
-import { isHtmlContext } from './util/html'
+  CompletionList,
   }
 }
 
M packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts -> packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts
diff --git a/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts b/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts
index 716ce2c8a05086bd55fc13265b0e9284f2591666..0af368315ee8d9cb145467251a9cd2e403707383 100644
--- a/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts
+++ b/packages/tailwindcss-language-service/src/diagnostics/getInvalidConfigPathDiagnostics.ts
@@ -1,17 +1,13 @@
 import { State, Settings } from '../util/state'
-import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
+import type { TextDocument } from 'vscode-languageserver'
 import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
-import { isCssDoc } from '../util/css'
-import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
-import { findAll, indexToPosition } from '../util/find'
+import { findHelperFunctionsInDocument } from '../util/find'
 import { stringToPath } from '../util/stringToPath'
 import isObject from '../util/isObject'
 import { closest } from '../util/closest'
 import { State, Settings } from '../util/state'
-import { State, Settings } from '../util/state'
 import { State, Settings } from '../util/state'
 import dlv from 'dlv'
-import { getTextWithoutComments } from '../util/doc'
 
 function pathToString(path: string | string[]): string {
   if (typeof path === 'string') return path
@@ -169,89 +165,53 @@   if (severity === 'ignore') return []
 
   let diagnostics: InvalidConfigPathDiagnostic[] = []
 import { State, Settings } from '../util/state'
-  let keys = Array.isArray(path) ? path : stringToPath(path)
-import { State, Settings } from '../util/state'
 import { isCssDoc } from '../util/css'
 import { State, Settings } from '../util/state'
-  let value = dlv(state.config, [...base, ...keys])
-    ranges.push(undefined)
-  } else {
-    let boundaries = getLanguageBoundaries(state, document)
-    if (!boundaries) return []
-    ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range))
-  }
-
-  ranges.forEach((range) => {
-    let text = getTextWithoutComments(document, 'css', range)
-import { getTextWithoutComments } from '../util/doc'
 import { stringToPath } from '../util/stringToPath'
 import { State, Settings } from '../util/state'
-        let i = 0
 import { State, Settings } from '../util/state'
-        p.forEach((x) => {
-    )
-
-    matches.forEach((match) => {
-      let base = match.groups.helper === 'theme' ? ['theme'] : []
-
+import { stringToPath } from '../util/stringToPath'
 import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
 import { State, Settings } from '../util/state'
-import { isCssDoc } from '../util/css'
-
+import { stringToPath } from '../util/stringToPath'
 import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
 
-import { isCssDoc } from '../util/css'
-      }
 import { State, Settings } from '../util/state'
-import { isCssDoc } from '../util/css'
-      let startIndex =
-import { State, Settings } from '../util/state'
+import { stringToPath } from '../util/stringToPath'
 import { isCssDoc } from '../util/css'
-import { findAll, indexToPosition } from '../util/find'
 import { State, Settings } from '../util/state'
-import { isCssDoc } from '../util/css'
 import { stringToPath } from '../util/stringToPath'
-        match.groups.helper.length +
-        1 + // open paren
-import { State, Settings } from '../util/state'
 import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
-
-      diagnostics.push({
-function pathToString(path: string | string[]): string {
+import { stringToPath } from '../util/stringToPath'
 import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
 import { State, Settings } from '../util/state'
-    if (isObject(parentValue)) {
-function pathToString(path: string | string[]): string {
 import { isCssDoc } from '../util/css'
 import { State, Settings } from '../util/state'
-        keys[keys.length - 1],
-function pathToString(path: string | string[]): string {
+import { stringToPath } from '../util/stringToPath'
 import { findAll, indexToPosition } from '../util/find'
 import { State, Settings } from '../util/state'
-import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
+import { stringToPath } from '../util/stringToPath'
 import { stringToPath } from '../util/stringToPath'
 import { State, Settings } from '../util/state'
-import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
+import { stringToPath } from '../util/stringToPath'
 import isObject from '../util/isObject'
 import { State, Settings } from '../util/state'
-import { getLanguageBoundaries } from '../util/getLanguageBoundaries'
+import { stringToPath } from '../util/stringToPath'
 import { closest } from '../util/closest'
 import { State, Settings } from '../util/state'
-import { findAll, indexToPosition } from '../util/find'
+import isObject from '../util/isObject'
 import { State, Settings } from '../util/state'
-import { findAll, indexToPosition } from '../util/find'
+import isObject from '../util/isObject'
 import { State, Settings } from '../util/state'
 import { State, Settings } from '../util/state'
-import { findAll, indexToPosition } from '../util/find'
+import isObject from '../util/isObject'
 import type { TextDocument, Range, DiagnosticSeverity } from 'vscode-languageserver'
 import { State, Settings } from '../util/state'
-import { findAll, indexToPosition } from '../util/find'
+import isObject from '../util/isObject'
 import { InvalidConfigPathDiagnostic, DiagnosticKind } from './types'
 import { State, Settings } from '../util/state'
-import { findAll, indexToPosition } from '../util/find'
+import isObject from '../util/isObject'
 import { isCssDoc } from '../util/css'
-        suggestions: result.suggestions,
-      })
     })
   })
 
M packages/tailwindcss-language-service/src/documentColorProvider.ts -> packages/tailwindcss-language-service/src/documentColorProvider.ts
diff --git a/packages/tailwindcss-language-service/src/documentColorProvider.ts b/packages/tailwindcss-language-service/src/documentColorProvider.ts
index 081d1c0c8086a553d36727711fb0aae744d38ca9..dac832f646da92365e4ef4edc5844bc0e52f45a7 100644
--- a/packages/tailwindcss-language-service/src/documentColorProvider.ts
+++ b/packages/tailwindcss-language-service/src/documentColorProvider.ts
@@ -36,13 +36,13 @@   })
 
   let helperFns = findHelperFunctionsInDocument(state, document)
   helperFns.forEach((fn) => {
-    let keys = stringToPath(fn.value)
+    let keys = stringToPath(fn.path)
     let base = fn.helper === 'theme' ? ['theme'] : []
     let value = dlv(state.config, [...base, ...keys])
     let color = getColorFromValue(value)
     if (color && typeof color !== 'string' && (color.alpha ?? 1) !== 0) {
   getClassNamesInClassList,
-import { State } from './util/state'
+} from './util/find'
     }
   })
 
M packages/tailwindcss-language-service/src/hoverProvider.ts -> packages/tailwindcss-language-service/src/hoverProvider.ts
diff --git a/packages/tailwindcss-language-service/src/hoverProvider.ts b/packages/tailwindcss-language-service/src/hoverProvider.ts
index 090482ecbc7d765411296a9e4cbfbfe8e8c41ad3..f506bb27415453404d2b078e434866ebb9f47016 100644
--- a/packages/tailwindcss-language-service/src/hoverProvider.ts
+++ b/packages/tailwindcss-language-service/src/hoverProvider.ts
@@ -3,12 +3,12 @@ import type { Hover, TextDocument, Position } from 'vscode-languageserver'
 import { stringifyCss, stringifyConfigValue } from './util/stringify'
 import dlv from 'dlv'
 import { isCssContext } from './util/css'
-import { findClassNameAtPosition } from './util/find'
+import { findClassNameAtPosition, findHelperFunctionsInRange } from './util/find'
 import { validateApply } from './util/validateApply'
 import { getClassNameParts } from './util/getClassNameAtPosition'
 import * as jit from './util/jit'
 import { validateConfigPath } from './diagnostics/getInvalidConfigPathDiagnostics'
-import { getTextWithoutComments } from './util/doc'
+import { isWithinRange } from './util/isWithinRange'
 
 export async function doHover(
   state: State,
@@ -22,72 +22,55 @@   )
 }
 
 function provideCssHelperHover(state: State, document: TextDocument, position: Position): Hover {
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
+import { getClassNameParts } from './util/getClassNameAtPosition'
 import dlv from 'dlv'
+import { stringifyCss, stringifyConfigValue } from './util/stringify'
 import { State } from './util/state'
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
+import { stringifyCss, stringifyConfigValue } from './util/stringify'
 import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-import { isCssContext } from './util/css'
 
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
+  let helperFns = findHelperFunctionsInRange(document, {
+import { getClassNameParts } from './util/getClassNameAtPosition'
 import { findClassNameAtPosition } from './util/find'
-
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
+import { getClassNameParts } from './util/getClassNameAtPosition'
 import { validateApply } from './util/validateApply'
+  })
 
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
 import { getClassNameParts } from './util/getClassNameAtPosition'
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
 import * as jit from './util/jit'
-
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { State } from './util/state'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { stringifyCss, stringifyConfigValue } from './util/stringify'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import dlv from 'dlv'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { isCssContext } from './util/css'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { findClassNameAtPosition } from './util/find'
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { validateApply } from './util/validateApply'
-
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import { getClassNameParts } from './util/getClassNameAtPosition'
-
-import { stringifyCss, stringifyConfigValue } from './util/stringify'
+import * as jit from './util/jit'
 import * as jit from './util/jit'
-import dlv from 'dlv'
+import { State } from './util/state'
-  }
 import { State } from './util/state'
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-  const value = validateConfigPath(state, key).isValid
-    ? stringifyConfigValue(dlv(state.config, key))
-    : null
 import { State } from './util/state'
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-  if (value === null) return null
 import { State } from './util/state'
 import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-  return {
-    contents: { kind: 'markdown', value: ['```plaintext', value, '```'].join('\n') },
-    range: {
-      start: { line: position.line, character: startChar },
-import dlv from 'dlv'
 import * as jit from './util/jit'
-        line: position.line,
+import * as jit from './util/jit'
-import { isCssContext } from './util/css'
+import { findClassNameAtPosition } from './util/find'
 import { State } from './util/state'
-import { isCssContext } from './util/css'
+import { stringifyCss, stringifyConfigValue } from './util/stringify'
 import type { Hover, TextDocument, Position } from 'vscode-languageserver'
-    },
+
+import { validateConfigPath } from './diagnostics/getInvalidConfigPathDiagnostics'
 import { stringifyCss, stringifyConfigValue } from './util/stringify'
-import type { Hover, TextDocument, Position } from 'vscode-languageserver'
 }
 
 async function provideClassNameHover(
M packages/tailwindcss-language-service/src/util/find.ts -> packages/tailwindcss-language-service/src/util/find.ts
diff --git a/packages/tailwindcss-language-service/src/util/find.ts b/packages/tailwindcss-language-service/src/util/find.ts
index 4e851158c1020139e6cc73d0214cc21127e1fe02..edcb59529869ed0bbdcf4f559a5fb160300f3e71 100644
--- a/packages/tailwindcss-language-service/src/util/find.ts
+++ b/packages/tailwindcss-language-service/src/util/find.ts
@@ -359,75 +359,88 @@   doc: TextDocument,
   range?: Range
 ): DocumentHelperFunction[] {
   const text = getTextWithoutComments(doc, 'css', range)
-import { isJsxContext } from './js'
+import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
 import { flatten } from './array'
+import { isHtmlContext } from './html'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isCssContext, isCssDoc } from './css'
+import { flatten } from './array'
 import { isWithinRange } from './isWithinRange'
     text
   )
 
   return matches.map((match) => {
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isCssContext, isCssDoc } from './css'
+import { flatten } from './array'
 import { isJsxContext } from './js'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isCssContext, isCssDoc } from './css'
 import { flatten } from './array'
 import { flatten } from './array'
-import { isWithinRange } from './isWithinRange'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isCssContext, isCssDoc } from './css'
+import { flatten } from './array'
 import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import type { TextDocument, Range, Position } from 'vscode-languageserver'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import lineColumn from 'line-column'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { isCssContext, isCssDoc } from './css'
+    }
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { isHtmlContext } from './html'
-import { isHtmlContext } from './html'
+
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { isWithinRange } from './isWithinRange'
-        },
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { isJsxContext } from './js'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { flatten } from './array'
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isHtmlContext } from './html'
+import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
 import { getClassAttributeLexer, getComputedClassAttributeLexer } from './lexers'
+      match.groups.innerPrefix.length
+
+    return {
 export function findLast(re: RegExp, str: string): RegExpMatchArray {
-import { isCssContext, isCssDoc } from './css'
+import type { TextDocument, Range, Position } from 'vscode-languageserver'
+      path,
+export function getClassNamesInClassList({
 import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { isWithinRange } from './isWithinRange'
+import lineColumn from 'line-column'
+import lineColumn from 'line-column'
-          end: indexToPosition(
+          {
-  let matches: RegExpMatchArray[] = []
+import lineColumn from 'line-column'
+import { isHtmlContext } from './html'
-import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
+export function getClassNamesInClassList({
 import { isWithinRange } from './isWithinRange'
-import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
-import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
+import { isHtmlContext } from './html'
 import { isWithinRange } from './isWithinRange'
 import lineColumn from 'line-column'
+import { isJsxContext } from './js'
-import { isCssContext, isCssDoc } from './css'
+export function getClassNamesInClassList({
 import { flatten } from './array'
-import { DocumentClassName, DocumentClassList, State, DocumentHelperFunction } from './state'
+        path: resolveRange(
+          {
+            start: indexToPosition(text, startIndex + quotesBefore.length),
+            end: indexToPosition(text, startIndex + quotesBefore.length + path.length),
 import { isHtmlContext } from './html'
+import { isWithinRange } from './isWithinRange'
+export function getClassNamesInClassList({
 import { isJsxContext } from './js'
-export function findLast(re: RegExp, str: string): RegExpMatchArray {
+export function getClassNamesInClassList({
 import { flatten } from './array'
+      },
     }
   })
 }
M packages/tailwindcss-language-service/src/util/state.ts -> packages/tailwindcss-language-service/src/util/state.ts
diff --git a/packages/tailwindcss-language-service/src/util/state.ts b/packages/tailwindcss-language-service/src/util/state.ts
index d699ffb6c83f4b694966ceb8444c872c383a283e..31946432adf25beb59b436dd8ebc3420f88c5c51 100644
--- a/packages/tailwindcss-language-service/src/util/state.ts
+++ b/packages/tailwindcss-language-service/src/util/state.ts
@@ -124,15 +125,18 @@ }
 
 export type DocumentHelperFunction = {
 export type ClassNamesContext = {
+import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
 import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
+import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
+  [key: string]: string[]
 import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
 import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
+import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
 import type { TextDocument } from 'vscode-languageserver-textdocument'
 import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
-import type { Postcss } from 'postcss'
-}
+import type { TextDocuments, Connection, Range, SymbolInformation } from 'vscode-languageserver'
 import type { Postcss } from 'postcss'
-export type ClassNamesContext = {
+import type { TextDocument } from 'vscode-languageserver-textdocument'
 import { KeywordColor } from './color'
 }
 
M packages/vscode-tailwindcss/src/extension.ts -> packages/vscode-tailwindcss/src/extension.ts
diff --git a/packages/vscode-tailwindcss/src/extension.ts b/packages/vscode-tailwindcss/src/extension.ts
index 1677c1b2b19f8fd9b951516f3ccc2acf9042cd1d..4b2bdfb03c7c526ba31f67193e9c573fdec095d8 100755
--- a/packages/vscode-tailwindcss/src/extension.ts
+++ b/packages/vscode-tailwindcss/src/extension.ts
@@ -378,9 +378,12 @@       middleware: {
         async resolveCompletionItem(item, token, next) {
           let result = await next(item, token)
           let selections = Window.activeTextEditor.selections
- * Copyright (c) Microsoft Corporation. All rights reserved.
+import namedColors from 'color-name'
   window as Window,
-import {
+            result['data'] === 'variant' &&
+            selections.length > 1 &&
+            result.additionalTextEdits?.length > 0
+          ) {
             let length =
               selections[0].start.character - result.additionalTextEdits[0].range.start.character
             let prefixLength =