Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/linkify/vscode-node/findSymbol.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import type * as vscode from 'vscode';
6
7
type FoundSymbol = {
8
symbol: vscode.SymbolInformation | vscode.DocumentSymbol;
9
matchCount: number;
10
};
11
12
function findBestSymbol(
13
symbols: ReadonlyArray<vscode.SymbolInformation | vscode.DocumentSymbol>,
14
symbolParts: readonly string[]
15
): FoundSymbol | undefined {
16
if (!symbolParts.length) {
17
return;
18
}
19
20
let bestMatch: FoundSymbol | undefined;
21
for (const symbol of symbols) {
22
// TODO: vscode.executeDocumentSymbolProvider doesn't return a real instance of
23
// vscode.DocumentSymbol so use cast to check for children
24
if ((symbol as vscode.DocumentSymbol).children) {
25
let partMatch = symbol.name === symbolParts[0] ? { symbol, matchCount: 1 } : undefined;
26
if (partMatch) {
27
const remainingPartMatch = findBestSymbol((symbol as vscode.DocumentSymbol).children, symbolParts.slice(1));
28
if (remainingPartMatch) {
29
partMatch = { symbol: remainingPartMatch.symbol, matchCount: partMatch.matchCount + remainingPartMatch.matchCount };
30
}
31
}
32
33
const restMatch = findBestSymbol((symbol as vscode.DocumentSymbol).children, symbolParts);
34
let match: FoundSymbol | undefined;
35
if (partMatch && restMatch) {
36
match = partMatch.matchCount >= restMatch.matchCount ? partMatch : restMatch;
37
} else {
38
match = partMatch ?? restMatch;
39
}
40
41
if (match && (!bestMatch || match.matchCount > bestMatch?.matchCount)) {
42
bestMatch = match;
43
}
44
} else { // Is a vscode.SymbolInformation
45
// For flat symbol information, try to match against symbol parts
46
// Prefer symbols that appear more to the right (higher index) in the qualified name
47
// This prioritizes members over classes (e.g., in `TextModel.undo()`, prefer `undo`)
48
const matchIndex = symbolParts.indexOf(symbol.name);
49
if (matchIndex !== -1) {
50
// Higher index = more to the right = higher priority
51
const match = { symbol, matchCount: matchIndex + 1 };
52
if (!bestMatch || match.matchCount > bestMatch.matchCount) {
53
bestMatch = match;
54
}
55
}
56
}
57
}
58
59
return bestMatch;
60
}
61
62
/**
63
* Try to find a symbol in a symbol tree.
64
*
65
* This does a fuzzy search of the symbol tree. This means that the symbol parts must appear in order,
66
* but there can be separated by layers. For example: `a, c` could match on a symbol tree `a -> b -> c`.
67
* We also always make a best effort to find the symbol even if not all parts match.
68
* For example with `a, c`, this means we would match on `a -> x -> z` because `a` matched.
69
*/
70
export function findBestSymbolByPath(
71
symbols: ReadonlyArray<vscode.SymbolInformation | vscode.DocumentSymbol>,
72
symbolPath: string
73
): vscode.SymbolInformation | vscode.DocumentSymbol | undefined {
74
75
// Prefer an exact match but fallback to breaking up the symbol into parts
76
return (
77
findBestSymbol(symbols, [symbolPath]) ?? findBestSymbol(symbols, extractSymbolNamesInCode(symbolPath))
78
)?.symbol;
79
}
80
81
/**
82
* The symbol path may be take a few different forms:
83
* - Exact name: `foo`, `some symbol name`
84
* - Name plus signature: `foo()`
85
* - Qualified name: `foo.bar`
86
*
87
* We want just the names without any of the extra punctuation because `symbols` does not include these
88
*/
89
function extractSymbolNamesInCode(inlineCode: string): string[] {
90
// TODO: this assumes the language is JS like.
91
// It won't handle symbol parts that include spaces or special characters
92
return Array.from(inlineCode.matchAll(/[#\w$][\w\d$]*/g), x => x[0]);
93
}
94
95