Home

tailwind-ctp-intellisense @master - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tree log patch
Adopt `getVariants` API
Brad Cornes <hello@bradley.dev>
2 years ago
6 changed files, 316 additions(+), 129 deletions(-)
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 d98ab34cbba69391205ffaf7f6be1f5b49e83546..008c221a7744fb579ca9a8887c75c87a9916755c 100644
--- a/packages/tailwindcss-language-server/src/server.ts
+++ b/packages/tailwindcss-language-server/src/server.ts
@@ -63,6 +63,7 @@   State,
   FeatureFlags,
   Settings,
   ClassNames,
+  Variant,
 } from 'tailwindcss-language-service/src/util/state'
 import {
   provideDiagnostics,
@@ -1181,185 +1182,209 @@ function isAtRule(node: Node): node is AtRule {
   return node.type === 'atrule'
 }
 
-import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
+  '(',
 import './lib/env'
-import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
+  '(',
 import {
-import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
+  '(',
   CompletionItem,
-  DocumentColorParams,
+import './lib/env'
   CompletionItem,
-  CompletionList,
+import {
   DocumentColorParams,
-import { URI } from 'vscode-uri'
+  createConnection,
 import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri'
-  Connection,
+import {
 import './lib/env'
-
-    let result = {}
+  for (let i = 0; i < options.length; i++) {
     // [name, [sort, fn]]
     // [name, [[sort, fn]]]
     Array.from(state.jitContext.variantMap as Map<string, [any, any]>).forEach(
       ([variantName, variantFnOrFns]) => {
-        let fns = (Array.isArray(variantFnOrFns[0]) ? variantFnOrFns : [variantFnOrFns]).map(
-          ([_sort, fn]) => fn
+  Hover,
 import resolveFrom, { setPnpApi } from './util/resolveFrom'
-  DocumentColorParams,
-
-        let placeholder = '__variant_placeholder__'
-
-        let root = state.modules.postcss.module.root({
-  DocumentColorParams,
+  Hover,
 import { AtRule, Container, Node, Result } from 'postcss'
-  DocumentColorParams,
+  Hover,
 import Module from 'module'
-  DocumentColorParams,
+  Hover,
 import Hook from './lib/hook'
-  DocumentColorParams,
+  Hover,
 import * as semver from 'tailwindcss-language-service/src/util/semver'
-  DocumentColorParams,
+  Hover,
 import dlv from 'dlv'
-  DocumentColorParams,
+  Hover,
 import { dset } from 'dset'
-        })
-
-  DocumentColorParams,
+  Hover,
 import pkgUp from 'pkg-up'
-  DocumentColorParams,
+  Hover,
 import stackTrace from 'stack-trace'
-        })
-
-  DocumentColorParams,
+  Hover,
 import extractClassNames from './lib/extractClassNames'
-  DocumentColorParams,
   CompletionParams,
-  CompletionParams,
-        }
+  ClassNames,
 
-  DocumentColorParams,
+            let fns = (Array.isArray(variantFnOrFns[0]) ? variantFnOrFns : [variantFnOrFns]).map(
+  Hover,
 import { doHover } from 'tailwindcss-language-service/src/hoverProvider'
-  DocumentColorParams,
+  Hover,
   doComplete,
   DocumentColorParams,
+  createConnection,
+  Hover,
   resolveCompletionItem,
   DocumentColorParams,
+  createConnection,
+  Hover,
 } from 'tailwindcss-language-service/src/completionProvider'
-            }
-
-  DocumentColorParams,
+  Hover,
   State,
-  DocumentColorParams,
+  Hover,
   FeatureFlags,
-  DocumentColorParams,
+  Hover,
   Settings,
-  DocumentColorParams,
+  Hover,
   ClassNames,
-  DocumentColorParams,
+  Hover,
 } from 'tailwindcss-language-service/src/util/state'
-  DocumentColorParams,
+  Hover,
   provideDiagnostics,
-              })
             })
-  CompletionParams,
+
+  Hover,
   Connection,
-  CompletionList,
+  Connection,
-  DocumentColorParams,
+  Hover,
   clearAllDiagnostics,
 import {
-import assert from 'assert'
+import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
 
-  DocumentColorParams,
+  Hover,
 } from './lsp/diagnosticsProvider'
-
-  DocumentColorParams,
+  Hover,
 import { doCodeActions } from 'tailwindcss-language-service/src/codeActions/codeActionProvider'
