Path: blob/main/src/vs/workbench/api/browser/mainThreadCodeInsets.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 { getWindow } from '../../../base/browser/dom.js';6import { DisposableStore } from '../../../base/common/lifecycle.js';7import { isEqual } from '../../../base/common/resources.js';8import { URI, UriComponents } from '../../../base/common/uri.js';9import { IActiveCodeEditor, IViewZone } from '../../../editor/browser/editorBrowser.js';10import { ICodeEditorService } from '../../../editor/browser/services/codeEditorService.js';11import { ExtensionIdentifier } from '../../../platform/extensions/common/extensions.js';12import { reviveWebviewContentOptions } from './mainThreadWebviews.js';13import { ExtHostContext, ExtHostEditorInsetsShape, IWebviewContentOptions, MainContext, MainThreadEditorInsetsShape } from '../common/extHost.protocol.js';14import { IWebviewService, IWebviewElement } from '../../contrib/webview/browser/webview.js';15import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js';1617// todo@jrieken move these things back into something like contrib/insets18class EditorWebviewZone implements IViewZone {1920readonly domNode: HTMLElement;21readonly afterLineNumber: number;22readonly afterColumn: number;23readonly heightInLines: number;2425private _id?: string;26// suppressMouseDown?: boolean | undefined;27// heightInPx?: number | undefined;28// minWidthInPx?: number | undefined;29// marginDomNode?: HTMLElement | null | undefined;30// onDomNodeTop?: ((top: number) => void) | undefined;31// onComputedHeight?: ((height: number) => void) | undefined;3233constructor(34readonly editor: IActiveCodeEditor,35readonly line: number,36readonly height: number,37readonly webview: IWebviewElement,38) {39this.domNode = document.createElement('div');40this.domNode.style.zIndex = '10'; // without this, the webview is not interactive41this.afterLineNumber = line;42this.afterColumn = 1;43this.heightInLines = height;4445editor.changeViewZones(accessor => this._id = accessor.addZone(this));46webview.mountTo(this.domNode, getWindow(editor.getDomNode()));47}4849dispose(): void {50this.editor.changeViewZones(accessor => this._id && accessor.removeZone(this._id));51}52}5354@extHostNamedCustomer(MainContext.MainThreadEditorInsets)55export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {5657private readonly _proxy: ExtHostEditorInsetsShape;58private readonly _disposables = new DisposableStore();59private readonly _insets = new Map<number, EditorWebviewZone>();6061constructor(62context: IExtHostContext,63@ICodeEditorService private readonly _editorService: ICodeEditorService,64@IWebviewService private readonly _webviewService: IWebviewService,65) {66this._proxy = context.getProxy(ExtHostContext.ExtHostEditorInsets);67}6869dispose(): void {70this._disposables.dispose();71}7273async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewContentOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {7475let editor: IActiveCodeEditor | undefined;76id = id.substr(0, id.indexOf(',')); //todo@jrieken HACK7778for (const candidate of this._editorService.listCodeEditors()) {79if (candidate.getId() === id && candidate.hasModel() && isEqual(candidate.getModel().uri, URI.revive(uri))) {80editor = candidate;81break;82}83}8485if (!editor) {86setTimeout(() => this._proxy.$onDidDispose(handle));87return;88}8990const disposables = new DisposableStore();9192const webview = this._webviewService.createWebviewElement({93title: undefined,94options: {95enableFindWidget: false,96},97contentOptions: reviveWebviewContentOptions(options),98extension: { id: extensionId, location: URI.revive(extensionLocation) }99});100101const webviewZone = new EditorWebviewZone(editor, line, height, webview);102103const remove = () => {104disposables.dispose();105this._proxy.$onDidDispose(handle);106this._insets.delete(handle);107};108109disposables.add(editor.onDidChangeModel(remove));110disposables.add(editor.onDidDispose(remove));111disposables.add(webviewZone);112disposables.add(webview);113disposables.add(webview.onMessage(msg => this._proxy.$onDidReceiveMessage(handle, msg.message)));114115this._insets.set(handle, webviewZone);116}117118$disposeEditorInset(handle: number): void {119const inset = this.getInset(handle);120this._insets.delete(handle);121inset.dispose();122}123124$setHtml(handle: number, value: string): void {125const inset = this.getInset(handle);126inset.webview.setHtml(value);127}128129$setOptions(handle: number, options: IWebviewContentOptions): void {130const inset = this.getInset(handle);131inset.webview.contentOptions = reviveWebviewContentOptions(options);132}133134async $postMessage(handle: number, value: any): Promise<boolean> {135const inset = this.getInset(handle);136inset.webview.postMessage(value);137return true;138}139140private getInset(handle: number): EditorWebviewZone {141const inset = this._insets.get(handle);142if (!inset) {143throw new Error('Unknown inset');144}145return inset;146}147}148149150