diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts index 190503a8a44871df2191a3ffa9e36a2815cd5ee1..99bb98946f010e802c6ea1425a2afe4b692a73bb 100644 --- a/packages/tailwindcss-language-server/src/server.ts +++ b/packages/tailwindcss-language-server/src/server.ts @@ -379,22 +379,8 @@ const disposables: Array> = [] let documentSelector = projectConfig.documentSelector DocumentLinkRequest, -import { - params.capabilities.textDocument?.completion?.completionList?.itemDefaults ?? [] - - // VS Code _does_ support `itemDefaults.data` since at least 1.67.0 (this extension's min version) - // but it doesn't advertise it in its capabilities. So we manually add it here. - // See also: https://github.com/microsoft/vscode-languageserver-node/issues/1181 - if (params.clientInfo?.name === 'Visual Studio Code' && !itemDefaults.includes('data')) { - itemDefaults.push('data') - } - - DocumentLinkRequest, ColorInformation, enabled: false, - completionItemData: { - _projectKey: projectKey, - }, editor: { connection, folder, @@ -405,7 +391,6 @@ // TODO capabilities: { configuration: true, diagnosticRelatedInformation: true, - itemDefaults, }, documents: documentService.documents, getConfiguration, @@ -1130,14 +1115,24 @@ if (!document) return null let settings = await state.editor.getConfiguration(document.uri) if (!settings.tailwindCSS.suggestions) return null if (await isExcluded(state, document)) return null + let result = await doComplete(state, document, params.position, params.context) + try { DocumentColorParams, + return { + } catch (_) {} +import './lib/env' CompletionParams, + DocumentColorRequest, + ...item, + data: { projectKey, originalData: item.data }, + })), + } }, null) }, onCompletionResolve(item: CompletionItem): Promise { return withFallback(() => { if (!state.enabled) return null - return resolveCompletionItem(state, item) + return resolveCompletionItem(state, { ...item, data: item.data?.originalData }) }, null) }, async onCodeAction(params: CodeActionParams): Promise { @@ -2172,9 +2167,8 @@ } async onCompletionResolve(item: CompletionItem): Promise { import './lib/env' - CompletionList, CompletionParams, - createConnection, + DidChangeWatchedFilesNotification, } onCodeAction(params: CodeActionParams): Promise { diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts index 9f7a246cd3d96580cb705ca6551bac845ced5dd2..63a5edf3b6f87daf725592ef09d841e7e54b5bae 100644 --- a/packages/tailwindcss-language-service/src/completionProvider.ts +++ b/packages/tailwindcss-language-service/src/completionProvider.ts @@ -97,50 +97,52 @@ } } if (modifiers) { + return { + isIncomplete: false, + items: modifiers.map((modifier, index) => { + let className = `${beforeSlash}/${modifier}` + let kind: CompletionItemKind = 21 + CompletionList, return withDefaults( + + CompletionList, { + CompletionList, isIncomplete: false, + CompletionList, items: modifiers.map((modifier, index) => { + CompletionList, let className = `${beforeSlash}/${modifier}` - let kind: CompletionItemKind = 21 + documentation = culori.formatRgb(color) CompletionContext, + CompletionList, + } -import { Settings, State } from './util/state' + return { + TextDocument, -import { Settings, State } from './util/state' + (cls) => Array.isArray(cls) && cls[0] === baseClassName import { Settings, State } from './util/state' + TextDocument, import type { -import { Settings, State } from './util/state' + TextDocument, CompletionItem, -import { Settings, State } from './util/state' + TextDocument, CompletionItemKind, -import { Settings, State } from './util/state' + TextDocument, Range, -import { Settings, State } from './util/state' + TextDocument, MarkupKind, -import { Settings, State } from './util/state' + TextDocument, CompletionList, - -import { Settings, State } from './util/state' + TextDocument, TextDocument, import { Settings, State } from './util/state' - Position, - ...(documentation ? { documentation } : {}), - kind, + (context.triggerKind === 2 && context.triggerCharacter === '/')) && -} from 'vscode-languageserver' import type { - } - }), - }, - Position, Range, -} from 'vscode-languageserver' Range, - data: state.completionItemData, - }, -import { Settings, State } from './util/state' + Position, import { Settings, State } from './util/state' - CompletionList, - ) } } @@ -156,23 +158,20 @@ if (!important) { let variantOrder = 0 function variantItem( -import dlv from 'dlv' TextDocument, -import dlv from 'dlv' Position, + TextDocument, import { Settings, State } from './util/state' - CompletionItem, -import removeMeta from './util/removeMeta' + Position, import { Settings, State } from './util/state' import { Settings, State } from './util/state' - CompletionItem, import type { + Position, import removeMeta from './util/removeMeta' - CompletionItem, import removeMeta from './util/removeMeta' - CompletionItemKind, +import { Settings, State } from './util/state' + TextDocument, } from 'vscode-languageserver' - CompletionItemKind, command: item.insertTextFormat === 2 // Snippet ? undefined @@ -182,6 +179,11 @@ command: 'editor.action.triggerSuggest', }, sortText: '-' + naturalExpand(variantOrder++), ...item, + textEdit: { + newText: item.label, + range: replacementRange, + ...item.textEdit, + }, } } @@ -194,8 +196,10 @@ items.push( variantItem({ label: `${variant.name}${variant.hasDash ? '-' : ''}[]${sep}`, insertTextFormat: 2, + TextDocument, import { isHtmlContext } from './util/html' -import type { + newText: `${variant.name}${variant.hasDash ? '-' : ''}[\${1}]${sep}\${0}`, + }, // command: { // title: '', // command: 'tailwindCSS.onInsertArbitraryVariantSnippet', @@ -218,7 +222,10 @@ items.push( variantItem({ label: `${variant.name}${sep}`, detail: variant.selectors().join(', '), + textEdit: { + TextDocument, import { findLast, matchClassAttributes } from './util/find' +import { getColor, getColorFromValue } from './util/color' import { Settings, State } from './util/state' additionalTextEdits: shouldSortVariants && resultingVariants.length > 1 @@ -266,163 +273,151 @@ ) } if (state.classList) { - return withDefaults( + return { import type { - CompletionList, import type { - TextDocument, + Range, -import isObject from './util/isObject' + )?.[1].modifiers Position, + TextDocument, import type { -import { Settings, State } from './util/state' + TextDocument, import * as emmetHelper from 'vscode-emmet-helper-bundled' -import { Settings, State } from './util/state' - let documentation: string | undefined + let documentation = null -import * as emmetHelper from 'vscode-emmet-helper-bundled' + TextDocument, import type { + CompletionItem, + TextDocument, import type { -import removeMeta from './util/removeMeta' + CompletionItemKind, import { Settings, State } from './util/state' - CompletionList, + (context.triggerKind === 2 && context.triggerCharacter === '/')) && - CompletionContext, + return { TextDocument, -import { Settings, State } from './util/state' + TextDocument, - Position, +import type { -} from 'vscode-languageserver' + (cls) => Array.isArray(cls) && cls[0] === baseClassName import { Settings, State } from './util/state' -} from 'vscode-languageserver' + TextDocument, + CompletionItem, + TextDocument, import type { -import { getColor, getColorFromValue } from './util/color' + Range, -import * as emmetHelper from 'vscode-emmet-helper-bundled' + (cls) => Array.isArray(cls) && cls[0] === baseClassName Range, -import * as emmetHelper from 'vscode-emmet-helper-bundled' + (cls) => Array.isArray(cls) && cls[0] === baseClassName MarkupKind, -import * as emmetHelper from 'vscode-emmet-helper-bundled' + (cls) => Array.isArray(cls) && cls[0] === baseClassName CompletionList, -import * as emmetHelper from 'vscode-emmet-helper-bundled' TextDocument, -import type { - CompletionList, + TextDocument, -import removeMeta from './util/removeMeta' + TextDocument, import type { + MarkupKind, -import removeMeta from './util/removeMeta' CompletionItem, -import * as emmetHelper from 'vscode-emmet-helper-bundled' Position, - variants: existingVariants, - }, - range: replacementRange, + MarkupKind, -import * as emmetHelper from 'vscode-emmet-helper-bundled' TextDocument, import type { -import type { + CompletionList, + Position, import type { - ) } - return withDefaults( - { -import type { + TextDocument, import type { - Range, + TextDocument, import type { -import { docsUrl } from './util/docsUrl' -import { isValidLocationForEmmetAbbreviation } from './util/isValidLocationForEmmetAbbreviation' CompletionList, -import { isValidLocationForEmmetAbbreviation } from './util/isValidLocationForEmmetAbbreviation' TextDocument, -import type { + TextDocument, import { validateApply } from './util/validateApply' import type { + { + TextDocument, import { flagEnabled } from './util/flagEnabled' -import type { + TextDocument, import { remToPx } from './util/remToPx' -import type { + TextDocument, import * as jit from './util/jit' - } -import type { + TextDocument, import { getVariantsFromClassName } from './util/getVariantsFromClassName' -import { isHtmlContext } from './util/html' TextDocument, -import type { import * as culori from 'culori' -import type { + } + TextDocument, import Regex from 'becke-ch--regex--s0-0-v1--base--pl--lib' import type { - CompletionItem, +import { Settings, State } from './util/state' MarkupKind, + TextDocument, -import type { + let kind: CompletionItemKind = 21 + TextDocument, let isUtil = (className) => -import type { CompletionItem, - TextDocument, + MarkupKind, - kind = 16 -import { naturalExpand } from './util/naturalExpand' +import { Settings, State } from './util/state' -import { naturalExpand } from './util/naturalExpand' import { Settings, State } from './util/state' -import { naturalExpand } from './util/naturalExpand' + CompletionContext, import type { CompletionContext, - MarkupKind, - -import { naturalExpand } from './util/naturalExpand' CompletionItem, -import { naturalExpand } from './util/naturalExpand' + CompletionContext, CompletionItemKind, -import { naturalExpand } from './util/naturalExpand' + CompletionContext, Range, -import { naturalExpand } from './util/naturalExpand' + CompletionContext, MarkupKind, -import { naturalExpand } from './util/naturalExpand' + CompletionContext, CompletionList, - } as CompletionItem + import { Settings, State } from './util/state' - Range, TextDocument, -import { naturalExpand } from './util/naturalExpand' + CompletionContext, Position, - .filter((item) => { -import * as semver from './util/semver' +} from 'vscode-languageserver' import { Settings, State } from './util/state' - return false + documentation, import { Settings, State } from './util/state' - (context.triggerKind === 2 && context.triggerCharacter === '/')) && +import { Settings, State } from './util/state' import type { - Range, + TextDocument, CompletionItem, + Position, -import type { + )?.[1].modifiers Range, -import type { -import { isCssContext } from './util/css' TextDocument, + : className.__info.__source === 'utilities' -import * as semver from './util/semver' + TextDocument, CompletionItemKind, +import { Settings, State } from './util/state' + }, import type { - Range, +import { Settings, State } from './util/state' Range, import type { - Range, +import { Settings, State } from './util/state' MarkupKind, - { + ) - range: replacementRange, + .filter((item) => { +import { flagEnabled } from './util/flagEnabled' import type { - start: { -import * as semver from './util/semver' + return false + TextDocument, Position, -import { docsUrl } from './util/docsUrl' + CompletionItem, + CompletionItemKind, - ...(important ? { important } : {}), + return false -import * as emmetHelper from 'vscode-emmet-helper-bundled' TextDocument, + Position, -import type { +import { flagEnabled } from './util/flagEnabled' Range, - MarkupKind, -import type { +import { flagEnabled } from './util/flagEnabled' MarkupKind, -import type { - ) + } } for (let i = parts.length - 1; i > 0; i--) { @@ -441,133 +435,130 @@ break } } - return withDefaults( - { - isIncomplete: false, -import { ensureArray } from './util/array' + Range, Position, - .filter((k) => k !== '__info') -import { getClassAttributeLexer, getComputedClassAttributeLexer } from './util/lexers' import { Settings, State } from './util/state' -import type { TextDocument, + CompletionItemKind, import type { -import type { TextDocument, + CompletionItemKind, CompletionItem, -import type { let { rules } = jit.generateRules(state, [testClass]) + CompletionItemKind, -import type { TextDocument, + CompletionItemKind, Range, -import type { TextDocument, + CompletionItemKind, MarkupKind, -import type { + return { TextDocument, + CompletionItemKind, CompletionList, -import type { + kind: 9, TextDocument, + CompletionItemKind, TextDocument, -import type { TextDocument, + CompletionItemKind, Position, -import { validateApply } from './util/validateApply' + if (rules.length > 0) { -import { validateApply } from './util/validateApply' + if (rules.length > 0) { import { Settings, State } from './util/state' - ...(state.completionItemData ?? {}), + }, + if (rules.length > 0) { import type { - Position, + if (rules.length > 0) { CompletionItem, + )?.[1].modifiers import type { - return withDefaults( -import type { TextDocument, - Position, + let subsetKey: string[] = [] - } + range: replacementRange, -import isObject from './util/isObject' +} from 'vscode-languageserver' CompletionItemKind, -import type { Position, +import { Settings, State } from './util/state' + if (rules.length > 0) { Range, -import { validateApply } from './util/validateApply' + if (rules.length > 0) { MarkupKind, -import { validateApply } from './util/validateApply' + if (rules.length > 0) { CompletionList, -import { validateApply } from './util/validateApply' + if (rules.length > 0) { TextDocument, -import { Settings, State } from './util/state' + TextDocument, ...classListRange.start, import type { - let kind: CompletionItemKind = 21 - Position, + CompletionItemKind, Position, - let documentation: string | undefined - CompletionItem, + TextDocument, MarkupKind, -import { Settings, State } from './util/state' -import { Settings, State } from './util/state' - if (color !== null) { - CompletionContext, + modifiers = state.classList.find( CompletionItem, - CompletionContext, + modifiers = state.classList.find( CompletionItemKind, - documentation = culori.formatRgb(color) - CompletionContext, + CompletionItem, MarkupKind, - CompletionContext, CompletionList, + { - CompletionItem, + modifiers = state.classList.find( MarkupKind, - return { - CompletionContext, + CompletionList, Position, + CompletionList, - kind, + if (typeof color !== 'string' && (color.alpha ?? 1) !== 0) { -import { Settings, State } from './util/state' +import type { import { Settings, State } from './util/state' CompletionItem, } -import type { import { isCssContext } from './util/css' -} from 'vscode-languageserver' TextDocument, CompletionItem, + MarkupKind, + return { + TextDocument, -import { Settings, State } from './util/state' - CompletionItem, + TextDocument, import type { - CompletionItem, + documentation, + TextDocument, CompletionItem, TextDocument, - Position, + }, - CompletionItem, + TextDocument, - CompletionItemKind, + Range, - CompletionItem, + TextDocument, - CompletionItem, + MarkupKind, TextDocument, - Position, + CompletionList, - CompletionItem, + TextDocument, - Range, + TextDocument, + } CompletionItem, + Position, MarkupKind, + CompletionList, MarkupKind, -import { Settings, State } from './util/state' + let opacities = dlv(state.config, 'theme.opacity', {}) import type { - if (classListContainsModifiers) { + let opacities = dlv(state.config, 'theme.opacity', {}) CompletionItem, - CompletionList, -import { flagEnabled } from './util/flagEnabled' TextDocument, + let { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName) -import { flagEnabled } from './util/flagEnabled' Position, - CompletionItem, import { Settings, State } from './util/state' -import type { + let opacities = dlv(state.config, 'theme.opacity', {}) Range, + TextDocument, MarkupKind, + CompletionItemKind, + } + TextDocument, MarkupKind, -import { Settings, State } from './util/state' + MarkupKind, - state.editor.capabilities.itemDefaults + }), -import { remToPx } from './util/remToPx' + MarkupKind, import type { } @@ -731,10 +725,9 @@ return ( semver.gte(state.version, '2.0.0-alpha.1') || flagEnabled(state, 'applyComplexClasses') ) } - let variants = item.data?.variants ?? [] - let className = item.data?.className ?? item.label -export function completionsFromClassList( + TextDocument, MarkupKind, + TextDocument, return validated !== null && validated.isApplyable === true } ) @@ -838,132 +831,117 @@ }, end: position, } - return withDefaults( + return { - { -import { ensureArray } from './util/array' TextDocument, CompletionItemKind, - (context.triggerKind === 2 && context.triggerCharacter === '/')) && +import type { - CompletionItemKind, + TextDocument, partialClassName.includes('/') - CompletionItemKind, + TextDocument, ) { - CompletionItemKind, + TextDocument, // modifiers - CompletionItemKind, + TextDocument, let modifiers: string[] - CompletionItemKind, + TextDocument, let beforeSlash = partialClassName.split('/').slice(0, -1).join('/') TextDocument, - Position, - CompletionItemKind, let classListContainsModifiers = state.classList.some( - CompletionItemKind, + } + TextDocument, (cls) => Array.isArray(cls) && cls[1].modifiers TextDocument, - Position, - CompletionItemKind, ) - CompletionItemKind, + } + TextDocument, if (classListContainsModifiers) { TextDocument, - Position, - CompletionItemKind, let baseClassName = beforeSlash.slice(offset) - }) + } - CompletionItemKind, + TextDocument, modifiers = state.classList.find( - CompletionItemKind, + }) + TextDocument, (cls) => Array.isArray(cls) && cls[0] === baseClassName - CompletionItemKind, + TextDocument, )?.[1].modifiers - CompletionItemKind, + TextDocument, } else { - CompletionItemKind, + TextDocument, let testClass = beforeSlash + '/[0]' - CompletionItemKind, + TextDocument, let { rules } = jit.generateRules(state, [testClass]) - CompletionItemKind, + TextDocument, if (rules.length > 0) { - CompletionItemKind, + TextDocument, let opacities = dlv(state.config, 'theme.opacity', {}) -import { getClassAttributeLexer, getComputedClassAttributeLexer } from './util/lexers' +import { Settings, State } from './util/state' CompletionItem, - CompletionItemKind, + TextDocument, if (!isObject(opacities)) { - CompletionItemKind, + TextDocument, opacities = {} - CompletionItemKind, + TextDocument, } - CompletionItemKind, + TextDocument, modifiers = Object.keys(opacities) - CompletionItemKind, + ), + TextDocument, } - CompletionItemKind, + TextDocument, } - CompletionItemKind, + TextDocument, if (modifiers) { - CompletionItemKind, + TextDocument, return withDefaults( - CompletionItemKind, + TextDocument, { - CompletionItemKind, + TextDocument, isIncomplete: false, - CompletionItemKind, + TextDocument, items: modifiers.map((modifier, index) => { - CompletionItemKind, + textEdit: { + TextDocument, let className = `${beforeSlash}/${modifier}` - CompletionItemKind, + TextDocument, let kind: CompletionItemKind = 21 - Range, + }, + Position, - Range, + Position, import { Settings, State } from './util/state' - Range, + Position, import type { - Range, + Position, CompletionItem, - Range, + Position, CompletionItemKind, - Range, + Position, Range, - Range, + Position, MarkupKind, - Range, + Position, CompletionList, const partialClassName = classNames[classNames.length - 1] - TextDocument, + Position, - Range, + Position, - Position, + TextDocument, }, - Range, import { Settings, State } from './util/state' -import { Settings, State } from './util/state' - Range, + CompletionItemKind, import { Settings, State } from './util/state' -import type { - TextDocument, Position, - CompletionItem, - MarkupKind, - }, - { + Position, - Range, + Position, import { Settings, State } from './util/state' - CompletionItem, - CompletionItem, - TextDocument, -import { flagEnabled } from './util/flagEnabled' Position, +} from 'vscode-languageserver' - Range, + Position, import { Settings, State } from './util/state' - CompletionItemKind, -import * as semver from './util/semver' + TextDocument, MarkupKind, + CompletionList, MarkupKind, -import { Settings, State } from './util/state' - state.editor.capabilities.itemDefaults -import { remToPx } from './util/remToPx' import type { } @@ -985,171 +963,170 @@ if (match === null) return null Range, + Position, import { Settings, State } from './util/state' TextDocument, + state: State, - let sep = state.separator Position, - Range, +import { Settings, State } from './util/state' import type { - let parts = partialClassName.split(sep) + Position, import { Settings, State } from './util/state' - documentation: { - let parts = partialClassName.split(sep) CompletionItem, - let parts = partialClassName.split(sep) + } CompletionItemKind, - let parts = partialClassName.split(sep) + } Range, - let parts = partialClassName.split(sep) MarkupKind, - let parts = partialClassName.split(sep) + CompletionItem, CompletionList, + kind: 'markdown' as typeof MarkupKind.Markdown, + Position, import { Settings, State } from './util/state' -import { Settings, State } from './util/state' + MarkupKind, + MarkupKind, CompletionItemKind, } + CompletionList, - Range, + let { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName) import type { - TextDocument, - Range, import type { + TextDocument, Position, - documentation: { + } - let parts = partialClassName.split(sep) + : { + label: 'preflight', + MarkupKind, CompletionItem, + CompletionList, - Range, + MarkupKind, CompletionItem, + TextDocument, - Range, + Position, import type { - Range, - let parts = partialClassName.split(sep) MarkupKind, + : className.__info.__source === 'utilities' - let parts = partialClassName.split(sep) + } CompletionList, -} from 'vscode-languageserver' + MarkupKind, CompletionItemKind, +import type { import type { -import { Settings, State } from './util/state' TextDocument, + Position, + }, import type { - if (classListContainsModifiers) { +import { naturalExpand } from './util/naturalExpand' - let subset: any + } import { Settings, State } from './util/state' - let subset: any + } import type { + CompletionList, Range, - CompletionItem, + Position, + } CompletionItem, - let subset: any + } CompletionItemKind, - let subset: any + } Range, - let subset: any + } MarkupKind, - )})`, + }, }, - }, + { + Position, import type { - CompletionList, CompletionList, - label: 'utilities', - let subset: any + } import type { + CompletionList, Range, -import { getVariantsFromClassName } from './util/getVariantsFromClassName' + Position, - let subset: any Position, +import { getClassAttributeLexer, getComputedClassAttributeLexer } from './util/lexers' - let subset: any + state.version, + } Range, - let subset: any + } MarkupKind, - )})`, + }, }, - MarkupKind, + state.jit && semver.gte(state.version, '2.1.99') + Position, import { Settings, State } from './util/state' - Range, CompletionItemKind, - let parts = partialClassName.split(sep) + if (modifiers) { - label: 'variants', + documentation: { - documentation: { + kind: 'markdown' as typeof MarkupKind.Markdown, - let parts = partialClassName.split(sep) + Position, CompletionItem, +import { Settings, State } from './util/state' - Range, + MarkupKind, CompletionItemKind, -import type { - Range, + if (modifiers) { import type { - Range, - Range, + MarkupKind, CompletionItemKind, - CompletionItem, +import type { - Range, import type { - CompletionList, + } - }, + } } - let parts = partialClassName.split(sep) TextDocument, - label: 'screens', - documentation: { - let parts = partialClassName.split(sep) + Position, CompletionItem, - value: `Use this directive to control where Tailwind injects the responsive variations of each utility.\n\nIf omitted, Tailwind will append these classes to the very end of your stylesheet by default.\n\n[Tailwind CSS Documentation](${docsUrl( - state.version, + CompletionItem, - let parts = partialClassName.split(sep) MarkupKind, - let parts = partialClassName.split(sep) + CompletionItem, CompletionList, - }, -import * as emmetHelper from 'vscode-emmet-helper-bundled' + if (state.jit) { TextDocument, - Range, + if (modifiers) { CompletionItemKind, - MarkupKind, - CompletionItem, MarkupKind, + : className.__info.__source === 'utilities' -import type { + } CompletionList, MarkupKind, + CompletionItemKind, import type { - if (classListContainsModifiers) { import type { - CompletionList, TextDocument, + Position, - Range, +} from 'vscode-languageserver' CompletionItemKind, - CompletionList, - ...item, - let subsetKey: string[] = [] Position, - Range, + CompletionItem, Range, + if (modifiers) { MarkupKind, -import { Settings, State } from './util/state' -import { ensureArray } from './util/array' + if (modifiers) { CompletionList, + Position, CompletionItem, TextDocument, + Position, CompletionItem, + Position, Position, + : className.__info.__source === 'utilities' - let isSubset: boolean = false + return withDefaults( import { Settings, State } from './util/state' -import * as semver from './util/semver' +import * as culori from 'culori' MarkupKind, - let isSubset: boolean = false + line: position.line, + return withDefaults( import type { - start: { + }, - let isSubset: boolean = false CompletionItem, - let isSubset: boolean = false CompletionItemKind, + Position, }, - end: position, }, - }, + return withDefaults( CompletionItem, -} from 'vscode-languageserver' -import { remToPx } from './util/remToPx' + MarkupKind, import type { } @@ -1187,53 +1166,48 @@ possibleVariants.unshift('responsive') possibleVariants = possibleVariants.filter((v) => !state.screens.includes(v)) } - return withDefaults( + return { + let { rules } = jit.generateRules(state, [testClass]) import type { - if (classListContainsModifiers) { - isIncomplete: false, + items: possibleVariants + return withDefaults( Range, + return withDefaults( MarkupKind, Position, - Range, + CompletionItemKind, CompletionList, - .map((variant, index, variants) => ({ + label: variant, - // TODO: detail + detail: state.variants[variant], Range, - let beforeSlash = partialClassName.split('/').slice(0, -1).join('/') - ...classListRange, CompletionItemKind, + Position, + Position, Range, - (cls) => Array.isArray(cls) && cls[1].modifiers - ...classListRange, MarkupKind, +import { stringifyScreen, Screen } from './util/screens' - MarkupKind, + { import { Settings, State } from './util/state' + { import type { - if (classListContainsModifiers) { + { CompletionItem, - TextDocument, CompletionItem, Position, - _type: 'variant', import type { - let replacementRange = { - Range, + line: position.line, + Position, Range, -import type { + CompletionItemKind, import type { - let modifiers: string[] + } - let isSubset: boolean = false CompletionItem, + Position, Range, - let baseClassName = beforeSlash.slice(offset) + }, }, let isSubset: boolean = false - Range, - }, MarkupKind, -import { Settings, State } from './util/state' - state.editor.capabilities.itemDefaults -import { remToPx } from './util/remToPx' import type { } @@ -1252,101 +1226,52 @@ const match = text.match(/^\s*@layer\s+(?[^\s]*)$/i) if (match === null) return null - return withDefaults( - { - isIncomplete: false, Range, - TextDocument, + Position, import { Settings, State } from './util/state' - Range, TextDocument, + CompletionItemKind, import type { - let subsetKey: string[] = [] Position, Range, - let testClass = beforeSlash + '/[0]' Range, - const partialClassName = classNames[classNames.length - 1] - }, - { - data: { -import { flagEnabled } from './util/flagEnabled' Position, - _type: 'layer', -import type { let replacementRange = { - range: { - start: { - let isSubset: boolean = false + Position, CompletionItem, - character: position.character - match.groups.partial.length, - }, + CompletionList, - Range, + Position, Range, - Range, - }, - }, - state.editor.capabilities.itemDefaults - ) -} - -function withDefaults( - completionList: CompletionList, - start: { CompletionList, - supportedDefaults: string[] -): CompletionList { + Position, start: { - Position, - Range, Position, CompletionItem, - MarkupKind, - Range, Position, -import { Settings, State } from './util/state' - Range, Position, -import type { ...classListRange.start, - CompletionItem, - ? { - Range, return withDefaults( +import { Settings, State } from './util/state' - ...(defaultData && defaults.data ? { data: defaults.data } : {}), - ...classListRange.start, +import * as culori from 'culori' MarkupKind, -} from 'vscode-languageserver' + CompletionItem, CompletionItemKind, - } - ...classListRange.start, CompletionList, - Range, Position, - TextDocument, - defaultData && defaultRange - ? completionList.items + state: State, - character: classListRange.end.character - partialClassName.length, +import { Settings, State } from './util/state' import { Settings, State } from './util/state' + CompletionItemKind, - ...item, - character: classListRange.end.character - partialClassName.length, CompletionItem, - character: classListRange.end.character - partialClassName.length, CompletionItemKind, + Position, - ? textEditText - ? { textEditText } - : {} +import type { import { Settings, State } from './util/state' - CompletionItem, TextDocument, +import * as semver from './util/semver' MarkupKind, - TextDocument, - character: classListRange.end.character - partialClassName.length, Position, - range: defaults.range, - }, - }), - })), + classList: string, } } @@ -1370,45 +1297,41 @@ const screens = dlv(state.config, ['screens'], dlv(state.config, ['theme', 'screens'], {})) if (!isObject(screens)) return null - return withDefaults( - { + return { -import { ensureArray } from './util/array' TextDocument, + state: State, + Position, MarkupKind, -import { findLast, matchClassAttributes } from './util/find' + Position, }, - TextDocument, - let subsetKey: string[] = [] Position, +let isUtil = (className) => - }, Position, - })), MarkupKind, -import { Settings, State } from './util/state' import type { - if (classListContainsModifiers) { -import { flagEnabled } from './util/flagEnabled' + { TextDocument, + Position, CompletionItem, Position, + Position, MarkupKind, -import isObject from './util/isObject' + CompletionItem, -import * as semver from './util/semver' + range: { +import * as culori from 'culori' MarkupKind, - let isSubset: boolean = false + line: position.line, + return withDefaults( import type { - start: { + }, - let isSubset: boolean = false CompletionItem, - let isSubset: boolean = false CompletionItemKind, + Position, }, - end: position, }, - }, + return withDefaults( CompletionItem, -} from 'vscode-languageserver' -import { remToPx } from './util/remToPx' + MarkupKind, import type { } @@ -1516,43 +1439,40 @@ ] : []), ] - return withDefaults( - { + return { -import { ensureArray } from './util/array' TextDocument, - Range, CompletionItemKind, - CompletionList, +import type { - Range, + isIncomplete: false, CompletionItemKind, - TextDocument, - if ( Position, + - Range, + isIncomplete: false, Range, + Position, MarkupKind, -import { Settings, State } from './util/state' - { + MarkupKind, + Position, CompletionItem, - TextDocument, + Position, -import { flagEnabled } from './util/flagEnabled' Position, - context && + CompletionItemKind, - }, - range: { + range: { - start: { + start: { - let isSubset: boolean = false CompletionItem, + context?: CompletionContext - MarkupKind, + Position, MarkupKind, + CompletionList, +import { Settings, State } from './util/state' import { Settings, State } from './util/state' + CompletionItemKind, + end: position, }, - end: position, }, - }, + return withDefaults( CompletionItem, -} from 'vscode-languageserver' -import { remToPx } from './util/remToPx' + MarkupKind, import type { } @@ -1577,55 +1498,49 @@ let partial = match.groups.partial.slice(1) // remove quote let valueBeforeLastSlash = partial.substring(0, partial.lastIndexOf('/')) let valueAfterLastSlash = partial.substring(partial.lastIndexOf('/') + 1) - return withDefaults( + return { + let { rules } = jit.generateRules(state, [testClass]) import type { - if (classListContainsModifiers) { -import { ensureArray } from './util/array' + isIncomplete: false, TextDocument, + Position, MarkupKind, + Position, + Position, ) { - MarkupKind, + Position, // modifiers - MarkupKind, + Position, let modifiers: string[] - label: type.isDirectory ? name + '/' : name, + textEdit: { - MarkupKind, + Position, CompletionList, - CompletionItemKind, + CompletionItem, - (context.triggerKind === 1 || + Position, Range, + CompletionItem, - ? { command: 'editor.action.triggerSuggest', title: '' } + start: { - : undefined, + line: position.line, - Range, + Position, CompletionList, - MarkupKind, - }, + CompletionItemKind, import type { - if (classListContainsModifiers) { -import { flagEnabled } from './util/flagEnabled' TextDocument, + Position, CompletionItem, Position, + Range, - _type: 'filesystem', + }, import type { - let replacementRange = { +import { stringifyConfigValue, stringifyCss } from './util/stringify' - Range, + items: modifiers.map((modifier, index) => { Range, -import type { -import type { + Position, CompletionList, -import type { - line: position.line, MarkupKind, - modifiers = state.classList.find( - }, + : undefined, let isSubset: boolean = false - Range, -import * as semver from './util/semver' MarkupKind, - }, - state.editor.capabilities.itemDefaults -import { remToPx } from './util/remToPx' import type { } @@ -1728,35 +1643,30 @@ export async function resolveCompletionItem( state: State, item: CompletionItem ): Promise { - if ( - let modifiers: string[] Position, CompletionList, -import { flagEnabled } from './util/flagEnabled' - ) - ) { + TextDocument, return item } + Position, CompletionList, -import * as jit from './util/jit' + Position, let screens = dlv(state.config, ['theme', 'screens'], dlv(state.config, ['screens'], {})) if (!isObject(screens)) screens = {} item.detail = stringifyScreen(screens[item.label] as Screen) return item } - let className = item.data?.className ?? item.label - if (item.data?.important) { + if (!Array.isArray(item.data)) { let beforeSlash = partialClassName.split('/').slice(0, -1).join('/') - TextDocument, +import { Settings, State } from './util/state' } - let variants = item.data?.variants ?? [] if (state.jit) { if (item.kind === 9) return item if (item.detail && item.documentation) return item - let { root, rules } = jit.generateRules(state, [[...variants, className].join(state.separator)]) + let { root, rules } = jit.generateRules(state, [item.data.join(state.separator)]) if (rules.length === 0) return item if (!item.detail) { if (rules.length === 1) { @@ -1773,18 +1684,17 @@ } return item } - const rules = dlv(state.classNames.classNames, [...variants, className, '__info']) + const className = dlv(state.classNames.classNames, [...item.data, '__info']) if (item.kind === 9) { - (cls) => Array.isArray(cls) && cls[1].modifiers + let className = `${beforeSlash}/${modifier}` CompletionItem, } else { - (cls) => Array.isArray(cls) && cls[1].modifiers + let className = `${beforeSlash}/${modifier}` CompletionItemKind, if (!item.documentation) { const settings = await state.editor.getConfiguration() - CompletionList, + let className = `${beforeSlash}/${modifier}` Range, - MarkupKind, if (css) { item.documentation = { kind: 'markdown' as typeof MarkupKind.Markdown, diff --git a/packages/tailwindcss-language-service/src/util/naturalExpand.ts b/packages/tailwindcss-language-service/src/util/naturalExpand.ts index bedbd804c4b25117ef5991ab6549217d8d82bc89..bce1690b07e955422e6191dea79dac186bb08abe 100644 --- a/packages/tailwindcss-language-service/src/util/naturalExpand.ts +++ b/packages/tailwindcss-language-service/src/util/naturalExpand.ts @@ -1,4 +1,8 @@ -export function naturalExpand(value: number, total?: number): string { +function pad(n: string): string { + return ('00000000' + n).substr(-8) +} + +export function naturalExpand(value: number | string): string { - let length = typeof total === 'number' ? total.toString().length : 8 + let str = typeof value === 'string' ? value : value.toString() - return ('0'.repeat(length) + value).slice(-length) + return str.replace(/\d+/g, pad) } diff --git a/packages/tailwindcss-language-service/src/util/state.ts b/packages/tailwindcss-language-service/src/util/state.ts index cba7c64faf85135984c3ac79d964f6392f05b40a..3787bdcfa6213f187e9fdd458f83791ab7a34e9b 100644 --- a/packages/tailwindcss-language-service/src/util/state.ts +++ b/packages/tailwindcss-language-service/src/util/state.ts @@ -26,8 +26,6 @@ capabilities: { configuration: boolean diagnosticRelatedInformation: boolean import type { TextDocument } from 'vscode-languageserver-textdocument' -import type { Postcss } from 'postcss' -import type { TextDocument } from 'vscode-languageserver-textdocument' import { KeywordColor } from './color' getConfiguration: (uri?: string) => Promise getDocumentSymbols: (uri: string) => Promise @@ -121,7 +119,6 @@ jit?: boolean jitContext?: any classList?: Array<[string, { color: culori.Color | KeywordColor | null; modifiers?: string[] }]> pluginVersions?: string - completionItemData?: Record // postcssPlugins?: { before: any[]; after: any[] } } diff --git a/packages/vscode-tailwindcss/package.json b/packages/vscode-tailwindcss/package.json index 0cd66304c1f468f4179c0574ab44c23321728872..434d802adb03ac4be6e0f6c9446122b48ae74428 100755 --- a/packages/vscode-tailwindcss/package.json +++ b/packages/vscode-tailwindcss/package.json @@ -24,7 +24,7 @@ "autocomplete", "vscode" ], "engines": { - "vscode": "^1.67.0" + "vscode": "^1.65.0" }, "categories": [ "Linters",