Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vscode): If uno.root is not set, auto-detection #3069

Merged
merged 14 commits into from
Sep 26, 2023
2 changes: 1 addition & 1 deletion packages/shared-integration/src/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cssIdRE } from '@unocss/core'

// picomatch patterns, used with rollup's createFilter
export const defaultPipelineExclude = [cssIdRE]
export const defaultPipelineExclude = [/[\/](node_modules|dist|\.temp|\.cache|\.vscode)[\/]/, cssIdRE]
export const defaultPipelineInclude = [/\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/]

// micromatch patterns, used in postcss plugin
Expand Down
21 changes: 21 additions & 0 deletions packages/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@
},
"description": "Project root that contains the UnoCSS configuration file"
},
"unocss.include": {
"type": [
"array",
"string"
],
"items": {
"type": "string"
},
"description": "Directory of files to be detected"
},
"unocss.exclude": {
"type": [
"array",
"string"
],
"items": {
"type": "string"
},
"description": "Directory of files not to be detected"
},
"unocss.underline": {
"type": "boolean",
"default": true,
Expand Down Expand Up @@ -108,6 +128,7 @@
"@unocss/nuxt": "workspace:*",
"@unocss/preset-uno": "workspace:*",
"esno": "^0.17.0",
"find-up": "^6.3.0",
"jiti": "^1.20.0",
"prettier": "^2.8.8",
"tsup": "^7.2.0",
Expand Down
45 changes: 26 additions & 19 deletions packages/vscode/src/annotation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path'
import type { DecorationOptions, ExtensionContext, StatusBarItem } from 'vscode'
import type { DecorationOptions, Disposable, ExtensionContext, StatusBarItem, TextEditor } from 'vscode'
import { DecorationRangeBehavior, MarkdownString, Range, window, workspace } from 'vscode'
import { INCLUDE_COMMENT_IDE, getMatchedPositionsFromCode, isCssId } from './integration'
import { log } from './log'
Expand All @@ -13,13 +13,15 @@ export async function registerAnnotations(
status: StatusBarItem,
ext: ExtensionContext,
) {
const { configuration, watchChanged } = useConfigurations(ext)

const { configuration, watchChanged, disposable } = useConfigurations(ext)
const disposals: Disposable[] = []
watchChanged(['underline', 'colorPreview', 'remToPxPreview', 'remToPxRatio'], () => {
updateAnnotation()
})

workspace.onDidSaveTextDocument(async (doc) => {
disposals.push(disposable)

disposals.push(workspace.onDidSaveTextDocument(async (doc) => {
const id = doc.uri.fsPath
const dir = path.dirname(id)

Expand All @@ -36,7 +38,7 @@ export async function registerAnnotations(
log.appendLine(String(e.stack ?? e))
}
}
})
}))

const UnderlineDecoration = window.createTextEditorDecorationType({
textDecoration: 'none; border-bottom: 1px dashed currentColor',
Expand Down Expand Up @@ -72,15 +74,15 @@ export async function registerAnnotations(
try {
const doc = editor?.document
if (!doc)
return reset()
return reset(editor)

const id = doc.uri.fsPath
if (!isSubdir(cwd, id))
return reset()
return reset(editor)

const code = doc.getText()
if (!code)
return reset()
return reset(editor)

let ctx = await contextLoader.resolveContext(code, id)
if (!ctx)
Expand All @@ -92,7 +94,7 @@ export async function registerAnnotations(
|| isCssId(id) // include css files

if (!isTarget)
return reset()
return reset(editor)

const result = await ctx.uno.generate(code, { id, preflights: false, minify: true })

Expand Down Expand Up @@ -148,30 +150,35 @@ export async function registerAnnotations(
status.text = `UnoCSS: ${result.matched.size}`
status.tooltip = new MarkdownString(`${result.matched.size} utilities used in this file`)
status.show()

function reset() {
editor?.setDecorations(UnderlineDecoration, [])
editor?.setDecorations(NoneDecoration, [])
editor?.setDecorations(colorDecoration, [])
status.hide()
}
}
catch (e: any) {
log.appendLine('⚠️ Error on annotation')
log.appendLine(String(e.stack ?? e))
}
}

function reset(editor?: TextEditor) {
editor?.setDecorations(UnderlineDecoration, [])
editor?.setDecorations(NoneDecoration, [])
editor?.setDecorations(colorDecoration, [])
status.hide()
}

const throttledUpdateAnnotation = throttle(updateAnnotation, 200)

window.onDidChangeActiveTextEditor(updateAnnotation)
workspace.onDidChangeTextDocument((e) => {
disposals.push(window.onDidChangeActiveTextEditor(updateAnnotation))
disposals.push(workspace.onDidChangeTextDocument((e) => {
if (e.document === window.activeTextEditor?.document)
throttledUpdateAnnotation()
})
}))
contextLoader.events.on('reload', async () => {
await updateAnnotation()
})

contextLoader.events.on('unload', async () => {
reset(window.activeTextEditor)
disposals.forEach(disposal => disposal.dispose())
})

await updateAnnotation()
}
10 changes: 8 additions & 2 deletions packages/vscode/src/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,20 @@ export async function registerAutoComplete(
) {
const allLanguages = await languages.getLanguages()
const autoCompletes = new Map<UnocssPluginContext, UnocssAutocomplete>()
const { configuration, watchChanged, disposable } = useConfigurations(ext)

contextLoader.events.on('contextReload', (ctx) => {
autoCompletes.delete(ctx)
})

contextLoader.events.on('contextUnload', (ctx) => {
autoCompletes.delete(ctx)
})

const { configuration, watchChanged } = useConfigurations(ext)
contextLoader.events.on('unload', (ctx) => {
autoCompletes.delete(ctx)
disposable.dispose()
})

function getAutocomplete(ctx: UnocssPluginContext) {
const cached = autoCompletes.get(ctx)
Expand Down Expand Up @@ -116,7 +122,7 @@ export async function registerAutoComplete(

const result = await autoComplete.suggestInFile(code, doc.offsetAt(position))

log.appendLine(`🤖 ${id} | ${result.suggestions.slice(0, 10).map(v => `[${v[0]}, ${v[1]}]`).join(', ')}`)
// log.appendLine(`🤖 ${id} | ${result.suggestions.slice(0, 10).map(v => `[${v[0]}, ${v[1]}]`).join(', ')}`)

if (!result.suggestions.length)
return
Expand Down
16 changes: 16 additions & 0 deletions packages/vscode/src/contextLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class ContextLoader {

public events = createNanoEvents<{
reload: () => void
unload: (context: UnocssPluginContext<UserConfig<any>>) => void
contextLoaded: (context: UnocssPluginContext<UserConfig<any>>) => void
contextReload: (context: UnocssPluginContext<UserConfig<any>>) => void
contextUnload: (context: UnocssPluginContext<UserConfig<any>>) => void
Expand Down Expand Up @@ -60,6 +61,20 @@ export class ContextLoader {
await this.loadContextInDirectory(this.cwd)
}

async unload(configDir: string) {
const context = this.contextsMap.get(configDir)
if (!context)
return

this.contextsMap.delete(configDir)

for (const [path, ctx] of this.fileContextCache) {
if (ctx === context)
this.fileContextCache.delete(path)
}
this.events.emit('unload', context)
}

async unloadContext(configDir: string) {
const context = this.contextsMap.get(configDir)
if (!context)
Expand Down Expand Up @@ -89,6 +104,7 @@ export class ContextLoader {
return cached

const load = async () => {
log.appendLine('\n-----------')
log.appendLine(`🛠 Resolving config for ${dir}`)

// @ts-expect-error support global utils
Expand Down