Skip to content

Commit 9db76d4

Browse files
committed
feat: displayAdditionalInfoInCompletions, disabled by default
fix: Speed up completions details resolving by vscode API (evaluate isGoodPositionForMethodCompletions once)
1 parent 8e52224 commit 9db76d4

File tree

6 files changed

+71
-10
lines changed

6 files changed

+71
-10
lines changed

src/configurationType.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,11 @@ export type Configuration = {
434434
* @default []
435435
*/
436436
'autoImport.alwaysIgnoreInImportAll': string[]
437+
/**
438+
* Enable to display additional information about source declaration in completion's documentation
439+
* For now only displays function's body
440+
* Requires symbol patching
441+
* @default false
442+
*/
443+
displayAdditionalInfoInCompletions: boolean
437444
}

src/vueVolarSupport.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default () => {
1818

1919
handler()
2020
watchExtensionSettings(['enableVueSupport'], handler)
21+
vscode.extensions.onDidChange(handler)
2122
}
2223

2324
const isConfigValueChanged = (id: string) => {

typescript/src/completionEntryDetails.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { oneOf } from '@zardoy/utils'
2-
import { isGoodPositionMethodCompletion } from './completions/isGoodPositionMethodCompletion'
32
import { getParameterListParts } from './completions/snippetForFunctionCall'
3+
import { PrevCompletionsAdditionalData } from './completionsAtPosition'
44
import { GetConfig } from './types'
55

66
export default (
@@ -10,6 +10,7 @@ export default (
1010
position: number,
1111
sourceFile: ts.SourceFile,
1212
prior: ts.CompletionEntryDetails,
13+
{ enableMethodCompletion }: PrevCompletionsAdditionalData,
1314
) => {
1415
if (
1516
c('enableMethodSnippets') &&
@@ -23,15 +24,15 @@ export default (
2324
)
2425
) {
2526
// - 1 to look for possibly previous completing item
26-
let goodPosition = isGoodPositionMethodCompletion(ts, fileName, sourceFile, position - 1, languageService, c)
2727
let rawPartsOverride: ts.SymbolDisplayPart[] | undefined
28-
if (goodPosition && prior.kind === ts.ScriptElementKind.alias) {
29-
goodPosition = prior.displayParts[5]?.text === 'method' || (prior.displayParts[4]?.kind === 'keyword' && prior.displayParts[4].text === 'function')
28+
if (enableMethodCompletion && prior.kind === ts.ScriptElementKind.alias) {
29+
enableMethodCompletion =
30+
prior.displayParts[5]?.text === 'method' || (prior.displayParts[4]?.kind === 'keyword' && prior.displayParts[4].text === 'function')
3031
const { parts, gotMethodHit, hasOptionalParameters } = getParameterListParts(prior.displayParts)
3132
if (gotMethodHit) rawPartsOverride = hasOptionalParameters ? [...parts, { kind: '', text: ' ' }] : parts
3233
}
3334
const punctuationIndex = prior.displayParts.findIndex(({ kind, text }) => kind === 'punctuation' && text === ':')
34-
if (goodPosition && punctuationIndex !== 1) {
35+
if (enableMethodCompletion && punctuationIndex !== 1) {
3536
const isParsableMethod = prior.displayParts
3637
// next is space
3738
.slice(punctuationIndex + 2)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { PrevCompletionMap } from '../completionsAtPosition'
2+
import { GetConfig } from '../types'
3+
import stringDedent from 'string-dedent'
4+
5+
export default (entries: ts.CompletionEntry[], prevCompletionsMap: PrevCompletionMap, c: GetConfig): ts.CompletionEntry[] | undefined => {
6+
if (!c('displayAdditionalInfoInCompletions')) return entries
7+
return entries.map(entry => {
8+
const symbol = entry['symbol'] as ts.Symbol | undefined
9+
if (!symbol) return entry
10+
const addNodeText = (node: ts.Node) => {
11+
let text = node.getText().trim()
12+
if (ts.isBlock(node)) text = text.slice(1, -1)
13+
try {
14+
text = stringDedent(text)
15+
} catch (e) {
16+
// ignore
17+
}
18+
prevCompletionsMap[entry.name] = {
19+
documentationAppend: `\nFunction source:\n\`\`\`ts\n${text}\n\`\`\`\n`,
20+
}
21+
}
22+
let node: ts.Node = symbol.valueDeclaration!
23+
if (!node) return entry
24+
if (ts.isVariableDeclaration(node)) node = node.initializer!
25+
if (!node) return entry
26+
if ((ts.isMethodDeclaration(node) || ts.isArrowFunction(node)) && node.body) {
27+
const { body } = node
28+
if (ts.isBlock(body) && body.statements.length === 1 && ts.isReturnStatement(body.statements[0]!)) {
29+
addNodeText(body.statements[0])
30+
} else {
31+
addNodeText(body)
32+
}
33+
}
34+
return entry
35+
})
36+
}

typescript/src/completionsAtPosition.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ import markOrRemoveGlobalCompletions from './completions/markOrRemoveGlobalLibCo
2323
import { oneOf } from '@zardoy/utils'
2424
import filterWIthIgnoreAutoImports from './completions/ignoreAutoImports'
2525
import escapeStringRegexp from 'escape-string-regexp'
26+
import addSourceDefinition from './completions/addSourceDefinition'
2627

27-
export type PrevCompletionMap = Record<string, { originalName?: string; documentationOverride?: string | ts.SymbolDisplayPart[] }>
28+
export type PrevCompletionMap = Record<string, { originalName?: string; documentationOverride?: string | ts.SymbolDisplayPart[]; documentationAppend?: string }>
29+
export type PrevCompletionsAdditionalData = {
30+
enableMethodCompletion: boolean
31+
}
2832

2933
export const getCompletionsAtPosition = (
3034
fileName: string,
@@ -40,6 +44,7 @@ export const getCompletionsAtPosition = (
4044
completions: ts.CompletionInfo
4145
/** Let default getCompletionEntryDetails to know original name or let add documentation from here */
4246
prevCompletionsMap: PrevCompletionMap
47+
prevCompletionsAdittionalData: PrevCompletionsAdditionalData
4348
}
4449
| undefined => {
4550
const prevCompletionsMap: PrevCompletionMap = {}
@@ -214,6 +219,8 @@ export const getCompletionsAtPosition = (
214219
}
215220
}
216221

222+
prior.entries = addSourceDefinition(prior.entries, prevCompletionsMap, c) ?? prior.entries
223+
217224
if (c('improveJsxCompletions') && leftNode) prior.entries = improveJsxCompletions(prior.entries, leftNode, position, sourceFile, c('jsxCompletionsMap'))
218225

219226
const processedEntries = new Set<ts.CompletionEntry>()
@@ -282,7 +289,8 @@ export const getCompletionsAtPosition = (
282289
}
283290

284291
// prevent vscode-builtin wrong insertText with methods snippets enabled
285-
if (!isGoodPositionBuiltinMethodCompletion(ts, sourceFile, position - 1, c)) {
292+
const goodPositionForMethodCompletions = isGoodPositionBuiltinMethodCompletion(ts, sourceFile, position - 1, c)
293+
if (!goodPositionForMethodCompletions) {
286294
prior.entries = prior.entries.map(item => {
287295
if (item.isSnippet) return item
288296
return { ...item, insertText: (item.insertText ?? item.name).replace(/\$/g, '\\$'), isSnippet: true }
@@ -302,6 +310,9 @@ export const getCompletionsAtPosition = (
302310
return {
303311
completions: prior,
304312
prevCompletionsMap,
313+
prevCompletionsAdittionalData: {
314+
enableMethodCompletion: goodPositionForMethodCompletions,
315+
},
305316
}
306317
}
307318

typescript/src/decorateProxy.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getCompletionsAtPosition, PrevCompletionMap } from './completionsAtPosition'
1+
import { getCompletionsAtPosition, PrevCompletionMap, PrevCompletionsAdditionalData } from './completionsAtPosition'
22
import { TriggerCharacterCommand } from './ipcTypes'
33
import { getNavTreeItems } from './getPatchedNavTree'
44
import decorateCodeActions from './codeActions/decorateProxy'
@@ -37,6 +37,7 @@ export const decorateLanguageService = (
3737
const proxy = getInitialProxy(languageService, existingProxy)
3838

3939
let prevCompletionsMap: PrevCompletionMap
40+
let prevCompletionsAdittionalData: PrevCompletionsAdditionalData
4041
// eslint-disable-next-line complexity
4142
proxy.getCompletionsAtPosition = (fileName, position, options, formatOptions) => {
4243
const updateConfigCommand = 'updateConfig'
@@ -66,14 +67,15 @@ export const decorateLanguageService = (
6667
const result = getCompletionsAtPosition(fileName, position, options, c, languageService, scriptSnapshot, formatOptions, { scriptKind })
6768
if (!result) return
6869
prevCompletionsMap = result.prevCompletionsMap
70+
prevCompletionsAdittionalData = result.prevCompletionsAdittionalData
6971
return result.completions
7072
}
7173

7274
proxy.getCompletionEntryDetails = (fileName, position, entryName, formatOptions, source, preferences, data) => {
7375
const program = languageService.getProgram()
7476
const sourceFile = program?.getSourceFile(fileName)
7577
if (!program || !sourceFile) return
76-
const { documentationOverride } = prevCompletionsMap[entryName] ?? {}
78+
const { documentationOverride, documentationAppend } = prevCompletionsMap[entryName] ?? {}
7779
if (documentationOverride) {
7880
return {
7981
name: entryName,
@@ -92,7 +94,10 @@ export const decorateLanguageService = (
9294
data,
9395
)
9496
if (!prior) return
95-
return completionEntryDetails(languageService, c, fileName, position, sourceFile, prior)
97+
if (documentationAppend) {
98+
prior.documentation = [...(prior.documentation ?? []), { kind: 'text', text: documentationAppend }]
99+
}
100+
return completionEntryDetails(languageService, c, fileName, position, sourceFile, prior, prevCompletionsAdittionalData)
96101
}
97102

98103
decorateCodeActions(proxy, languageService, c)

0 commit comments

Comments
 (0)