tailwind-ctp-intellisense @master -
refs -
log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
Adopt `getVariants` API
6 changed files, 316 additions(+), 129 deletions(-)
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) {
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) {
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))
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)
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 }
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)