Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/debug/browser/replAccessibleView.ts
3296 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 { AccessibleViewProviderId, AccessibleViewType, IAccessibleViewContentProvider, IAccessibleViewService } from '../../../../platform/accessibility/browser/accessibleView.js';
7
import { AccessibilityVerbositySettingId } from '../../accessibility/browser/accessibilityConfiguration.js';
8
import { IReplElement } from '../common/debug.js';
9
import { IAccessibleViewImplementation } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js';
10
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
11
import { getReplView, Repl } from './repl.js';
12
import { IViewsService } from '../../../services/views/common/viewsService.js';
13
import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
14
import { Emitter, Event } from '../../../../base/common/event.js';
15
import { Disposable } from '../../../../base/common/lifecycle.js';
16
import { Position } from '../../../../editor/common/core/position.js';
17
18
export class ReplAccessibleView implements IAccessibleViewImplementation {
19
priority = 70;
20
name = 'debugConsole';
21
when = ContextKeyExpr.equals('focusedView', 'workbench.panel.repl.view');
22
type: AccessibleViewType = AccessibleViewType.View;
23
getProvider(accessor: ServicesAccessor) {
24
const viewsService = accessor.get(IViewsService);
25
const accessibleViewService = accessor.get(IAccessibleViewService);
26
const replView = getReplView(viewsService);
27
if (!replView) {
28
return undefined;
29
}
30
31
const focusedElement = replView.getFocusedElement();
32
return new ReplOutputAccessibleViewProvider(replView, focusedElement, accessibleViewService);
33
}
34
}
35
36
class ReplOutputAccessibleViewProvider extends Disposable implements IAccessibleViewContentProvider {
37
public readonly id = AccessibleViewProviderId.Repl;
38
private _content: string | undefined;
39
private readonly _onDidChangeContent: Emitter<void> = this._register(new Emitter<void>());
40
public readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
41
private readonly _onDidResolveChildren: Emitter<void> = this._register(new Emitter<void>());
42
public readonly onDidResolveChildren: Event<void> = this._onDidResolveChildren.event;
43
44
public readonly verbositySettingKey = AccessibilityVerbositySettingId.Debug;
45
public readonly options = {
46
type: AccessibleViewType.View
47
};
48
49
private _elementPositionMap: Map<string, Position> = new Map<string, Position>();
50
private _treeHadFocus = false;
51
52
constructor(
53
private readonly _replView: Repl,
54
private readonly _focusedElement: IReplElement | undefined,
55
@IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService) {
56
super();
57
this._treeHadFocus = !!_focusedElement;
58
}
59
public provideContent(): string {
60
const debugSession = this._replView.getDebugSession();
61
if (!debugSession) {
62
return 'No debug session available.';
63
}
64
const elements = debugSession.getReplElements();
65
if (!elements.length) {
66
return 'No output in the debug console.';
67
}
68
if (!this._content) {
69
this._updateContent(elements);
70
}
71
// Content is loaded asynchronously, so we need to check if it's available or fallback to the elements that are already available.
72
return this._content ?? elements.map(e => e.toString(true)).join('\n');
73
}
74
75
public onClose(): void {
76
this._content = undefined;
77
this._elementPositionMap.clear();
78
if (this._treeHadFocus) {
79
return this._replView.focusTree();
80
}
81
this._replView.getReplInput().focus();
82
}
83
84
public onOpen(): void {
85
// Children are resolved async, so we need to update the content when they are resolved.
86
this._register(this.onDidResolveChildren(() => {
87
this._onDidChangeContent.fire();
88
queueMicrotask(() => {
89
if (this._focusedElement) {
90
const position = this._elementPositionMap.get(this._focusedElement.getId());
91
if (position) {
92
this._accessibleViewService.setPosition(position, true);
93
}
94
}
95
});
96
}));
97
}
98
99
private async _updateContent(elements: IReplElement[]) {
100
const dataSource = this._replView.getReplDataSource();
101
if (!dataSource) {
102
return;
103
}
104
let line = 1;
105
const content: string[] = [];
106
for (const e of elements) {
107
content.push(e.toString().replace(/\n/g, ''));
108
this._elementPositionMap.set(e.getId(), new Position(line, 1));
109
line++;
110
if (dataSource.hasChildren(e)) {
111
const childContent: string[] = [];
112
const children = await dataSource.getChildren(e);
113
for (const child of children) {
114
const id = child.getId();
115
if (!this._elementPositionMap.has(id)) {
116
// don't overwrite parent position
117
this._elementPositionMap.set(id, new Position(line, 1));
118
}
119
childContent.push(' ' + child.toString());
120
line++;
121
}
122
content.push(childContent.join('\n'));
123
}
124
}
125
126
this._content = content.join('\n');
127
this._onDidResolveChildren.fire();
128
}
129
}
130
131