+            }
 
+  '!',
-  DocumentColorParams,
+  Hover,
 import { getDocumentLinks } from 'tailwindcss-language-service/src/documentLinksProvider'
-  DocumentColorParams,
+  Hover,
 import { debounce } from 'debounce'
-  DocumentColorParams,
+  Hover,
 import { getModuleDependencies } from './util/getModuleDependencies'
+                }
 
+  '!',
   CompletionList,
-  DocumentColorParams,
+  Hover,
 // import postcssLoadConfig from 'postcss-load-config'
-  DocumentColorParams,
+  Hover,
 import * as parcel from './watcher/index.js'
-  DocumentColorParams,
+  Hover,
 import { generateRules } from 'tailwindcss-language-service/src/util/jit'
-  CompletionParams,
 import './lib/env'
-  DocumentColorParams,
+import './lib/env'
 import { getColor } from 'tailwindcss-language-service/src/util/color'
-  DocumentColorParams,
+  Hover,
 import * as culori from 'culori'
-  DocumentColorParams,
+  Hover,
 import namedColors from 'color-name'
+  CompletionParams,
   Connection,
-} from 'vscode-languageserver/node'
+              })
-  CompletionParams,
+  // JIT opacity modifiers
 import './lib/env'
 import { doHover } from 'tailwindcss-language-service/src/hoverProvider'
-  CompletionList,
+  CompletionItem,
 
+  Hover,
   DocumentColorParams,
