Path: blob/main/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import './standaloneQuickInput.css';6import { Event } from '../../../../base/common/event.js';7import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from '../../../browser/editorBrowser.js';8import { EditorContributionInstantiation, registerEditorContribution } from '../../../browser/editorExtensions.js';9import { IEditorContribution } from '../../../common/editorCommon.js';10import { IThemeService } from '../../../../platform/theme/common/themeService.js';11import { IQuickInputService, IQuickPickItem, IQuickPick, IInputBox, IQuickNavigateConfiguration, IPickOptions, QuickPickInput, IInputOptions, IQuickWidget, IQuickTree, IQuickTreeItem } from '../../../../platform/quickinput/common/quickInput.js';12import { CancellationToken } from '../../../../base/common/cancellation.js';13import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';14import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';15import { EditorScopedLayoutService } from '../standaloneLayoutService.js';16import { ICodeEditorService } from '../../../browser/services/codeEditorService.js';17import { QuickInputController, IQuickInputControllerHost } from '../../../../platform/quickinput/browser/quickInputController.js';18import { QuickInputService } from '../../../../platform/quickinput/browser/quickInputService.js';19import { createSingleCallFunction } from '../../../../base/common/functional.js';20import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';2122class EditorScopedQuickInputService extends QuickInputService {2324private host: IQuickInputControllerHost | undefined = undefined;2526constructor(27editor: ICodeEditor,28@IInstantiationService instantiationService: IInstantiationService,29@IContextKeyService contextKeyService: IContextKeyService,30@IThemeService themeService: IThemeService,31@ICodeEditorService codeEditorService: ICodeEditorService,32@IConfigurationService configurationService: IConfigurationService,33) {34super(35instantiationService,36contextKeyService,37themeService,38new EditorScopedLayoutService(editor.getContainerDomNode(), codeEditorService),39configurationService,40);4142// Use the passed in code editor as host for the quick input widget43const contribution = QuickInputEditorContribution.get(editor);44if (contribution) {45const widget = contribution.widget;46this.host = {47_serviceBrand: undefined,48get mainContainer() { return widget.getDomNode(); },49getContainer() { return widget.getDomNode(); },50whenContainerStylesLoaded() { return undefined; },51get containers() { return [widget.getDomNode()]; },52get activeContainer() { return widget.getDomNode(); },53get mainContainerDimension() { return editor.getLayoutInfo(); },54get activeContainerDimension() { return editor.getLayoutInfo(); },55get onDidLayoutMainContainer() { return editor.onDidLayoutChange; },56get onDidLayoutActiveContainer() { return editor.onDidLayoutChange; },57get onDidLayoutContainer() { return Event.map(editor.onDidLayoutChange, dimension => ({ container: widget.getDomNode(), dimension })); },58get onDidChangeActiveContainer() { return Event.None; },59get onDidAddContainer() { return Event.None; },60get mainContainerOffset() { return { top: 0, quickPickTop: 0 }; },61get activeContainerOffset() { return { top: 0, quickPickTop: 0 }; },62focus: () => editor.focus()63};64} else {65this.host = undefined;66}67}6869protected override createController(): QuickInputController {70return super.createController(this.host);71}72}7374export class StandaloneQuickInputService implements IQuickInputService {7576declare readonly _serviceBrand: undefined;7778private mapEditorToService = new Map<ICodeEditor, EditorScopedQuickInputService>();79private get activeService(): IQuickInputService {80const editor = this.codeEditorService.getFocusedCodeEditor();81if (!editor) {82throw new Error('Quick input service needs a focused editor to work.');83}8485// Find the quick input implementation for the focused86// editor or create it lazily if not yet created87let quickInputService = this.mapEditorToService.get(editor);88if (!quickInputService) {89const newQuickInputService = quickInputService = this.instantiationService.createInstance(EditorScopedQuickInputService, editor);90this.mapEditorToService.set(editor, quickInputService);9192createSingleCallFunction(editor.onDidDispose)(() => {93newQuickInputService.dispose();94this.mapEditorToService.delete(editor);95});96}9798return quickInputService;99}100101get currentQuickInput() { return this.activeService.currentQuickInput; }102get quickAccess() { return this.activeService.quickAccess; }103get backButton() { return this.activeService.backButton; }104get onShow() { return this.activeService.onShow; }105get onHide() { return this.activeService.onHide; }106107constructor(108@IInstantiationService private readonly instantiationService: IInstantiationService,109@ICodeEditorService private readonly codeEditorService: ICodeEditorService110) {111}112113pick<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> {114return (this.activeService as unknown as QuickInputController /* TS fail */).pick(picks, options, token);115}116117input(options?: IInputOptions | undefined, token?: CancellationToken | undefined): Promise<string | undefined> {118return this.activeService.input(options, token);119}120121createQuickPick<T extends IQuickPickItem>(options: { useSeparators: true }): IQuickPick<T, { useSeparators: true }>;122createQuickPick<T extends IQuickPickItem>(options?: { useSeparators: boolean }): IQuickPick<T, { useSeparators: false }>;123createQuickPick<T extends IQuickPickItem>(options: { useSeparators: boolean } = { useSeparators: false }): IQuickPick<T, { useSeparators: boolean }> {124return this.activeService.createQuickPick(options);125}126127createInputBox(): IInputBox {128return this.activeService.createInputBox();129}130131createQuickWidget(): IQuickWidget {132return this.activeService.createQuickWidget();133}134135createQuickTree<T extends IQuickTreeItem>(): IQuickTree<T> {136return this.activeService.createQuickTree();137}138139focus(): void {140return this.activeService.focus();141}142143toggle(): void {144return this.activeService.toggle();145}146147navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration | undefined): void {148return this.activeService.navigate(next, quickNavigate);149}150151accept(): Promise<void> {152return this.activeService.accept();153}154155back(): Promise<void> {156return this.activeService.back();157}158159cancel(): Promise<void> {160return this.activeService.cancel();161}162163setAlignment(alignment: 'top' | 'center' | { top: number; left: number }): void {164return this.activeService.setAlignment(alignment);165}166167toggleHover(): void {168return this.activeService.toggleHover();169}170}171172export class QuickInputEditorContribution implements IEditorContribution {173174static readonly ID = 'editor.controller.quickInput';175176static get(editor: ICodeEditor): QuickInputEditorContribution | null {177return editor.getContribution<QuickInputEditorContribution>(QuickInputEditorContribution.ID);178}179180readonly widget: QuickInputEditorWidget;181182constructor(private editor: ICodeEditor) {183this.widget = new QuickInputEditorWidget(this.editor);184}185186dispose(): void {187this.widget.dispose();188}189}190191export class QuickInputEditorWidget implements IOverlayWidget {192193private static readonly ID = 'editor.contrib.quickInputWidget';194195private domNode: HTMLElement;196197constructor(private codeEditor: ICodeEditor) {198this.domNode = document.createElement('div');199200this.codeEditor.addOverlayWidget(this);201}202203getId(): string {204return QuickInputEditorWidget.ID;205}206207getDomNode(): HTMLElement {208return this.domNode;209}210211getPosition(): IOverlayWidgetPosition | null {212return { preference: OverlayWidgetPositionPreference.TOP_CENTER };213}214215dispose(): void {216this.codeEditor.removeOverlayWidget(this);217}218}219220registerEditorContribution(QuickInputEditorContribution.ID, QuickInputEditorContribution, EditorContributionInstantiation.Lazy);221222223