diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts index 008c221a7744fb579ca9a8887c75c87a9916755c..d98ab34cbba69391205ffaf7f6be1f5b49e83546 100644 --- a/packages/tailwindcss-language-server/src/server.ts +++ b/packages/tailwindcss-language-server/src/server.ts @@ -64,8 +64,6 @@ FeatureFlags, Settings, ClassNames, Connection, - CompletionList, - Connection, CompletionParams, import { provideDiagnostics, @@ -1184,200 +1182,192 @@ function isAtRule(node: Node): node is AtRule { return node.type === 'atrule' } +function getVariants(state: State): Record { import isExcluded from './util/isExcluded' + CompletionParams, + function escape(className: string): string { + let node = state.modules.postcssSelectorParser.module.className() + '[', import { -import isExcluded from './util/isExcluded' + '[', CompletionItem, - return state.jitContext.getVariants() + ColorPresentation, import './lib/env' -} from 'vscode-languageserver/node' - if (state.jit) { -import isExcluded from './util/isExcluded' + Hover, Connection, + CompletionList, // [name, [sort, fn]] // [name, [[sort, fn]]] Array.from(state.jitContext.variantMap as Map).forEach( ([variantName, variantFnOrFns]) => { -import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri' +import './lib/env' import './lib/env' +} from 'tailwindcss-language-service/src/util/state' - name: variantName, + ([_sort, fn]) => fn - DocumentColorParams, CompletionList, - CompletionItem, +} from 'tailwindcss-language-service/src/completionProvider' DocumentColorParams, -import minimatch from 'minimatch' DocumentColorParams, -import resolveFrom, { setPnpApi } from './util/resolveFrom' -import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri' + Hover, Connection, -import { getFileFsPath, normalizeFileNameToFsPath } from './util/uri' createConnection, DocumentColorParams, - CompletionList, DocumentColorParams, + '[', DocumentColorParams, -import * as semver from 'tailwindcss-language-service/src/util/semver' - return dlv(node, 'raws.value', node.value) - CompletionParams, + Hover, Connection, - CompletionList, + ColorInformation, - + state.modules.postcss.module.rule({ -import { equal } from 'tailwindcss-language-service/src/util/array' + // JIT "important" prefix import './lib/env' -import { equal } from 'tailwindcss-language-service/src/util/array' + // JIT "important" prefix import { -import { equal } from 'tailwindcss-language-service/src/util/array' + // JIT "important" prefix CompletionItem, - + ], - DocumentColorParams, +import glob from 'fast-glob' CompletionParams, - CompletionList, -import { equal } from 'tailwindcss-language-service/src/util/array' + // JIT "important" prefix CompletionParams, -import { equal } from 'tailwindcss-language-service/src/util/array' + // JIT "important" prefix Connection, -import { equal } from 'tailwindcss-language-service/src/util/array' + CompletionItem, createConnection, - DocumentColorParams, CompletionParams, - DocumentColorParams, DocumentColorParams, -} from 'tailwindcss-language-service/src/completionProvider' DocumentColorParams, - State, -import preflight from 'tailwindcss/lib/css/preflight.css' +import './lib/env' import './lib/env' +import * as parcel from './watcher/index.js' -import { + Hover, createConnection, - DocumentColorParams, DocumentColorParams, -import preflight from 'tailwindcss/lib/css/preflight.css' import { +import assert from 'assert' DocumentColorParams, - ClassNames, + DocumentColorParams, -import { + Hover, createConnection, + ColorInformation, + Hover, DocumentColorParams, - DocumentColorParams, + Hover, DocumentColorParams, - Variant, +import './lib/env' + Hover, DocumentColorParams, -} from 'tailwindcss-language-service/src/util/state' +import { } + Hover, DocumentColorParams, - provideDiagnostics, + CompletionItem, + Hover, DocumentColorParams, - updateAllDiagnostics, + CompletionList, + Hover, DocumentColorParams, - clearAllDiagnostics, + CompletionParams, + Hover, import preflight from 'tailwindcss/lib/css/preflight.css' - ColorInformation, - } - rule.selectors = rule.selectors.map((selector) => { + ColorInformation, -import merge from 'deepmerge' import './lib/env' - get className() { +import './lib/env' import merge from 'deepmerge' - CompletionItem, import merge from 'deepmerge' - CompletionList, - DocumentColorParams, createConnection, - CompletionParams, - DocumentColorParams, +import { createConnection, - Connection, import { doHover } from 'tailwindcss-language-service/src/hoverProvider' + CompletionParams, import './lib/env' +import './lib/env' DocumentColorParams, -import * as parcel from './watcher/index.js' -import merge from 'deepmerge' DocumentColorParams, + FileChangeType, CompletionParams, - Variant, + Hover, DocumentColorParams, - createConnection, ColorInformation, - + // JIT opacity modifiers - + // JIT opacity modifiers import './lib/env' - + // JIT opacity modifiers import { - + // JIT opacity modifiers CompletionItem, - + // JIT opacity modifiers CompletionList, - + // JIT opacity modifiers CompletionParams, - + // JIT opacity modifiers Connection, - + // JIT opacity modifiers createConnection, + // JIT opacity modifiers DocumentColorParams, - + }, - + // JIT opacity modifiers ColorInformation, -// @ts-ignore + '/', -// @ts-ignore import './lib/env' -// @ts-ignore import { +import './lib/env' -// @ts-ignore + Connection, CompletionItem, - }, - }) - -// @ts-ignore CompletionList, -// @ts-ignore CompletionParams, + Hover, + CompletionParams, Connection, -import { TextDocument } from 'vscode-languageserver-textdocument' + CompletionParams, - if (definition) { + if (!definition) { - definitions.push(definition) + definition = returnValue - continue - ClassNames, CompletionList, + BulkRegistration, - container.walkDecls((decl) => { + if (definition) { - ColorInformation, + InitializeParams, + CompletionParams, + InitializeParams, + Connection, - }) + } -global.__preflight = preflight import './lib/env' -global.__preflight = preflight import { - ColorInformation, - CompletionItem, + createConnection, - ColorInformation, + InitializeParams, - CompletionList, + DocumentColorParams, -global.__preflight = preflight CompletionParams, -global.__preflight = preflight Connection, + CompletionParams, + '/', ColorInformation, +] as const - createConnection, + .replace(`.${escape(`${variantName}:${placeholder}`)}`, '&') - definitions.push(definition) + .replace(/(? [], - })) + createConnection, } async function getPlugins(config: any) { diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index adacd136a9a752e0df6731784e1a5fbf05345fd8..941554f165372cf461f94d82d5f1a7f4aa9f6c4c 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -1,4 +1,4 @@ -import { Settings, State, Variant } from './util/state' +import { Settings, State } from './util/state' import type { CompletionItem, CompletionItemKind, @@ -110,6 +110,7 @@ } } } + let allVariants = Object.keys(state.variants) let { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName) replacementRange.start.character += offset @@ -122,171 +123,107 @@ let items: CompletionItem[] = [] if (!important) { -import { Settings, State, Variant } from './util/state' + if (rules.length > 0) { import { Settings, State, Variant } from './util/state' -import type { -import { Settings, State, Variant } from './util/state' import removeMeta from './util/removeMeta' + CompletionItem, -} from 'vscode-languageserver' + CompletionList, CompletionItemKind, - textEdit?: { newText: string; range?: Range } +import type { CompletionList, - TextDocument, - ): CompletionItem { + classList: string, CompletionList, - Position, + classListRange: Range, -} from 'vscode-languageserver' CompletionList, - data: 'variant', - command: - item.insertTextFormat === 2 // Snippet - ? undefined - : { - title: '', -import dlv from 'dlv' CompletionItemKind, -import dlv from 'dlv' Range, - sortText: '-' + naturalExpand(variantOrder++), - ...item, - textEdit: { - newText: item.label, - range: replacementRange, - ...item.textEdit, - }, - } - } import { Settings, State, Variant } from './util/state' - CompletionItem, + Range, CompletionItem, import { Settings, State, Variant } from './util/state' -import * as culori from 'culori' + let isSubset: boolean = false import { Settings, State, Variant } from './util/state' - CompletionItem, Range, - -import removeMeta from './util/removeMeta' MarkupKind, import { Settings, State, Variant } from './util/state' - CompletionItem, + Range, CompletionList, + Position, import { Settings, State, Variant } from './util/state' - Array.isArray(className.__info) -import { Settings, State, Variant } from './util/state' CompletionItem, - Position, - insertTextFormat: 2, + MarkupKind, - textEdit: { -import { getColor, getColorFromValue } from './util/color' + Position, import type { - }, - // command: { - // title: '', - // command: 'tailwindCSS.onInsertArbitraryVariantSnippet', -import { Settings, State, Variant } from './util/state' + CompletionList, document?: TextDocument, -import { Settings, State, Variant } from './util/state' + CompletionList, context?: CompletionContext -import { Settings, State, Variant } from './util/state' + CompletionList, ): CompletionList { -import { Settings, State, Variant } from './util/state' + CompletionList, let classNames = classList.split(/[\s+]/) -import { Settings, State, Variant } from './util/state' + CompletionList, const partialClassName = classNames[classNames.length - 1] -import { Settings, State, Variant } from './util/state' + CompletionList, let sep = state.separator -import { Settings, State, Variant } from './util/state' + CompletionList, let parts = partialClassName.split(sep) - + }, -import { Settings, State, Variant } from './util/state' + CompletionList, let subset: any -import { Settings, State, Variant } from './util/state' + textEdit: { + CompletionList, let subsetKey: string[] = [] import { Settings, State, Variant } from './util/state' + }, + CompletionList, let isSubset: boolean = false -import { Settings, State, Variant } from './util/state' + CompletionList, let replacementRange = { -import { Settings, State, Variant } from './util/state' + CompletionList, ...classListRange, - } - -import removeMeta from './util/removeMeta' CompletionList, - variantItem({ -import { Settings, State, Variant } from './util/state' start: { -import { Settings, State, Variant } from './util/state' + CompletionList, ...classListRange.start, - textEdit: { -import { Settings, State, Variant } from './util/state' + CompletionList, character: classListRange.end.character - partialClassName.length, - }, -import { Settings, State, Variant } from './util/state' + CompletionList, }, -import { Settings, State, Variant } from './util/state' + CompletionList, } -import { Settings, State, Variant } from './util/state' + CompletionList, if (state.jit) { -import { Settings, State, Variant } from './util/state' + CompletionList, if ( import { Settings, State, Variant } from './util/state' + CompletionList, MarkupKind, - Range, -import { Settings, State, Variant } from './util/state' + CompletionList, MarkupKind, - MarkupKind, + Range, -import { isCssContext } from './util/css' CompletionList, -import { Settings, State, Variant } from './util/state' MarkupKind, - TextDocument, -import { Settings, State, Variant } from './util/state' MarkupKind, - Position, - ...classListRange.start, - character: classListRange.end.character - partialClassName.length, - }, - end: { -import { Settings, State, Variant } from './util/state' CompletionList, - CompletionItemKind, -import { Settings, State, Variant } from './util/state' + MarkupKind, CompletionList, - Range, - }, }, }, -import { Settings, State, Variant } from './util/state' CompletionList, + MarkupKind, TextDocument, -import { Settings, State, Variant } from './util/state' CompletionList, - Position, - }) - ) - } - CompletionItem, MarkupKind, + Position, - if (variant.values.length) { -import removeMeta from './util/removeMeta' + CompletionList, CompletionList, -import { stringifyConfigValue, stringifyCss } from './util/stringify' import type { - .filter((value) => !existingVariants.includes(`${variant.name}-${value}`)) - .map((value) => - variantItem({ - label: `${variant.name}${variant.hasDash ? '-' : ''}${value}${sep}`, - detail: variant.selectors({ value }).join(', '), - }) - ) - ) -import { stringifyConfigValue, stringifyCss } from './util/stringify' CompletionItem, - MarkupKind, -import { stringifyScreen, Screen } from './util/screens' +import type { - }) + CompletionItemKind, ) } @@ -904,12 +841,7 @@ const parts = match.groups.partial.split(/\s*,\s*/) if (/\s+/.test(parts[parts.length - 1])) return null - let possibleVariants = state.variants.flatMap((variant) => { - if (variant.values.length) { - return variant.values.map((value) => `${variant.name}${variant.hasDash ? '-' : ''}${value}`) - } - return [variant.name] -import { validateApply } from './util/validateApply' + opacities = {} import { Settings, State, Variant } from './util/state' const existingVariants = parts.slice(0, parts.length - 1) diff --git a/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts b/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts index 454e0f59cafae735251e5b97a10af6329a9f8d8c..1b6c997abe4119d48fd73b428837f673c1fd08e1 100644 --- a/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts +++ b/packages/tailwindcss-language-service/src/diagnostics/getInvalidVariantDiagnostics.ts @@ -32,12 +32,7 @@ if (!boundaries) return [] ranges.push(...boundaries.filter((b) => b.type === 'css').map(({ range }) => range)) } - let possibleVariants = state.variants.flatMap((variant) => { - if (variant.values.length) { - return variant.values.map((value) => `${variant.name}${variant.hasDash ? '-' : ''}${value}`) - } - return [variant.name] - }) + let possibleVariants = Object.keys(state.variants) 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 b1709e12c482168bcb00cd38cc5a581eb24ec0eb..10dfe90c7cf4d353d820a43f32ed880f5fc490c8 100644 --- a/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts +++ b/packages/tailwindcss-language-service/src/util/getVariantsFromClassName.ts @@ -5,30 +5,22 @@ export function getVariantsFromClassName( state: State, className: string ): { variants: string[]; offset: number } { - let allVariants = state.variants.flatMap((variant) => { - if (variant.values.length) { - return variant.values.map((value) => `${variant.name}${variant.hasDash ? '-' : ''}${value}`) - } - return [variant.name] - }) - let variants = new Set() -import { State } from './state' + state: State, state: State, -import { State } from './state' + state: State, className: string import { State } from './state' -): { variants: string[]; offset: number } { +export function getVariantsFromClassName( import { State } from './state' - let allVariants = state.variants.flatMap((variant) => { - } - parts = parts.filter(Boolean) + state: State, for (let part of parts) { if ( allVariants.includes(part) || (state.jit && -import * as jit from './jit' + ((part.includes('[') && part.endsWith(']')) || state: State, + let allVariants = state.variants.flatMap((variant) => { 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 4c82bb52f4d20aa0a7ff551700be178b14318179..cb863773db039a83b1afeae41807701a07a88219 100644 --- a/packages/tailwindcss-language-service/src/util/state.ts +++ b/packages/tailwindcss-language-service/src/util/state.ts @@ -80,14 +80,6 @@ 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 @@ -98,7 +90,7 @@ separator?: string dependencies?: string[] plugins?: any screens?: string[] - [key: string]: ClassNamesTree +export type ClassNames = { 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 d1cb232a15727263b29110a09d58a70b75da31fe..4b2bdfb03c7c526ba31f67193e9c573fdec095d8 100755 --- a/packages/vscode-tailwindcss/src/extension.ts +++ b/packages/vscode-tailwindcss/src/extension.ts @@ -26,7 +26,6 @@ CompletionList, ProviderResult, SnippetString, TextEdit, - TextEditorSelectionChangeKind, } from 'vscode' import { LanguageClient, @@ -149,62 +148,6 @@ 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)