+import {
   DocumentColorParams,
+  createConnection,
 import './lib/env'
+  projectConfig: ProjectConfig,
+  Hover,
   DocumentColorParams,
+  CompletionList,
+  Hover,
   DocumentColorParams,
-import {
+  CompletionParams,
-import type * as chokidar from 'chokidar'
+import './lib/env'
 import './lib/env'
+import merge from 'deepmerge'
+  Hover,
 
+  Hover,
 // @ts-ignore
-  CompletionItem,
+  Hover,
   DocumentColorParams,
+  ColorInformation,
+                format: (def: string) => {
+                  definition = def.replace(/:merge\(([^)]+)\)/g, '$1')
   DocumentColorParams,
+  Connection,
   CompletionList,
-            continue
+                wrap: (rule: Container) => {
+                  if (isAtRule(rule)) {
+  '/',
   CompletionList,
-import {
+import './lib/env'
 import './lib/env'
+    require('fs').readFileSync = function (filename, ...args) {
   DocumentColorParams,
-  createConnection,
+} from 'tailwindcss-language-service/src/util/state'
   DocumentColorParams,
-  DocumentColorParams,
+  Connection,
   Connection,
-  DocumentColorParams,
 
-  CompletionParams,
+  '/',
   Connection,
-  CompletionList,
-  DocumentColorParams,
+  '/',
   createConnection,
-          definition = container
+              }
   DocumentColorParams,
-  DocumentColorParams,
+  createConnection,
+  Hover,
   ColorInformation,
+  DocumentColorParams,
-  DocumentColorParams,
+  Hover,
   ColorInformation,
+  ColorInformation,
+] as const
+              }
   DocumentColorParams,
-  ColorInformation,
+  createConnection,
+] as const
 import './lib/env'
-global.__preflight = preflight
+] as const
 import {
   DocumentColorParams,
-  `
+  updateAllDiagnostics,
 
-          if (!definition.includes(placeholder)) {
+              definition = container
-// @ts-ignore
+] as const
   CompletionList,
-  CompletionList,
+import './lib/env'
 import {
+  CompletionParams,
 import './lib/env'
+        editor: { tabSize: 2 },
+import './lib/env'
 import {
   createConnection,
-  CompletionList,
+                .trim()
 
-  DocumentColorParams,
+              if (!definition.includes(placeholder)) {
+  '/',
   ColorInformation,
+              }
   CompletionParams,
+  ClassNames,
+
+            return definitions
+          },
+        })
       }
     )
 
@@ -1390,8 +1415,14 @@       },
     })
   })
 
-  ColorInformation,
+  return variants.map((variant) => ({
+    name: variant,
+    values: [],
+    isArbitrary: false,
+  InitializeParams,
   TextDocuments,
+    selectors: () => [],
+  }))
 }
 
 async function getPlugins(config: any) {
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 941554f165372cf461f94d82d5f1a7f4aa9f6c4c..adacd136a9a752e0df6731784e1a5fbf05345fd8 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -1,4 +1,4 @@
-import { Settings, State } from './util/state'
+import { Settings, State, Variant } from './util/state'
 import type {
   CompletionItem,
   CompletionItemKind,
@@ -111,8 +111,6 @@       }
     }
 
   CompletionContext,
-  Range,
-  CompletionContext,
   MarkupKind,
 
     replacementRange.start.character += offset
@@ -125,107 +123,180 @@
     let items: CompletionItem[] = []
 
     if (!important) {
-} from 'vscode-languageserver'
+      // opacity modifiers
   CompletionItem,
 
-} from 'vscode-languageserver'
+      // opacity modifiers
   CompletionItemKind,
-} from 'vscode-languageserver'
+      // opacity modifiers
   Range,
+          textEdit?: { newText: string; range?: Range }
+        }
+      ): CompletionItem {
+        return {
+          kind: 9,
+          data: 'variant',
+          command:
+  CompletionList,
 import { Settings, State } from './util/state'
-import { isCssContext } from './util/css'
+  CompletionList,
 } from 'vscode-languageserver'
   CompletionList,
+import dlv from 'dlv'
+  CompletionList,
 import { Settings, State } from './util/state'
+  CompletionItem,
+  CompletionList,
 import { Settings, State } from './util/state'
-  TextDocument,
+  CompletionItemKind,
+import { stringifyScreen, Screen } from './util/screens'
   CompletionItem,
-  MarkupKind,
+  CompletionList,
 import { Settings, State } from './util/state'
-import { stringifyScreen, Screen } from './util/screens'
+  Range,
+  CompletionList,
 import { Settings, State } from './util/state'
+  MarkupKind,
 import type {
+import { remToPx } from './util/remToPx'
+  CompletionList,
 import { Settings, State } from './util/state'
+  CompletionList,
 import type {
+import { getVariantsFromClassName } from './util/getVariantsFromClassName'
+  CompletionList,
 import { Settings, State } from './util/state'
+  TextDocument,
-import { Settings, State } from './util/state'
 import { isValidLocationForEmmetAbbreviation } from './util/isValidLocationForEmmetAbbreviation'
+  TextDocument,
-  Position,
+        }
 import { Settings, State } from './util/state'
+  CompletionItem,
 
+      items.push(
+      let beforeSlash = partialClassName.split('/').slice(0, -1).join('/')
   Position,
+  CompletionList,
 import type {
+
+      let testClass = beforeSlash + '/[0]'
 import { Settings, State } from './util/state'
+            items.push(
+  CompletionList,
 import { isJsDoc, isJsxContext } from './util/js'
-import { Settings, State } from './util/state'
+  CompletionList,
 import { naturalExpand } from './util/naturalExpand'
-import { Settings, State } from './util/state'
+  CompletionList,
 import * as semver from './util/semver'
 import { Settings, State } from './util/state'
+              }
+  CompletionList,
 import { docsUrl } from './util/docsUrl'
 import { Settings, State } from './util/state'
+              label: className,
+  CompletionList,
 import { ensureArray } from './util/array'
-import { Settings, State } from './util/state'
+  CompletionList,
 import { getClassAttributeLexer, getComputedClassAttributeLexer } from './util/lexers'
-import { Settings, State } from './util/state'
+  CompletionList,
 import { validateApply } from './util/validateApply'
-import { Settings, State } from './util/state'
+      let { rules } = jit.generateRules(state, [testClass])
+      let { rules } = jit.generateRules(state, [testClass])
 import { Settings, State } from './util/state'
-import { Settings, State } from './util/state'
+              })
+            )
+          } else if (!existingVariants.includes(variant.name)) {
+  CompletionList,
   CompletionItem,
+  Range,
+            let resultingVariants = [...existingVariants, variant.name]
+
+} from 'vscode-languageserver'
   Position,
-  TextDocument,
-import { Settings, State } from './util/state'
+  CompletionList,
   CompletionItem,
-import { Settings, State } from './util/state'
+  CompletionList,
 import { Settings, State } from './util/state'
+import type {
 import { Settings, State } from './util/state'
+import type {
 import { Settings, State } from './util/state'
 import { Settings, State } from './util/state'
-  CompletionItem,
+import type {
 import type {
+  Position,
 import { Settings, State } from './util/state'
-import { getVariantsFromClassName } from './util/getVariantsFromClassName'
-import { Settings, State } from './util/state'
   CompletionItem,
-  CompletionItemKind,
+  MarkupKind,
-                      {
+            items.push(
-import { Settings, State } from './util/state'
+      let testClass = beforeSlash + '/[0]'
   CompletionItem,
-  MarkupKind,
-import removeMeta from './util/removeMeta'
   CompletionList,
-import { Settings, State } from './util/state'
   Array.isArray(className.__info)
-import { Settings, State } from './util/state'
+  CompletionList,
     ? className.__info.some((x) => x.__source === 'utilities')
 import { Settings, State } from './util/state'
+              }
+  CompletionList,
     : className.__info.__source === 'utilities'
 import { Settings, State } from './util/state'
+              label: className,
+  CompletionList,
 export function completionsFromClassList(
-import { Settings, State } from './util/state'
+  CompletionList,
   state: State,
-import { Settings, State } from './util/state'
+  CompletionList,
   classList: string,
-import { Settings, State } from './util/state'
+      if (rules.length > 0) {
   CompletionItemKind,
+  CompletionList,
   CompletionItemKind,
+  Range,
+                            resultingVariants.slice(0, resultingVariants.length - 1).join(sep) +
+                            sep,
+                          range: {
+                            start: {
+                              ...classListRange.start,
+        let opacities = dlv(state.config, 'theme.opacity', {})
 import { Settings, State } from './util/state'
+                            },
+                            end: {
+        let opacities = dlv(state.config, 'theme.opacity', {})
   CompletionItemKind,
+        let opacities = dlv(state.config, 'theme.opacity', {})
   Range,
+                            },
                           },
                         },
-import { getColor, getColorFromValue } from './util/color'
   CompletionList,
+  let replacementRange = {
-                    ]
+                    : [],
+              })
+            )
 import { Settings, State } from './util/state'
-  CompletionItemKind,
+  Position,
   Position,
-import { Settings, State } from './util/state'
+
+  CompletionList,
   Range,
+  TextDocument,
+            items.push(
+              ...variant.values
+        if (!isObject(opacities)) {
+        if (!isObject(opacities)) {
 import { Settings, State } from './util/state'
+                  variantItem({
+                    label: `${variant.name}${variant.hasDash ? '-' : ''}${value}${sep}`,
+                    detail: variant.selectors({ value }).join(', '),
+        if (!isObject(opacities)) {
   Range,
+                )
+            )
 import { Settings, State } from './util/state'
+                newText: className,
+
+          return items
+        })
       )
     }
 
@@ -840,9 +912,14 @@   const parts = match.groups.partial.split(/\s*,\s*/)
 
   if (/\s+/.test(parts[parts.length - 1])) return null
 
-  CompletionItemKind,
+  let possibleVariants = state.variants.flatMap((variant) => {
+        if (!isObject(opacities)) {
   Position,
+  CompletionList,
   CompletionList,
+    }
+    return [variant.name]
+  })
   const existingVariants = parts.slice(0, parts.length - 1)
 
   if (state.jit) {
M packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts -> packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts
diff --git a/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts b/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts
index 1b6c997abe4119d48fd73b428837f673c1fd08e1..454e0f59cafae735251e5b97a10af6329a9f8d8c 100644
--- a/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts
+++ b/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts
@@ -32,7 +32,13 @@     if (!boundaries) return []
     ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range))
   }
 
+import { closest } from '../util/closest'
 import { InvalidVariantDiagnostic, DiagnosticKind } from './types'
+    if (variant.values.length) {
+      return variant.values.map((value) => `${variant.name}${variant.hasDash ? '-' : ''}${value}`)
+    }
+    return [variant.name]
+import { closest } from '../util/closest'
   if (state.jit) {
     possibleVariants.unshift('responsive')
     possibleVariants = possibleVariants.filter((v) => !state.screens.includes(v))
M packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts -> packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
diff --git a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
index 10dfe90c7cf4d353d820a43f32ed880f5fc490c8..b1709e12c482168bcb00cd38cc5a581eb24ec0eb 100644
--- a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
+++ b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts
@@ -5,17 +5,26 @@ export function getVariantsFromClassName(
   state: State,
   className: string
 ): { variants: string[]; offset: number } {
-  let allVariants = Object.keys(state.variants)
+export function getVariantsFromClassName(
   let parts = splitAtTopLevelOnly(className, state.separator).filter(Boolean)
+    if (variant.values.length) {
+      return variant.values.map((value) => `${variant.name}${variant.hasDash ? '-' : ''}${value}`)
+    }
+    return [variant.name]
+  })
   let variants = new Set<string>()
   let offset = 0
+  let parts = splitAtTopLevelOnly(className, state.separator)
+  if (parts.length < 2) {
+    return { variants: Array.from(variants), offset }
+  }
+  parts = parts.filter(Boolean)
 
   for (let part of parts) {
     if (
       allVariants.includes(part) ||
       (state.jit &&
-        ((part.includes('[') && part.endsWith(']')) ||
-          (part.includes('<') && part.includes('>'))) &&
+        ((part.includes('[') && part.endsWith(']')) || part.includes('/')) &&
         jit.generateRules(state, [`${part}${state.separator}[color:red]`]).rules.length > 0)
     ) {
       variants.add(part)
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 cb863773db039a83b1afeae41807701a07a88219..4c82bb52f4d20aa0a7ff551700be178b14318179 100644
--- a/packages/tailwindcss-language-service/src/util/state.ts
+++ b/packages/tailwindcss-language-service/src/util/state.ts
@@ -80,6 +80,14 @@   future: string[]
   experimental: string[]
 }
 
+export interface Variant {
+  name: string
+  values: string[]
+  isArbitrary: boolean
+  hasDash: boolean
+  selectors: (params?: { value?: string; label?: string }) => string[]
+}
+
 export interface State {
   enabled: boolean
   configPath?: string
@@ -90,7 +98,7 @@   separator?: string
   dependencies?: string[]
   plugins?: any
   screens?: string[]
-  variants?: Record<string, string | null>
+  variants?: Variant[]
   corePlugins?: string[]
   modules?: {
     tailwindcss?: { version: string; module: any }
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 4b2bdfb03c7c526ba31f67193e9c573fdec095d8..d1cb232a15727263b29110a09d58a70b75da31fe 100755
--- a/packages/vscode-tailwindcss/src/extension.ts
+++ b/packages/vscode-tailwindcss/src/extension.ts
@@ -26,6 +26,7 @@   CompletionList,
   ProviderResult,
   SnippetString,
   TextEdit,
+  TextEditorSelectionChangeKind,
 } from 'vscode'
 import {
   LanguageClient,
@@ -148,6 +149,62 @@         outputChannel.show()
       }
     })
   )
+
+  // context.subscriptions.push(
+  //   commands.registerCommand(
+  //     'tailwindCSS.onInsertArbitraryVariantSnippet',
+  //     (
+  //       variantName: string,
+  //       range: {
+  //         start: { line: number; character: number }
+  //         end: { line: number; character: number }
+  //       }
+  //     ) => {
+  //       let listener = Window.onDidChangeTextEditorSelection((event) => {
+  //         if (event.selections.length !== 1) {
+  //           listener.dispose()
+  //           return
+  //         }
+
+  //         let document = event.textEditor.document
+  //         let selection = event.selections[0]
+
+  //         let line = document.lineAt(range.start.line)
+  //         let lineRangeFromCompletion = new Range(
+  //           range.start.line,
+  //           range.start.character,
+  //           line.range.end.line,
+  //           line.range.end.character
+  //         )
+  //         let lineText = document.getText(lineRangeFromCompletion)
+  //         let match = lineText.match(/^(\S+)]:/)
+
+  //         if (!match) {
+  //           listener.dispose()
+  //           return
+  //         }
+
+  //         let arbitraryValueRange = new Range(
+  //           lineRangeFromCompletion.start.translate(0, variantName.length + 2),
+  //           lineRangeFromCompletion.start.translate(0, match[1].length)
+  //         )
+
+  //         if (!arbitraryValueRange.contains(selection)) {
+  //           listener.dispose()
+  //         }
+
+  //         if (
+  //           event.kind === TextEditorSelectionChangeKind.Command &&
+  //           selection.isEmpty &&
+  //           selection.start.isEqual(arbitraryValueRange.end.translate(0, 2))
+  //         ) {
+  //           commands.executeCommand('editor.action.triggerSuggest')
+  //         }
+  //       })
+  //       context.subscriptions.push(listener)
+  //     }
+  //   )
+  // )
 
   let watcher = Workspace.createFileSystemWatcher(`**/${CONFIG_FILE_GLOB}`, false, true, true)