mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 19:44:25 +01:00
Merge remote-tracking branch 'origin/master' into misolori/new-icons
This commit is contained in:
@@ -7,12 +7,12 @@ import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { MainContext, MainThreadEditorInsetsShape, IExtHostContext, ExtHostEditorInsetsShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
// todo@joh move these things back into something like contrib/insets
|
||||
class EditorWebviewZone implements IViewZone {
|
||||
@@ -32,13 +32,15 @@ class EditorWebviewZone implements IViewZone {
|
||||
|
||||
constructor(
|
||||
readonly editor: IActiveCodeEditor,
|
||||
readonly range: IRange,
|
||||
readonly line: number,
|
||||
readonly height: number,
|
||||
readonly webview: Webview,
|
||||
) {
|
||||
this.domNode = document.createElement('div');
|
||||
this.afterLineNumber = range.startLineNumber;
|
||||
this.afterColumn = range.startColumn;
|
||||
this.heightInLines = range.endLineNumber - range.startLineNumber;
|
||||
this.domNode.style.zIndex = '10'; // without this, the webview is not interactive
|
||||
this.afterLineNumber = line;
|
||||
this.afterColumn = 1;
|
||||
this.heightInLines = height;
|
||||
|
||||
editor.changeViewZones(accessor => this._id = accessor.addZone(this));
|
||||
webview.mountTo(this.domNode);
|
||||
@@ -58,6 +60,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IWebviewService private readonly _webviewService: IWebviewService,
|
||||
) {
|
||||
@@ -68,7 +71,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
async $createEditorInset(handle: number, id: string, uri: UriComponents, range: IRange, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {
|
||||
async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {
|
||||
|
||||
let editor: IActiveCodeEditor | undefined;
|
||||
id = id.substr(0, id.indexOf(',')); //todo@joh HACK
|
||||
@@ -92,10 +95,11 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
allowSvgs: false,
|
||||
extension: { id: extensionId, location: URI.revive(extensionLocation) }
|
||||
}, {
|
||||
allowScripts: options.enableScripts
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined
|
||||
});
|
||||
|
||||
const webviewZone = new EditorWebviewZone(editor, range, webview);
|
||||
const webviewZone = new EditorWebviewZone(editor, line, height, webview);
|
||||
|
||||
const remove = () => {
|
||||
disposables.dispose();
|
||||
@@ -142,4 +146,8 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
async $getResourceRoot(_handle: number): Promise<string> {
|
||||
return this._environmentService.webviewResourceRoot;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions } from 'vs/platform/files/common/files';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat } from 'vs/platform/files/common/files';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
@@ -60,6 +60,56 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
}
|
||||
fileProvider.$onFileSystemChange(changes);
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
async $stat(uri: UriComponents): Promise<IStat> {
|
||||
const stat = await this._fileService.resolve(URI.revive(uri), { resolveMetadata: true });
|
||||
return {
|
||||
ctime: 0,
|
||||
mtime: stat.mtime,
|
||||
size: stat.size,
|
||||
type: MainThreadFileSystem._getFileType(stat)
|
||||
};
|
||||
}
|
||||
|
||||
async $readdir(uri: UriComponents): Promise<[string, FileType][]> {
|
||||
const stat = await this._fileService.resolve(URI.revive(uri), { resolveMetadata: false });
|
||||
if (!stat.children) {
|
||||
throw new Error('not a folder');
|
||||
}
|
||||
return stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)]);
|
||||
}
|
||||
|
||||
private static _getFileType(stat: IFileStat): FileType {
|
||||
return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0);
|
||||
}
|
||||
|
||||
async $readFile(uri: UriComponents): Promise<VSBuffer> {
|
||||
return (await this._fileService.readFile(URI.revive(uri))).value;
|
||||
}
|
||||
|
||||
async $writeFile(uri: UriComponents, content: VSBuffer, opts: FileWriteOptions): Promise<void> {
|
||||
//todo@joh honor opts
|
||||
await this._fileService.writeFile(URI.revive(uri), content, {});
|
||||
}
|
||||
|
||||
async $rename(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
await this._fileService.move(URI.revive(source), URI.revive(target), opts.overwrite);
|
||||
}
|
||||
|
||||
async $copy(source: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise<void> {
|
||||
await this._fileService.copy(URI.revive(source), URI.revive(target), opts.overwrite);
|
||||
}
|
||||
|
||||
async $mkdir(uri: UriComponents): Promise<void> {
|
||||
await this._fileService.createFolder(URI.revive(uri));
|
||||
}
|
||||
|
||||
async $delete(uri: UriComponents, opts: FileDeleteOptions): Promise<void> {
|
||||
await this._fileService.del(URI.revive(uri), opts);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainThreadTelemetryShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTelemetry)
|
||||
export class MainThreadTelemetry implements MainThreadTelemetryShape {
|
||||
@@ -28,4 +29,10 @@ export class MainThreadTelemetry implements MainThreadTelemetryShape {
|
||||
data[MainThreadTelemetry._name] = true;
|
||||
this._telemetryService.publicLog(eventName, data);
|
||||
}
|
||||
|
||||
$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data: StrictPropertyCheck<T, E>): void {
|
||||
this.$publicLog(eventName, data as any);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
@@ -22,11 +24,15 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
|
||||
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
|
||||
this._remoteAuthority = extHostContext.remoteAuthority;
|
||||
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
|
||||
|
||||
// ITerminalService listeners
|
||||
this._toDispose.push(_terminalService.onInstanceCreated((instance) => {
|
||||
// Delay this message so the TerminalInstance constructor has a chance to finish and
|
||||
// return the ID normally to the extension host. The ID that is passed here will be used
|
||||
// to register non-extension API terminals in the extension host.
|
||||
@@ -35,25 +41,32 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._onInstanceDimensionsChanged(instance);
|
||||
}, EXT_HOST_CREATION_DELAY);
|
||||
}));
|
||||
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
|
||||
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.push(terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
|
||||
this._toDispose.push(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
|
||||
this._toDispose.push(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.push(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.push(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
|
||||
this._toDispose.push(_terminalService.onRequestAvailableShells(e => this._onRequestAvailableShells(e)));
|
||||
|
||||
// ITerminalInstanceService listeners
|
||||
if (terminalInstanceService.onRequestDefaultShellAndArgs) {
|
||||
this._toDispose.push(terminalInstanceService.onRequestDefaultShellAndArgs(e => this._onRequestDefaultShellAndArgs(e)));
|
||||
}
|
||||
|
||||
// Set initial ext host state
|
||||
this.terminalService.terminalInstances.forEach(t => {
|
||||
this._terminalService.terminalInstances.forEach(t => {
|
||||
this._onTerminalOpened(t);
|
||||
t.processReady.then(() => this._onTerminalProcessIdReady(t));
|
||||
});
|
||||
const activeInstance = this.terminalService.getActiveInstance();
|
||||
const activeInstance = this._terminalService.getActiveInstance();
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
|
||||
this.terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
this._terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -63,7 +76,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
// when the extension host process goes down ?
|
||||
}
|
||||
|
||||
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }> {
|
||||
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean, hideFromUser?: boolean): Promise<{ id: number, name: string }> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name,
|
||||
executable: shellPath,
|
||||
@@ -73,9 +86,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
ignoreConfigurationCwd: true,
|
||||
env,
|
||||
strictEnv,
|
||||
runInBackground
|
||||
hideFromUser
|
||||
};
|
||||
const terminal = this.terminalService.createTerminal(shellLaunchConfig);
|
||||
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
|
||||
return Promise.resolve({
|
||||
id: terminal.id,
|
||||
name: terminal.title
|
||||
@@ -83,55 +96,55 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
public $createTerminalRenderer(name: string): Promise<number> {
|
||||
const instance = this.terminalService.createTerminalRenderer(name);
|
||||
const instance = this._terminalService.createTerminalRenderer(name);
|
||||
return Promise.resolve(instance.id);
|
||||
}
|
||||
|
||||
public $show(terminalId: number, preserveFocus: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
this.terminalService.setActiveInstance(terminalInstance);
|
||||
this.terminalService.showPanel(!preserveFocus);
|
||||
this._terminalService.setActiveInstance(terminalInstance);
|
||||
this._terminalService.showPanel(!preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public $hide(terminalId: number): void {
|
||||
const instance = this.terminalService.getActiveInstance();
|
||||
const instance = this._terminalService.getActiveInstance();
|
||||
if (instance && instance.id === terminalId) {
|
||||
this.terminalService.hidePanel();
|
||||
this._terminalService.hidePanel();
|
||||
}
|
||||
}
|
||||
|
||||
public $dispose(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererWrite(terminalId: number, text: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.write(text);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetName(terminalId: number, name: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setTitle(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setDimensions(dimensions);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererRegisterOnInputListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
@@ -147,14 +160,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
|
||||
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.sendText(text, addNewLine);
|
||||
}
|
||||
}
|
||||
|
||||
public $registerOnDataListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
@@ -216,6 +229,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._proxy.$acceptTerminalDimensions(instance.id, instance.cols, instance.rows);
|
||||
}
|
||||
|
||||
private _onInstanceMaximumDimensionsChanged(instance: ITerminalInstance): void {
|
||||
this._proxy.$acceptTerminalMaximumDimensions(instance.id, instance.maxCols, instance.maxRows);
|
||||
}
|
||||
|
||||
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
|
||||
// Only allow processes on remote ext hosts
|
||||
if (!this._remoteAuthority) {
|
||||
@@ -275,4 +292,25 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
this._terminalProcesses[terminalId].emitLatency(sum / COUNT);
|
||||
}
|
||||
|
||||
private _isPrimaryExtHost(): boolean {
|
||||
// The "primary" ext host is the remote ext host if there is one, otherwise the local
|
||||
const conn = this._remoteAgentService.getConnection();
|
||||
if (conn) {
|
||||
return this._remoteAuthority === conn.remoteAuthority;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private _onRequestAvailableShells(request: IAvailableShellsRequest): void {
|
||||
if (this._isPrimaryExtHost()) {
|
||||
this._proxy.$requestAvailableShells().then(e => request(e));
|
||||
}
|
||||
}
|
||||
|
||||
private _onRequestDefaultShellAndArgs(request: IDefaultShellAndArgsRequest): void {
|
||||
if (this._isPrimaryExtHost()) {
|
||||
this._proxy.$requestDefaultShellAndArgs().then(e => request(e.shell, e.args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/commo
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWebviews)
|
||||
export class MainThreadWebviews extends Disposable implements MainThreadWebviewsShape {
|
||||
@@ -54,6 +55,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -75,7 +77,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
}));
|
||||
|
||||
this._register(lifecycleService.onBeforeShutdown(e => {
|
||||
e.veto(this._onBeforeShutdown());
|
||||
this._onBeforeShutdown();
|
||||
e.veto(false); // Don't veto shutdown
|
||||
}, this));
|
||||
}
|
||||
|
||||
@@ -138,6 +141,10 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */));
|
||||
}
|
||||
|
||||
async $getResourceRoot(_handle: WebviewPanelHandle): Promise<string> {
|
||||
return this._environmentService.webviewResourceRoot;
|
||||
}
|
||||
|
||||
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
if (webview.isDisposed()) {
|
||||
@@ -217,13 +224,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
return `mainThreadWebview-${viewType}`;
|
||||
}
|
||||
|
||||
private _onBeforeShutdown(): boolean {
|
||||
private _onBeforeShutdown(): void {
|
||||
this._webviews.forEach((webview) => {
|
||||
if (!webview.isDisposed() && webview.state && this._revivers.has(webview.state.viewType)) {
|
||||
webview.state.state = webview.webviewState;
|
||||
}
|
||||
});
|
||||
return false; // Don't veto shutdown
|
||||
}
|
||||
|
||||
private createWebviewEventDelegate(handle: WebviewPanelHandle) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape, IOpenUriOptions } from '../common/extHost.protocol';
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { extractLocalHostUriMetaDataForPortMapping } from 'vs/workbench/contrib/webview/common/portMapping';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||
export class MainThreadWindow implements MainThreadWindowShape {
|
||||
@@ -48,26 +49,16 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
async $openUri(uriComponent: UriComponents, options: IOpenUriOptions): Promise<boolean> {
|
||||
let uri = URI.revive(uriComponent);
|
||||
if (options.allowTunneling && !!this.environmentService.configuration.remoteAuthority) {
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
const port = this.getLocalhostPort(uri);
|
||||
if (typeof port === 'number') {
|
||||
const tunnel = await this.getOrCreateTunnel(port);
|
||||
if (tunnel) {
|
||||
uri = uri.with({ authority: `localhost:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
const portMappingRequest = extractLocalHostUriMetaDataForPortMapping(uri);
|
||||
if (portMappingRequest) {
|
||||
const tunnel = await this.getOrCreateTunnel(portMappingRequest.port);
|
||||
if (tunnel) {
|
||||
uri = uri.with({ authority: `127.0.0.1:${tunnel.tunnelLocalPort}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.windowsService.openExternal(encodeURI(uri.toString(true)));
|
||||
}
|
||||
|
||||
private getLocalhostPort(uri: URI): number | undefined {
|
||||
const match = /^localhost:(\d+)$/.exec(uri.authority);
|
||||
if (match) {
|
||||
return +match[1];
|
||||
}
|
||||
return undefined;
|
||||
return this.windowsService.openExternal(uri.toString());
|
||||
}
|
||||
|
||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
|
||||
Reference in New Issue
Block a user