Skip to content

Commit a2fb0dc

Browse files
feat(vscode): find all references support (#4353)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 51df0e7 commit a2fb0dc

File tree

11 files changed

+283
-99
lines changed

11 files changed

+283
-99
lines changed

.github/workflows/autofix.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ jobs:
3030
env:
3131
CYPRESS_INSTALL_BINARY: 0
3232

33-
- name: Lint
34-
run: nr lint --fix
33+
- run: nr lint --fix
34+
35+
- run: nr prepare
3536

3637
- uses: autofix-ci/action@v1

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"private": true,
66
"packageManager": "pnpm@9.15.1",
77
"scripts": {
8-
"postinstall": "esno scripts/prepare.ts",
8+
"prepare": "esno scripts/prepare.ts",
99
"taze": "taze minor -wIr && pnpm -r --parallel run update-post",
1010
"bench": "npm -C bench run bench",
1111
"build": "rimraf packages/*/dist --glob && esno scripts/copy-files.ts && pnpm -r --filter=./packages/* run build && pnpm -r run build-post && esno scripts/postbuild.ts",

packages/core/src/types.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -678,16 +678,30 @@ export interface CliOptions {
678678
}
679679

680680
export interface UnocssPluginContext<Config extends UserConfig = UserConfig> {
681+
/**
682+
* Singleton promise for config loading
683+
*/
681684
ready: Promise<LoadConfigResult<Config>>
685+
/**
686+
* The UnoCSS generator instance. Should be used after `ready` resolved.
687+
*/
682688
uno: UnoGenerator
683-
/** All tokens scanned */
689+
/**
690+
* All tokens scanned
691+
*/
684692
tokens: Set<string>
685-
/** Map for all module's raw content */
693+
/**
694+
* Map for all module's raw content
695+
*/
686696
modules: BetterMap<string, string>
687-
/** Module IDs that been affected by UnoCSS */
697+
/**
698+
* Module IDs that been affected by UnoCSS
699+
*/
688700
affectedModules: Set<string>
689701

690-
/** Pending promises */
702+
/**
703+
* Pending promises
704+
*/
691705
tasks: Promise<any>[]
692706
/**
693707
* Await all pending tasks

packages/vscode/src/annotation.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import type { ContextLoader } from './contextLoader'
33
import path from 'path'
44
import { DecorationRangeBehavior, MarkdownString, Range, window, workspace } from 'vscode'
55
import { useConfigurations } from './configuration'
6-
import { defaultIdeMatchExclude, defaultIdeMatchInclude, getMatchedPositionsFromCode, INCLUDE_COMMENT_IDE, isCssId } from './integration'
6+
import { getMatchedPositionsFromDoc } from './getMatched'
7+
import { INCLUDE_COMMENT_IDE, isCssId } from './integration'
78
import { log } from './log'
89
import { getColorString, getPrettiedMarkdown, throttle } from './utils'
910

@@ -13,13 +14,16 @@ export async function registerAnnotations(
1314
ext: ExtensionContext,
1415
) {
1516
const { configuration, watchChanged, disposable } = useConfigurations(ext)
16-
const disposals: Disposable[] = []
1717

18-
watchChanged(['underline', 'colorPreview', 'remToPxPreview', 'remToPxRatio', 'strictAnnotationMatch'], () => {
19-
updateAnnotation()
20-
})
18+
const disposals: Disposable[] = [
19+
disposable,
20+
]
2121

22-
disposals.push(disposable)
22+
disposals.push(
23+
watchChanged(['underline', 'colorPreview', 'remToPxPreview', 'remToPxRatio', 'strictAnnotationMatch'], () => {
24+
updateAnnotation()
25+
}),
26+
)
2327

2428
disposals.push(workspace.onDidSaveTextDocument(async (doc) => {
2529
const id = doc.uri.fsPath
@@ -105,14 +109,7 @@ export async function registerAnnotations(
105109
? configuration.remToPxRatio
106110
: -1
107111

108-
const options = configuration.strictAnnotationMatch
109-
? {
110-
includeRegex: defaultIdeMatchInclude,
111-
excludeRegex: defaultIdeMatchExclude,
112-
}
113-
: undefined
114-
115-
const positions = await getMatchedPositionsFromCode(ctx.uno, code, id, options)
112+
const positions = await getMatchedPositionsFromDoc(ctx.uno, doc)
116113
const isAttributify = ctx.uno.config.presets.some(i => i.name === '@unocss/preset-attributify')
117114

118115
const ranges: DecorationOptions[] = (

packages/vscode/src/autocomplete.ts

Lines changed: 21 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,13 @@ import type { UnocssPluginContext, UnoGenerator } from '@unocss/core'
33
import type { CompletionItemProvider, Disposable, ExtensionContext } from 'vscode'
44
import type { ContextLoader } from './contextLoader'
55
import { createAutocomplete } from '@unocss/autocomplete'
6-
import { CompletionItem, CompletionItemKind, CompletionList, languages, MarkdownString, Range, window, workspace } from 'vscode'
7-
import { useConfigurations } from './configuration'
6+
import { CompletionItem, CompletionItemKind, CompletionList, languages, MarkdownString, Range, window } from 'vscode'
7+
import { getLanguageIds, useConfigurations } from './configuration'
8+
import { delimiters } from './constants'
89
import { isCssId } from './integration'
910
import { log } from './log'
1011
import { getColorString, getCSS, getPrettiedCSS, getPrettiedMarkdown, shouldProvideAutocomplete } from './utils'
1112

12-
const defaultLanguageIds = [
13-
'erb',
14-
'haml',
15-
'hbs',
16-
'html',
17-
'css',
18-
'postcss',
19-
'javascript',
20-
'javascriptreact',
21-
'markdown',
22-
'ejs',
23-
'php',
24-
'svelte',
25-
'typescript',
26-
'typescriptreact',
27-
'vue-html',
28-
'vue',
29-
'sass',
30-
'scss',
31-
'less',
32-
'stylus',
33-
'astro',
34-
'rust',
35-
]
36-
const delimiters = ['-', ':', ' ', '"', '\'']
37-
3813
class UnoCompletionItem extends CompletionItem {
3914
uno: UnoGenerator
4015
value: string
@@ -50,7 +25,6 @@ export async function registerAutoComplete(
5025
contextLoader: ContextLoader,
5126
ext: ExtensionContext,
5227
) {
53-
const allLanguages = await languages.getLanguages()
5428
const autoCompletes = new Map<UnocssPluginContext, UnocssAutocomplete>()
5529
const { configuration, watchChanged, disposable } = useConfigurations(ext)
5630

@@ -84,21 +58,6 @@ export async function registerAutoComplete(
8458
return new MarkdownString(await getPrettiedMarkdown(uno, util, remToPxRatio))
8559
}
8660

87-
function validateLanguages(targets: string[]) {
88-
const unValidLanguages: string[] = []
89-
const validLanguages = targets.filter((language) => {
90-
if (!allLanguages.includes(language)) {
91-
unValidLanguages.push(language)
92-
return false
93-
}
94-
return true
95-
})
96-
if (unValidLanguages.length)
97-
window.showWarningMessage(`These language configurations are illegal: ${unValidLanguages.join(',')}`)
98-
99-
return validLanguages
100-
}
101-
10261
const provider: CompletionItemProvider<UnoCompletionItem> = {
10362
async provideCompletionItems(doc, position) {
10463
const id = doc.uri.fsPath
@@ -176,37 +135,33 @@ export async function registerAutoComplete(
176135

177136
let completeUnregister: Disposable
178137

179-
const registerProvider = () => {
138+
const registerProvider = async () => {
180139
completeUnregister?.dispose?.()
181140

182-
const languagesIds: string[] = workspace.getConfiguration().get('unocss.languageIds') || []
183-
184-
const validLanguages = validateLanguages(languagesIds)
185-
186141
completeUnregister = languages.registerCompletionItemProvider(
187-
defaultLanguageIds.concat(validLanguages),
142+
await getLanguageIds(),
188143
provider,
189144
...delimiters,
190145
)
191146
return completeUnregister
192147
}
193148

194-
watchChanged(['languagesIds'], () => {
195-
ext.subscriptions.push(
196-
registerProvider(),
197-
)
198-
})
199-
200-
watchChanged([
201-
'matchType',
202-
'maxItems',
203-
'remToPxRatio',
204-
'remToPxPreview',
205-
], () => {
206-
autoCompletes.clear()
207-
})
208-
209149
ext.subscriptions.push(
210-
registerProvider(),
150+
watchChanged(['languagesIds'], async () => {
151+
ext.subscriptions.push(
152+
await registerProvider(),
153+
)
154+
}),
155+
156+
watchChanged([
157+
'matchType',
158+
'maxItems',
159+
'remToPxRatio',
160+
'remToPxPreview',
161+
], () => {
162+
autoCompletes.clear()
163+
}),
164+
165+
await registerProvider(),
211166
)
212167
}

packages/vscode/src/configuration.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { AutoCompleteMatchType } from '@unocss/autocomplete'
2-
import type { ExtensionContext } from 'vscode'
2+
import type { Disposable, ExtensionContext } from 'vscode'
33
import { toArray } from '@unocss/core'
4-
import { workspace } from 'vscode'
4+
import { languages, window, workspace } from 'vscode'
55
import { createNanoEvents } from '../../core/src/utils/events'
6+
import { defaultLanguageIds } from './constants'
67

78
export interface UseConfigurationOptions<Init> {
89
ext?: ExtensionContext
@@ -47,10 +48,12 @@ export function getConfigurations<Init extends Record<string, unknown>>(
4748

4849
const emitter = createNanoEvents()
4950

50-
const watchChanged = <K extends keyof Init>(key: K | K[], fn: WatchConfigurationHandler<Init, K>) => {
51+
const watchChanged = <K extends keyof Init>(key: K | K[], fn: WatchConfigurationHandler<Init, K>): Disposable => {
5152
const keys = toArray(key)
5253
const unsubscribes = keys.map(key => emitter.on(`update:${String(key)}`, fn))
53-
return () => unsubscribes.forEach(fn => fn())
54+
return {
55+
dispose: () => unsubscribes.forEach(fn => fn()),
56+
}
5457
}
5558

5659
const disposable = workspace.onDidChangeConfiguration((e) => {
@@ -105,3 +108,33 @@ export function useConfigurations(ext: ExtensionContext) {
105108
},
106109
})
107110
}
111+
112+
async function validateLanguages(targets: string[], allLanguages: string[]) {
113+
const invalidLanguages: string[] = []
114+
const validLanguages = targets.filter((language) => {
115+
if (!allLanguages.includes(language)) {
116+
invalidLanguages.push(language)
117+
return false
118+
}
119+
return true
120+
})
121+
if (invalidLanguages.length)
122+
window.showWarningMessage(`These language configurations are illegal: ${invalidLanguages.join(',')}`)
123+
124+
return validLanguages
125+
}
126+
127+
export async function getLanguageIds() {
128+
const allLanguages = await languages.getLanguages()
129+
const languagesIds: string[] = workspace.getConfiguration().get('unocss.languageIds') || []
130+
131+
return Array.from(
132+
new Set(
133+
[
134+
...defaultLanguageIds,
135+
...await validateLanguages(languagesIds, allLanguages),
136+
]
137+
.filter(i => allLanguages.includes(i)),
138+
),
139+
)
140+
}

packages/vscode/src/constants.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const defaultLanguageIds = [
2+
'erb',
3+
'haml',
4+
'hbs',
5+
'html',
6+
'css',
7+
'postcss',
8+
'javascript',
9+
'javascriptreact',
10+
'markdown',
11+
'ejs',
12+
'php',
13+
'svelte',
14+
'typescript',
15+
'typescriptreact',
16+
'vue-html',
17+
'vue',
18+
'sass',
19+
'scss',
20+
'less',
21+
'stylus',
22+
'astro',
23+
'rust',
24+
]
25+
export const delimiters = ['-', ':', ' ', '"', '\'']

packages/vscode/src/contextLoader.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export class ContextLoader {
162162
(result) => {
163163
if (result.sources.some(s => s.includes('nuxt.config')))
164164
resolveNuxtOptions(result.config)
165+
result.config.details = true
165166
},
166167
)
167168

packages/vscode/src/getMatched.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { UnoGenerator } from '@unocss/core'
2+
import { getMatchedPositionsFromCode } from '@unocss/shared-common'
3+
import { defaultIdeMatchExclude, defaultIdeMatchInclude } from '@unocss/shared-integration'
4+
import { type ExtensionContext, type TextDocument, workspace } from 'vscode'
5+
6+
const cache = new Map<string, ReturnType<typeof getMatchedPositionsFromCode>>()
7+
8+
export function registerDocumentCacheCleaner(ext: ExtensionContext) {
9+
ext.subscriptions.push(
10+
workspace.onDidChangeTextDocument((e) => {
11+
cache.delete(e.document.uri.fsPath)
12+
}),
13+
)
14+
}
15+
16+
export function getMatchedPositionsFromDoc(
17+
uno: UnoGenerator,
18+
doc: TextDocument,
19+
force = false,
20+
) {
21+
const id = doc.uri.fsPath
22+
if (force)
23+
cache.delete(id)
24+
25+
if (cache.has(id))
26+
return cache.get(id)!
27+
28+
const options = workspace.getConfiguration('unocss').get('strictAnnotationMatch')
29+
? {
30+
includeRegex: defaultIdeMatchInclude,
31+
excludeRegex: defaultIdeMatchExclude,
32+
}
33+
: undefined
34+
35+
const result = getMatchedPositionsFromCode(
36+
uno,
37+
doc.getText(),
38+
id,
39+
options,
40+
)
41+
42+
cache.set(id, result)
43+
return result
44+
}

0 commit comments

Comments
 (0)