tailwind-ctp-intellisense @master -
refs -
log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
Merge branch 'next' into diagnostics
4 changed files, 132 additions(+), 97 deletions(-)
diff --git a/src/class-names/extractClassNames.js b/src/class-names/extractClassNames.js
index df4559939aba242c977b6be4adea01cfe05adb47..2aa426b22ab4a62489155861c15d87c5a0f3ce69 100644
--- a/src/class-names/extractClassNames.js
+++ b/src/class-names/extractClassNames.js
@@ -46,99 +46,102 @@
return classNames
}
-async function process(ast) {
+async function process(groups) {
const tree = {}
const commonContext = {}
- ast.root.walkRules((rule) => {
- const classNames = getClassNamesFromSelector(rule.selector)
+ groups.forEach((group) => {
+ group.root.walkRules((rule) => {
+ const classNames = getClassNamesFromSelector(rule.selector)
- const decls = {}
- rule.walkDecls((decl) => {
- if (decls[decl.prop]) {
- decls[decl.prop] = [
- ...(Array.isArray(decls[decl.prop])
- ? decls[decl.prop]
- : [decls[decl.prop]]),
- decl.value,
- ]
- } else {
- decls[decl.prop] = decl.value
- }
- })
+ const decls = {}
+ rule.walkDecls((decl) => {
+ if (decls[decl.prop]) {
+ decls[decl.prop] = [
+ ...(Array.isArray(decls[decl.prop])
+ ? decls[decl.prop]
+ : [decls[decl.prop]]),
+ decl.value,
+ ]
+ } else {
+ decls[decl.prop] = decl.value
+ }
+ })
- let p = rule
- const keys = []
- while (p.parent.type !== 'root') {
- p = p.parent
- if (p.type === 'atrule') {
- keys.push(`@${p.name} ${p.params}`)
+ let p = rule
+ const keys = []
+ while (p.parent.type !== 'root') {
+ p = p.parent
+ if (p.type === 'atrule') {
+ keys.push(`@${p.name} ${p.params}`)
+ }
}
- }
- for (let i = 0; i < classNames.length; i++) {
- const context = keys.concat([])
- const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__')
- const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
- const index = []
+ for (let i = 0; i < classNames.length; i++) {
+ const context = keys.concat([])
+ const baseKeys = classNames[i].className.split('__TAILWIND_SEPARATOR__')
+ const contextKeys = baseKeys.slice(0, baseKeys.length - 1)
+ const index = []
- const existing = dlv(tree, baseKeys)
- if (typeof existing !== 'undefined') {
- if (Array.isArray(existing)) {
- const scopeIndex = existing.findIndex(
- (x) =>
- x.__scope === classNames[i].scope &&
- arraysEqual(existing.__context, context)
- )
- if (scopeIndex > -1) {
- keys.unshift(scopeIndex)
- index.push(scopeIndex)
+ const existing = dlv(tree, baseKeys)
+ if (typeof existing !== 'undefined') {
+ if (Array.isArray(existing)) {
+ const scopeIndex = existing.findIndex(
+ (x) =>
+ x.__scope === classNames[i].scope &&
+ arraysEqual(existing.__context, context)
+ )
+ if (scopeIndex > -1) {
+ keys.unshift(scopeIndex)
+ index.push(scopeIndex)
+ } else {
+ keys.unshift(existing.length)
+ index.push(existing.length)
+ }
} else {
- keys.unshift(existing.length)
- index.push(existing.length)
- }
- } else {
- if (
- existing.__scope !== classNames[i].scope ||
- !arraysEqual(existing.__context, context)
- ) {
- dset(tree, baseKeys, [existing])
- keys.unshift(1)
- index.push(1)
+ if (
+ existing.__scope !== classNames[i].scope ||
+ !arraysEqual(existing.__context, context)
+ ) {
+ dset(tree, baseKeys, [existing])
+ keys.unshift(1)
+ index.push(1)
+ }
}
}
- }
- if (classNames[i].__rule) {
- dset(tree, [...baseKeys, ...index, '__rule'], true)
+ if (classNames[i].__rule) {
+ dset(tree, [...baseKeys, ...index, '__rule'], true)
+ dset(tree, [...baseKeys, ...index, '__source'], group.source)
- dsetEach(tree, [...baseKeys, ...index], decls)
- }
- if (classNames[i].__pseudo) {
- dset(tree, [...baseKeys, '__pseudo'], classNames[i].__pseudo)
- }
- dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
- dset(
- tree,
- [...baseKeys, ...index, '__context'],
- context.concat([]).reverse()
- )
+ dsetEach(tree, [...baseKeys, ...index], decls)
+ }
+ if (classNames[i].__pseudo) {
+ dset(tree, [...baseKeys, '__pseudo'], classNames[i].__pseudo)
+ }
+ dset(tree, [...baseKeys, ...index, '__scope'], classNames[i].scope)
+ dset(
+ tree,
+ [...baseKeys, ...index, '__context'],
+ context.concat([]).reverse()
+ )
- // common context
- if (classNames[i].__pseudo) {
- context.push(...classNames[i].__pseudo)
- }
+ // common context
+ if (classNames[i].__pseudo) {
+ context.push(...classNames[i].__pseudo)
+ }
- for (let i = 0; i < contextKeys.length; i++) {
- if (typeof commonContext[contextKeys[i]] === 'undefined') {
- commonContext[contextKeys[i]] = context
- } else {
- commonContext[contextKeys[i]] = intersection(
- commonContext[contextKeys[i]],
- context
- )
+ for (let i = 0; i < contextKeys.length; i++) {
+ if (typeof commonContext[contextKeys[i]] === 'undefined') {
+ commonContext[contextKeys[i]] = context
+ } else {
+ commonContext[contextKeys[i]] = intersection(
+ commonContext[contextKeys[i]],
+ context
+ )
+ }
}
}
- }
+ })
})
return { classNames: tree, context: commonContext }
diff --git a/src/class-names/index.js b/src/class-names/index.js
index 1e2d3e5fd54fe7bf1452d8893f155532686fa118..62d478d3f212678d9eaba2d53ffcaabcc38261f7 100644
--- a/src/class-names/index.js
+++ b/src/class-names/index.js
@@ -83,12 +83,16 @@ throw new TailwindConfigError(error)
}
hook.unwatch()
- const ast = await postcss([tailwindcss(configPath)]).process(
- `
- @tailwind components;
- @tailwind utilities;
- `,
- { from: undefined }
+ const [base, components, utilities] = await Promise.all(
+ [
+ semver.gte(version, '0.99.0') ? 'base' : 'preflight',
+ 'components',
+ 'utilities',
+ ].map((group) =>
+ postcss([tailwindcss(configPath)]).process(`@tailwind ${group};`, {
+ from: undefined,
+ })
+ )
)
hook.unhook()
@@ -111,7 +115,11 @@ version,
configPath,
config: resolvedConfig,
separator: typeof userSeperator === 'undefined' ? ':' : userSeperator,
- classNames: await extractClassNames(ast),
+ classNames: await extractClassNames([
+ { root: base.root, source: 'base' },
+ { root: components.root, source: 'components' },
+ { root: utilities.root, source: 'utilities' },
+ ]),
dependencies: hook.deps,
plugins: getPlugins(config),
variants: getVariants({ config, version, postcss, browserslist }),
diff --git a/src/lsp/providers/completionProvider.ts b/src/lsp/providers/completionProvider.ts
index d7cbbef0d734dfb224fbe93edcff2f7b23a8f921..8f2c43d8325bc847a7b05a87dc180025a647f2a9 100644
--- a/src/lsp/providers/completionProvider.ts
+++ b/src/lsp/providers/completionProvider.ts
@@ -28,7 +28,8 @@
function completionsFromClassList(
state: State,
classList: string,
- classListRange: Range
+ classListRange: Range,
+ filter?: (item: CompletionItem) => boolean
): CompletionList {
let classNames = classList.split(/[\s+]/)
const partialClassName = classNames[classNames.length - 1]
@@ -68,8 +69,8 @@ }
return {
isIncomplete: false,
- items: Object.keys(isSubset ? subset : state.classNames.classNames).map(
- (className, index) => {
+ items: Object.keys(isSubset ? subset : state.classNames.classNames)
+ .map((className, index) => {
let label = className
let kind: CompletionItemKind = CompletionItemKind.Constant
let documentation: string = null
@@ -88,7 +89,7 @@ documentation = color.documentation
}
}
- return {
+ const item = {
label,
kind,
documentation,
@@ -100,8 +101,14 @@ newText: label,
range: replacementRange,
},
}
- }
- ),
+
+ if (filter && !filter(item)) {
+ return null
+ }
+
+ return item
+ })
+ .filter((item) => item !== null),
}
}
@@ -175,13 +182,29 @@ }
const classList = match.groups.classList
- return completionsFromClassList(state, classList, {
- start: {
- line: position.line,
- character: position.character - classList.length,
+ return completionsFromClassList(
+ state,
+ classList,
+ {
+ start: {
+ line: position.line,
+ character: position.character - classList.length,
+ },
+ end: position,
},
- end: position,
- })
+ (item) => {
+ // TODO: first line excludes all subtrees but there could _technically_ be
+ // valid apply-able class names in there. Will be correct in 99% of cases
+ if (item.kind === CompletionItemKind.Module) return false
+ let info = dlv(state.classNames.classNames, item.data)
+ return (
+ !Array.isArray(info) &&
+ info.__source === 'utilities' &&
+ (info.__context || []).length === 0 &&
+ (info.__pseudo || []).length === 0
+ )
+ }
+ )
}
function provideClassNameCompletions(
diff --git a/src/lsp/util/removeMeta.ts b/src/lsp/util/removeMeta.ts
index 7e379a81a580ee60a4462230a61dd134afe32e9e..dfe58d336a4d4f355d1e634175694e44d8d4e756 100644
--- a/src/lsp/util/removeMeta.ts
+++ b/src/lsp/util/removeMeta.ts
@@ -3,9 +3,10 @@
export default function removeMeta(obj: any): any {
let result = {}
for (let key in obj) {
+ if (key.substr(0, 2) === '__') continue
if (isObject(obj[key])) {
result[key] = removeMeta(obj[key])
- } else if (key.substr(0, 2) !== '__') {
+ } else {
result[key] = obj[key]
}
}