[JIT] add opacity modifier completions

master
Brad Cornes 2021-05-18 12:22:18 +01:00
parent 1d0af70caa
commit 5cf4b1717d
2 changed files with 77 additions and 8 deletions

View File

@ -7,6 +7,7 @@ import type {
CompletionList, CompletionList,
TextDocument, TextDocument,
Position, Position,
CompletionContext,
} from 'vscode-languageserver' } from 'vscode-languageserver'
const dlv = require('dlv') const dlv = require('dlv')
import removeMeta from './util/removeMeta' import removeMeta from './util/removeMeta'
@ -43,7 +44,8 @@ export function completionsFromClassList(
classList: string, classList: string,
classListRange: Range, classListRange: Range,
filter?: (item: CompletionItem) => boolean, filter?: (item: CompletionItem) => boolean,
document?: TextDocument document?: TextDocument,
context?: CompletionContext
): CompletionList { ): CompletionList {
let classNames = classList.split(/[\s+]/) let classNames = classList.split(/[\s+]/)
const partialClassName = classNames[classNames.length - 1] const partialClassName = classNames[classNames.length - 1]
@ -62,6 +64,58 @@ export function completionsFromClassList(
} }
if (state.jit) { if (state.jit) {
if (
context &&
(context.triggerKind === 1 ||
(context.triggerKind === 2 && context.triggerCharacter === '/')) &&
partialClassName.includes('/')
) {
let beforeSlash = partialClassName.split('/').slice(0, -1).join('/')
let testClass = beforeSlash + '/[0]'
let { rules } = jit.generateRules(state, [testClass])
if (rules.length > 0) {
let opacities = dlv(state.config, 'theme.opacity', {})
if (!isObject(opacities)) {
opacities = {}
}
return {
isIncomplete: false,
items: Object.keys(opacities).map((opacity, index) => {
let className = `${beforeSlash}/${opacity}`
let kind: CompletionItemKind = 21
let documentation: string = null
const color = getColor(state, className)
if (color !== null) {
kind = 16
if (typeof color !== 'string') {
documentation = color.toRgbString().replace(/(^rgba\([^)]+) 0\)$/, '$1 0.001)')
}
}
return {
label: opacity,
detail: stringifyConfigValue(opacities[opacity]),
documentation,
kind,
sortText: naturalExpand(index),
data: [className],
textEdit: {
newText: opacity,
range: {
...replacementRange,
start: {
...replacementRange.start,
character: replacementRange.start.character + beforeSlash.length + 1,
},
},
},
}
}),
}
}
}
let allVariants = Object.keys(state.variants) let allVariants = Object.keys(state.variants)
let { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName) let { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName)
@ -256,7 +310,8 @@ export function completionsFromClassList(
function provideClassAttributeCompletions( function provideClassAttributeCompletions(
state: State, state: State,
document: TextDocument, document: TextDocument,
position: Position position: Position,
context?: CompletionContext
): CompletionList { ): CompletionList {
let str = document.getText({ let str = document.getText({
start: { line: Math.max(position.line - 10, 0), character: 0 }, start: { line: Math.max(position.line - 10, 0), character: 0 },
@ -299,7 +354,8 @@ function provideClassAttributeCompletions(
end: position, end: position,
}, },
undefined, undefined,
document document,
context
) )
} }
} catch (_) {} } catch (_) {}
@ -417,10 +473,11 @@ function provideAtApplyCompletions(
function provideClassNameCompletions( function provideClassNameCompletions(
state: State, state: State,
document: TextDocument, document: TextDocument,
position: Position position: Position,
context?: CompletionContext
): CompletionList { ): CompletionList {
if (isHtmlContext(state, document, position) || isJsContext(state, document, position)) { if (isHtmlContext(state, document, position) || isJsContext(state, document, position)) {
return provideClassAttributeCompletions(state, document, position) return provideClassAttributeCompletions(state, document, position, context)
} }
if (isCssContext(state, document, position)) { if (isCssContext(state, document, position)) {
@ -925,11 +982,16 @@ async function provideEmmetCompletions(
}) })
} }
export async function doComplete(state: State, document: TextDocument, position: Position) { export async function doComplete(
state: State,
document: TextDocument,
position: Position,
context?: CompletionContext
) {
if (state === null) return { items: [], isIncomplete: false } if (state === null) return { items: [], isIncomplete: false }
const result = const result =
provideClassNameCompletions(state, document, position) || provideClassNameCompletions(state, document, position, context) ||
provideCssHelperCompletions(state, document, position) || provideCssHelperCompletions(state, document, position) ||
provideCssDirectiveCompletions(state, document, position) || provideCssDirectiveCompletions(state, document, position) ||
provideScreenDirectiveCompletions(state, document, position) || provideScreenDirectiveCompletions(state, document, position) ||
@ -958,8 +1020,13 @@ export async function resolveCompletionItem(
return item return item
} }
if (!Array.isArray(item.data)) {
return item
}
if (state.jit) { if (state.jit) {
if (item.kind === 9) return item if (item.kind === 9) return item
if (item.detail && item.documentation) return item
let { root, rules } = jit.generateRules(state, [item.data.join(state.separator)]) let { root, rules } = jit.generateRules(state, [item.data.join(state.separator)])
if (rules.length === 0) return item if (rules.length === 0) return item
if (!item.detail) { if (!item.detail) {

View File

@ -85,6 +85,8 @@ const TRIGGER_CHARACTERS = [
'[', '[',
// JIT "important" prefix // JIT "important" prefix
'!', '!',
// JIT opacity modifiers
'/',
] as const ] as const
const colorNames = Object.keys(namedColors) const colorNames = Object.keys(namedColors)
@ -748,7 +750,7 @@ async function createProjectService(
if (!state.enabled) return null if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri) let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null if (!document) return null
return doComplete(state, document, params.position) return doComplete(state, document, params.position, params.context)
}, },
onCompletionResolve(item: CompletionItem): Promise<CompletionItem> { onCompletionResolve(item: CompletionItem): Promise<CompletionItem> {
if (!state.enabled) return null if (!state.enabled) return null