diff --git a/packages/tailwindcss-language-service/src/completionProvider.ts b/packages/tailwindcss-language-service/src/completionProvider.ts
index 103dba9ccf59d1827e58e5167beb03b236469b86..127d9ca8cdde9517692bd36642333a7449258d7c 100644
--- a/packages/tailwindcss-language-service/src/completionProvider.ts
+++ b/packages/tailwindcss-language-service/src/completionProvider.ts
@@ -7,6 +7,7 @@ MarkupKind,
CompletionList,
TextDocument,
Position,
+ CompletionContext,
} from 'vscode-languageserver'
const dlv = require('dlv')
import removeMeta from './util/removeMeta'
@@ -43,7 +44,8 @@ state: State,
classList: string,
classListRange: Range,
filter?: (item: CompletionItem) => boolean,
- document?: TextDocument
+ document?: TextDocument,
+ context?: CompletionContext
): CompletionList {
let classNames = classList.split(/[\s+]/)
const partialClassName = classNames[classNames.length - 1]
@@ -62,6 +64,58 @@ },
}
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 { variants: existingVariants, offset } = getVariantsFromClassName(state, partialClassName)
@@ -256,7 +310,8 @@
function provideClassAttributeCompletions(
state: State,
document: TextDocument,
- position: Position
+ position: Position,
+ context?: CompletionContext
): CompletionList {
let str = document.getText({
start: { line: Math.max(position.line - 10, 0), character: 0 },
@@ -299,7 +354,8 @@ },
end: position,
},
undefined,
- document
+ document,
+ context
)
}
} catch (_) {}
@@ -417,10 +473,11 @@
function provideClassNameCompletions(
state: State,
document: TextDocument,
- position: Position
+ position: Position,
+ context?: CompletionContext
): CompletionList {
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)) {
@@ -925,11 +982,16 @@ end: position,
})
}
-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 }
const result =
- provideClassNameCompletions(state, document, position) ||
+ provideClassNameCompletions(state, document, position, context) ||
provideCssHelperCompletions(state, document, position) ||
provideCssDirectiveCompletions(state, document, position) ||
provideScreenDirectiveCompletions(state, document, position) ||
@@ -958,8 +1020,13 @@ item.detail = stringifyScreen(screens[item.label] as Screen)
return item
}
+ if (!Array.isArray(item.data)) {
+ return item
+ }
+
if (state.jit) {
if (item.kind === 9) return item
+ if (item.detail && item.documentation) return item
let { root, rules } = jit.generateRules(state, [item.data.join(state.separator)])
if (rules.length === 0) return item
if (!item.detail) {
diff --git a/src/server.ts b/src/server.ts
index 1052baf850652f343025416c46cf2d91a810ff71..d989855fee7e6702793983f14d3e637f6020c9c0 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -85,6 +85,8 @@ // config/theme helper
'[',
// JIT "important" prefix
'!',
+ // JIT opacity modifiers
+ '/',
] as const
const colorNames = Object.keys(namedColors)
@@ -748,7 +750,7 @@ onCompletion(params: CompletionParams): Promise<CompletionList> {
if (!state.enabled) return null
let document = documentService.getDocument(params.textDocument.uri)
if (!document) return null
- return doComplete(state, document, params.position)
+ return doComplete(state, document, params.position, params.context)
},
onCompletionResolve(item: CompletionItem): Promise<CompletionItem> {
if (!state.enabled) return null