Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.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 './standaloneQuickInput.css';
7
import { Event } from '../../../../base/common/event.js';
8
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from '../../../browser/editorBrowser.js';
9
import { EditorContributionInstantiation, registerEditorContribution } from '../../../browser/editorExtensions.js';
10
import { IEditorContribution } from '../../../common/editorCommon.js';
11
import { IThemeService } from '../../../../platform/theme/common/themeService.js';
12
import { IQuickInputService, IQuickPickItem, IQuickPick, IInputBox, IQuickNavigateConfiguration, IPickOptions, QuickPickInput, IInputOptions, IQuickWidget, IQuickTree, IQuickTreeItem } from '../../../../platform/quickinput/common/quickInput.js';
13
import { CancellationToken } from '../../../../base/common/cancellation.js';
14
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
15
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
16
import { EditorScopedLayoutService } from '../standaloneLayoutService.js';
17
import { ICodeEditorService } from '../../../browser/services/codeEditorService.js';
18
import { QuickInputController, IQuickInputControllerHost } from '../../../../platform/quickinput/browser/quickInputController.js';
19
import { QuickInputService } from '../../../../platform/quickinput/browser/quickInputService.js';
20
import { createSingleCallFunction } from '../../../../base/common/functional.js';
21
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
22
23
class EditorScopedQuickInputService extends QuickInputService {
24
25
private host: IQuickInputControllerHost | undefined = undefined;
26
27
constructor(
28
editor: ICodeEditor,
29
@IInstantiationService instantiationService: IInstantiationService,
30
@IContextKeyService contextKeyService: IContextKeyService,
31
@IThemeService themeService: IThemeService,
32
@ICodeEditorService codeEditorService: ICodeEditorService,
33
@IConfigurationService configurationService: IConfigurationService,
34
) {
35
super(
36
instantiationService,
37
contextKeyService,
38
themeService,
39
new EditorScopedLayoutService(editor.getContainerDomNode(), codeEditorService),
40
configurationService,
41
);
42
43
// Use the passed in code editor as host for the quick input widget
44
const contribution = QuickInputEditorContribution.get(editor);
45
if (contribution) {
46
const widget = contribution.widget;
47
this.host = {
48
_serviceBrand: undefined,
49
get mainContainer() { return widget.getDomNode(); },
50
getContainer() { return widget.getDomNode(); },
51
whenContainerStylesLoaded() { return undefined; },
52
get containers() { return [widget.getDomNode()]; },
53
get activeContainer() { return widget.getDomNode(); },
54
get mainContainerDimension() { return editor.getLayoutInfo(); },
55
get activeContainerDimension() { return editor.getLayoutInfo(); },
56
get onDidLayoutMainContainer() { return editor.onDidLayoutChange; },
57
get onDidLayoutActiveContainer() { return editor.onDidLayoutChange; },
58
get onDidLayoutContainer() { return Event.map(editor.onDidLayoutChange, dimension => ({ container: widget.getDomNode(), dimension })); },
59
get onDidChangeActiveContainer() { return Event.None; },
60
get onDidAddContainer() { return Event.None; },
61
get mainContainerOffset() { return { top: 0, quickPickTop: 0 }; },
62
get activeContainerOffset() { return { top: 0, quickPickTop: 0 }; },
63
focus: () => editor.focus()
64
};
65
} else {
66
this.host = undefined;
67
}
68
}
69
70
protected override createController(): QuickInputController {
71
return super.createController(this.host);
72
}
73
}
74
75
export class StandaloneQuickInputService implements IQuickInputService {
76
77
declare readonly _serviceBrand: undefined;
78
79
private mapEditorToService = new Map<ICodeEditor, EditorScopedQuickInputService>();
80
private get activeService(): IQuickInputService {
81
const editor = this.codeEditorService.getFocusedCodeEditor();
82
if (!editor) {
83
throw new Error('Quick input service needs a focused editor to work.');
84
}
85
86
// Find the quick input implementation for the focused
87
// editor or create it lazily if not yet created
88
let quickInputService = this.mapEditorToService.get(editor);
89
if (!quickInputService) {
90
const newQuickInputService = quickInputService = this.instantiationService.createInstance(EditorScopedQuickInputService, editor);
91
this.mapEditorToService.set(editor, quickInputService);
92
93
createSingleCallFunction(editor.onDidDispose)(() => {
94
newQuickInputService.dispose();
95
this.mapEditorToService.delete(editor);
96
});
97
}
98
99
return quickInputService;
100
}
101
102
get currentQuickInput() { return this.activeService.currentQuickInput; }
103
get quickAccess() { return this.activeService.quickAccess; }
104
get backButton() { return this.activeService.backButton; }
105
get onShow() { return this.activeService.onShow; }
106
get onHide() { return this.activeService.onHide; }
107
108
constructor(
109
@IInstantiationService private readonly instantiationService: IInstantiationService,
110
@ICodeEditorService private readonly codeEditorService: ICodeEditorService
111
) {
112
}
113
114
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: O, token: CancellationToken = CancellationToken.None): Promise<(O extends { canPickMany: true } ? T[] : T) | undefined> {
115
return (this.activeService as unknown as QuickInputController /* TS fail */).pick(picks, options, token);
116
}
117
118
input(options?: IInputOptions | undefined, token?: CancellationToken | undefined): Promise<string | undefined> {
119
return this.activeService.input(options, token);
120
}
121
122
createQuickPick<T extends IQuickPickItem>(options: { useSeparators: true }): IQuickPick<T, { useSeparators: true }>;
123
createQuickPick<T extends IQuickPickItem>(options?: { useSeparators: boolean }): IQuickPick<T, { useSeparators: false }>;
124
createQuickPick<T extends IQuickPickItem>(options: { useSeparators: boolean } = { useSeparators: false }): IQuickPick<T, { useSeparators: boolean }> {
125
return this.activeService.createQuickPick(options);
126
}
127
128
createInputBox(): IInputBox {
129
return this.activeService.createInputBox();
130
}
131
132
createQuickWidget(): IQuickWidget {
133
return this.activeService.createQuickWidget();
134
}
135
136
createQuickTree<T extends IQuickTreeItem>(): IQuickTree<T> {
137
return this.activeService.createQuickTree();
138
}
139
140
focus(): void {
141
return this.activeService.focus();
142
}
143
144
toggle(): void {
145
return this.activeService.toggle();
146
}
147
148
navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration | undefined): void {
149
return this.activeService.navigate(next, quickNavigate);
150
}
151
152
accept(): Promise<void> {
153
return this.activeService.accept();
154
}
155
156
back(): Promise<void> {
157
return this.activeService.back();
158
}
159
160
cancel(): Promise<void> {
161
return this.activeService.cancel();
162
}
163
164
setAlignment(alignment: 'top' | 'center' | { top: number; left: number }): void {
165
return this.activeService.setAlignment(alignment);
166
}
167
168
toggleHover(): void {
169
return this.activeService.toggleHover();
170
}
171
}
172
173
export class QuickInputEditorContribution implements IEditorContribution {
174
175
static readonly ID = 'editor.controller.quickInput';
176
177
static get(editor: ICodeEditor): QuickInputEditorContribution | null {
178
return editor.getContribution<QuickInputEditorContribution>(QuickInputEditorContribution.ID);
179
}
180
181
readonly widget: QuickInputEditorWidget;
182
183
constructor(private editor: ICodeEditor) {
184
this.widget = new QuickInputEditorWidget(this.editor);
185
}
186
187
dispose(): void {
188
this.widget.dispose();
189
}
190
}
191
192
export class QuickInputEditorWidget implements IOverlayWidget {
193
194
private static readonly ID = 'editor.contrib.quickInputWidget';
195
196
private domNode: HTMLElement;
197
198
constructor(private codeEditor: ICodeEditor) {
199
this.domNode = document.createElement('div');
200
201
this.codeEditor.addOverlayWidget(this);
202
}
203
204
getId(): string {
205
return QuickInputEditorWidget.ID;
206
}
207
208
getDomNode(): HTMLElement {
209
return this.domNode;
210
}
211
212
getPosition(): IOverlayWidgetPosition | null {
213
return { preference: OverlayWidgetPositionPreference.TOP_CENTER };
214
}
215
216
dispose(): void {
217
this.codeEditor.removeOverlayWidget(this);
218
}
219
}
220
221
registerEditorContribution(QuickInputEditorContribution.ID, QuickInputEditorContribution, EditorContributionInstantiation.Lazy);
222
223