Skip to content

Commit

Permalink
feat: Completion only works in template attr
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon-He95 committed Jul 6, 2023
1 parent 9ef3546 commit b390110
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 27 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"@unocss/transformer-directives": "^0.53.3",
"@unocss/transformer-variant-group": "^0.53.3",
"@vscode-use/utils": "^0.0.28",
"@vue/compiler-sfc": "^3.3.4",
"bumpp": "^9.1.0",
"eslint": "^8.37.0",
"esno": "^0.16.3",
Expand Down
116 changes: 109 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 9 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@ import { findUp } from 'find-up'
import { rules, transform } from './transform'
import { getUnoCompletions } from './search'
import { CssToUnocssProcess } from './process'
import { LRUCache1, addCacheReact, addCacheVue, cacheMap, getMultipedUnocssText, hasFile, highlight, resetDecorationType, style, transformUnocssBack, unoToCssDecorationType } from './utils'
import { LRUCache1, addCacheReact, addCacheVue, cacheMap, getMultipedUnocssText, hasFile, highlight, parser, resetDecorationType, style, transformUnocssBack, unoToCssDecorationType } from './utils'

const toUnocssMap = new LRUCache1(5000)

export async function activate(context: vscode.ExtensionContext) {
const activeTextEditor = vscode.window.activeTextEditor
if (!activeTextEditor)
return

const pkgs = await hasFile(['**/package.json'])
if (!pkgs.some(pkg => pkg.includes('unocss')))
return

let unoToCssToggle = true
const styleReg = /style="([^"]+)"/
const document = activeTextEditor.document
Expand Down Expand Up @@ -435,15 +433,20 @@ export async function activate(context: vscode.ExtensionContext) {
if (!completions.length) {
getUnoCompletions(filepath).then((res: any) => {
completions = res
unoCompletionsMap = completions.map(([content, detail]: any) => createCompletionItem({ content, detail }))
unoCompletionsMap = completions.map(([content, detail]: any) => createCompletionItem({ content, detail, type: undefined }))
})
}
hasUnoConfig = filepath
})
}

// 如果是unocss环境下,给出一些预设提醒
context.subscriptions.push(registerCompletionItemProvider(['javascript', 'javascriptreact', 'svelte', 'solid', 'typescriptreact', 'html', 'vue', 'css'], () => hasUnoConfig && unoCompletionsMap, ['"', '\'', ' ']))
context.subscriptions.push(registerCompletionItemProvider(['javascript', 'javascriptreact', 'svelte', 'solid', 'typescriptreact', 'html', 'vue', 'css'], (document, position) => {
if (!hasUnoConfig)
return
const data = parser(document.getText(), position)
if (data?.type === 'props' || data === true)
return unoCompletionsMap
}, ['"', '\'', ' ']))
}

export function deactivate() {
Expand Down
89 changes: 75 additions & 14 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import fg from 'fast-glob'
import { getPosition } from '@vscode-use/utils'
import { findUp } from 'find-up'
import * as vscode from 'vscode'
import { parse } from '@vue/compiler-sfc'

export type CssType = 'less' | 'scss' | 'css' | 'stylus'
export function getCssType(filename: string) {
Expand Down Expand Up @@ -351,20 +352,80 @@ export function highlight(realRangeMap: vscode.Range[]) {
editor.edit(() => editor.setDecorations(unoToCssDecorationType, realRangeMap))
}

// export function getPosition(content: string, pos: number) {
// const contents = content.split('\n')
// let num = 0
// for (let i = 0; i < contents.length; i++) {
// const len = contents[i].length
// if ((num <= pos) && (pos <= (num + len))) {
// return {
// line: i,
// character: pos - num,
// }
// }
// num += contents[i].length + (i === 0 ? 0 : 1)
// }
// }
export function resetDecorationType() {
return vscode.window.activeTextEditor?.setDecorations(unoToCssDecorationType, [])
}

// 引入vue-parser只在template中才处理一些逻辑
export function parser(code: string, position: vscode.Position) {
const entry = vscode.window.activeTextEditor?.document.uri.fsPath
if (!entry)
return
const suffix = entry.slice(entry.lastIndexOf('.') + 1)
if (!suffix)
return
if (suffix === 'vue')
return transformVue(code, position)

return true
}

export function transformVue(code: string, position: vscode.Position) {
const {
descriptor: { template },
errors,
} = parse(code)
if (errors.length || !template)
return
if (!isInPosition(template.loc, position))
return
// 在template中
const { ast } = template
return dfs(ast.children, position)
}

function dfs(children: any, position: vscode.Position) {
for (const child of children) {
const { loc, tag, props, children } = child
if (!isInPosition(loc, position))
continue
if (props && props.length) {
for (const prop of props) {
if (isInPosition(prop.loc, position)) {
return {
tag,
prop,
props,
type: 'props',
}
}
}
}
if (children && children.length) {
const result = dfs(children, position) as any
if (result)
return result
}
else {
return {
type: 'text',
}
}
}
}

function isInPosition(loc: any, position: vscode.Position) {
const { start, end } = loc
const { line: startLine, column: startcharacter } = start
const { line: endLine, column: endcharacter } = end
const { line, character } = position
if (line + 1 === startLine && character < startcharacter)
return
if (line + 1 === endLine && character > endcharacter)
return
if (line + 1 < startLine)
return
if (line + 1 > endLine)
return
return true
}

0 comments on commit b390110

Please sign in to comment.