Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts
4780 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
6
import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeSorter } from '../../../../base/browser/ui/tree/tree.js';
7
import { CallHierarchyItem, CallHierarchyDirection, CallHierarchyModel, } from '../common/callHierarchy.js';
8
import { CancellationToken } from '../../../../base/common/cancellation.js';
9
import { IIdentityProvider, IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js';
10
import { FuzzyScore, createMatches } from '../../../../base/common/filters.js';
11
import { IconLabel } from '../../../../base/browser/ui/iconLabel/iconLabel.js';
12
import { SymbolKinds, Location, SymbolTag } from '../../../../editor/common/languages.js';
13
import { compare } from '../../../../base/common/strings.js';
14
import { Range } from '../../../../editor/common/core/range.js';
15
import { IListAccessibilityProvider } from '../../../../base/browser/ui/list/listWidget.js';
16
import { localize } from '../../../../nls.js';
17
import { ThemeIcon } from '../../../../base/common/themables.js';
18
19
export class Call {
20
constructor(
21
readonly item: CallHierarchyItem,
22
readonly locations: Location[] | undefined,
23
readonly model: CallHierarchyModel,
24
readonly parent: Call | undefined
25
) { }
26
27
static compare(a: Call, b: Call): number {
28
let res = compare(a.item.uri.toString(), b.item.uri.toString());
29
if (res === 0) {
30
res = Range.compareRangesUsingStarts(a.item.range, b.item.range);
31
}
32
return res;
33
}
34
}
35
36
export class DataSource implements IAsyncDataSource<CallHierarchyModel, Call> {
37
38
constructor(
39
public getDirection: () => CallHierarchyDirection,
40
) { }
41
42
hasChildren(): boolean {
43
return true;
44
}
45
46
async getChildren(element: CallHierarchyModel | Call): Promise<Call[]> {
47
if (element instanceof CallHierarchyModel) {
48
return element.roots.map(root => new Call(root, undefined, element, undefined));
49
}
50
51
const { model, item } = element;
52
53
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
54
return (await model.resolveOutgoingCalls(item, CancellationToken.None)).map(call => {
55
return new Call(
56
call.to,
57
call.fromRanges.map(range => ({ range, uri: item.uri })),
58
model,
59
element
60
);
61
});
62
63
} else {
64
return (await model.resolveIncomingCalls(item, CancellationToken.None)).map(call => {
65
return new Call(
66
call.from,
67
call.fromRanges.map(range => ({ range, uri: call.from.uri })),
68
model,
69
element
70
);
71
});
72
}
73
}
74
}
75
76
export class Sorter implements ITreeSorter<Call> {
77
78
compare(element: Call, otherElement: Call): number {
79
return Call.compare(element, otherElement);
80
}
81
}
82
83
export class IdentityProvider implements IIdentityProvider<Call> {
84
85
constructor(
86
public getDirection: () => CallHierarchyDirection
87
) { }
88
89
getId(element: Call): { toString(): string } {
90
let res = this.getDirection() + JSON.stringify(element.item.uri) + JSON.stringify(element.item.range);
91
if (element.parent) {
92
res += this.getId(element.parent);
93
}
94
return res;
95
}
96
}
97
98
class CallRenderingTemplate {
99
constructor(
100
readonly icon: HTMLDivElement,
101
readonly label: IconLabel
102
) { }
103
}
104
105
export class CallRenderer implements ITreeRenderer<Call, FuzzyScore, CallRenderingTemplate> {
106
107
static readonly id = 'CallRenderer';
108
109
templateId: string = CallRenderer.id;
110
111
renderTemplate(container: HTMLElement): CallRenderingTemplate {
112
container.classList.add('callhierarchy-element');
113
const icon = document.createElement('div');
114
container.appendChild(icon);
115
const label = new IconLabel(container, { supportHighlights: true });
116
return new CallRenderingTemplate(icon, label);
117
}
118
119
renderElement(node: ITreeNode<Call, FuzzyScore>, _index: number, template: CallRenderingTemplate): void {
120
const { element, filterData } = node;
121
const deprecated = element.item.tags?.includes(SymbolTag.Deprecated);
122
template.icon.className = '';
123
template.icon.classList.add('inline', ...ThemeIcon.asClassNameArray(SymbolKinds.toIcon(element.item.kind)));
124
template.label.setLabel(
125
element.item.name,
126
element.item.detail,
127
{ labelEscapeNewLines: true, matches: createMatches(filterData), strikethrough: deprecated }
128
);
129
}
130
disposeTemplate(template: CallRenderingTemplate): void {
131
template.label.dispose();
132
}
133
}
134
135
export class VirtualDelegate implements IListVirtualDelegate<Call> {
136
137
getHeight(_element: Call): number {
138
return 22;
139
}
140
141
getTemplateId(_element: Call): string {
142
return CallRenderer.id;
143
}
144
}
145
146
export class AccessibilityProvider implements IListAccessibilityProvider<Call> {
147
148
constructor(
149
public getDirection: () => CallHierarchyDirection
150
) { }
151
152
getWidgetAriaLabel(): string {
153
return localize('tree.aria', "Call Hierarchy");
154
}
155
156
getAriaLabel(element: Call): string | null {
157
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
158
return localize('from', "calls from {0}", element.item.name);
159
} else {
160
return localize('to', "callers of {0}", element.item.name);
161
}
162
}
163
}
164
165