Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/browser/mainThreadCodeInsets.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 { getWindow } from '../../../base/browser/dom.js';
7
import { DisposableStore } from '../../../base/common/lifecycle.js';
8
import { isEqual } from '../../../base/common/resources.js';
9
import { URI, UriComponents } from '../../../base/common/uri.js';
10
import { IActiveCodeEditor, IViewZone } from '../../../editor/browser/editorBrowser.js';
11
import { ICodeEditorService } from '../../../editor/browser/services/codeEditorService.js';
12
import { ExtensionIdentifier } from '../../../platform/extensions/common/extensions.js';
13
import { reviveWebviewContentOptions } from './mainThreadWebviews.js';
14
import { ExtHostContext, ExtHostEditorInsetsShape, IWebviewContentOptions, MainContext, MainThreadEditorInsetsShape } from '../common/extHost.protocol.js';
15
import { IWebviewService, IWebviewElement } from '../../contrib/webview/browser/webview.js';
16
import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js';
17
18
// todo@jrieken move these things back into something like contrib/insets
19
class EditorWebviewZone implements IViewZone {
20
21
readonly domNode: HTMLElement;
22
readonly afterLineNumber: number;
23
readonly afterColumn: number;
24
readonly heightInLines: number;
25
26
private _id?: string;
27
// suppressMouseDown?: boolean | undefined;
28
// heightInPx?: number | undefined;
29
// minWidthInPx?: number | undefined;
30
// marginDomNode?: HTMLElement | null | undefined;
31
// onDomNodeTop?: ((top: number) => void) | undefined;
32
// onComputedHeight?: ((height: number) => void) | undefined;
33
34
constructor(
35
readonly editor: IActiveCodeEditor,
36
readonly line: number,
37
readonly height: number,
38
readonly webview: IWebviewElement,
39
) {
40
this.domNode = document.createElement('div');
41
this.domNode.style.zIndex = '10'; // without this, the webview is not interactive
42
this.afterLineNumber = line;
43
this.afterColumn = 1;
44
this.heightInLines = height;
45
46
editor.changeViewZones(accessor => this._id = accessor.addZone(this));
47
webview.mountTo(this.domNode, getWindow(editor.getDomNode()));
48
}
49
50
dispose(): void {
51
this.editor.changeViewZones(accessor => this._id && accessor.removeZone(this._id));
52
}
53
}
54
55
@extHostNamedCustomer(MainContext.MainThreadEditorInsets)
56
export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
57
58
private readonly _proxy: ExtHostEditorInsetsShape;
59
private readonly _disposables = new DisposableStore();
60
private readonly _insets = new Map<number, EditorWebviewZone>();
61
62
constructor(
63
context: IExtHostContext,
64
@ICodeEditorService private readonly _editorService: ICodeEditorService,
65
@IWebviewService private readonly _webviewService: IWebviewService,
66
) {
67
this._proxy = context.getProxy(ExtHostContext.ExtHostEditorInsets);
68
}
69
70
dispose(): void {
71
this._disposables.dispose();
72
}
73
74
async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewContentOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {
75
76
let editor: IActiveCodeEditor | undefined;
77
id = id.substr(0, id.indexOf(',')); //todo@jrieken HACK
78
79
for (const candidate of this._editorService.listCodeEditors()) {
80
if (candidate.getId() === id && candidate.hasModel() && isEqual(candidate.getModel().uri, URI.revive(uri))) {
81
editor = candidate;
82
break;
83
}
84
}
85
86
if (!editor) {
87
setTimeout(() => this._proxy.$onDidDispose(handle));
88
return;
89
}
90
91
const disposables = new DisposableStore();
92
93
const webview = this._webviewService.createWebviewElement({
94
title: undefined,
95
options: {
96
enableFindWidget: false,
97
},
98
contentOptions: reviveWebviewContentOptions(options),
99
extension: { id: extensionId, location: URI.revive(extensionLocation) }
100
});
101
102
const webviewZone = new EditorWebviewZone(editor, line, height, webview);
103
104
const remove = () => {
105
disposables.dispose();
106
this._proxy.$onDidDispose(handle);
107
this._insets.delete(handle);
108
};
109
110
disposables.add(editor.onDidChangeModel(remove));
111
disposables.add(editor.onDidDispose(remove));
112
disposables.add(webviewZone);
113
disposables.add(webview);
114
disposables.add(webview.onMessage(msg => this._proxy.$onDidReceiveMessage(handle, msg.message)));
115
116
this._insets.set(handle, webviewZone);
117
}
118
119
$disposeEditorInset(handle: number): void {
120
const inset = this.getInset(handle);
121
this._insets.delete(handle);
122
inset.dispose();
123
}
124
125
$setHtml(handle: number, value: string): void {
126
const inset = this.getInset(handle);
127
inset.webview.setHtml(value);
128
}
129
130
$setOptions(handle: number, options: IWebviewContentOptions): void {
131
const inset = this.getInset(handle);
132
inset.webview.contentOptions = reviveWebviewContentOptions(options);
133
}
134
135
async $postMessage(handle: number, value: any): Promise<boolean> {
136
const inset = this.getInset(handle);
137
inset.webview.postMessage(value);
138
return true;
139
}
140
141
private getInset(handle: number): EditorWebviewZone {
142
const inset = this._insets.get(handle);
143
if (!inset) {
144
throw new Error('Unknown inset');
145
}
146
return inset;
147
}
148
}
149
150