mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 03:54:24 +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 {
|
||||
|
||||
@@ -46,6 +46,7 @@ import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHi
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
|
||||
export interface IEnvironment {
|
||||
isExtensionDevelopmentDebug: boolean;
|
||||
@@ -84,7 +85,7 @@ export interface IInitData {
|
||||
logLevel: LogLevel;
|
||||
logsLocation: URI;
|
||||
autoStart: boolean;
|
||||
remoteAuthority?: string | null;
|
||||
remote: { isRemote: boolean; authority: string | undefined; };
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
@@ -389,7 +390,7 @@ export interface MainThreadProgressShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }>;
|
||||
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean, hideFromUser?: boolean): Promise<{ id: number, name: string }>;
|
||||
$createTerminalRenderer(name: string): Promise<number>;
|
||||
$dispose(terminalId: number): void;
|
||||
$hide(terminalId: number): void;
|
||||
@@ -507,15 +508,17 @@ export interface MainThreadStorageShape extends IDisposable {
|
||||
|
||||
export interface MainThreadTelemetryShape extends IDisposable {
|
||||
$publicLog(eventName: string, data?: any): void;
|
||||
$publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>): void;
|
||||
}
|
||||
|
||||
export interface MainThreadEditorInsetsShape extends IDisposable {
|
||||
$createEditorInset(handle: number, id: string, uri: UriComponents, range: IRange, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
|
||||
$createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
|
||||
$disposeEditorInset(handle: number): void;
|
||||
|
||||
$setHtml(handle: number, value: string): void;
|
||||
$setOptions(handle: number, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: number, value: any): Promise<boolean>;
|
||||
$getResourceRoot(handle: number): Promise<string>;
|
||||
}
|
||||
|
||||
export interface ExtHostEditorInsetsShape {
|
||||
@@ -540,6 +543,7 @@ export interface MainThreadWebviewsShape extends IDisposable {
|
||||
$setHtml(handle: WebviewPanelHandle, value: string): void;
|
||||
$setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: WebviewPanelHandle, value: any): Promise<boolean>;
|
||||
$getResourceRoot(handle: WebviewPanelHandle): Promise<string>;
|
||||
|
||||
$registerSerializer(viewType: string): void;
|
||||
$unregisterSerializer(viewType: string): void;
|
||||
@@ -591,6 +595,15 @@ export interface MainThreadFileSystemShape extends IDisposable {
|
||||
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void;
|
||||
$unregisterResourceLabelFormatter(handle: number): void;
|
||||
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
|
||||
|
||||
$stat(uri: UriComponents): Promise<files.IStat>;
|
||||
$readdir(resource: UriComponents): Promise<[string, files.FileType][]>;
|
||||
$readFile(resource: UriComponents): Promise<VSBuffer>;
|
||||
$writeFile(resource: UriComponents, content: VSBuffer, opts: files.FileWriteOptions): Promise<void>;
|
||||
$rename(resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$copy(resource: UriComponents, target: UriComponents, opts: files.FileOverwriteOptions): Promise<void>;
|
||||
$mkdir(resource: UriComponents): Promise<void>;
|
||||
$delete(resource: UriComponents, opts: files.FileDeleteOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadSearchShape extends IDisposable {
|
||||
@@ -1106,6 +1119,16 @@ export interface ShellLaunchConfigDto {
|
||||
env?: { [key: string]: string | null };
|
||||
}
|
||||
|
||||
export interface IShellDefinitionDto {
|
||||
label: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface IShellAndArgsDto {
|
||||
shell: string;
|
||||
args: string[] | string | undefined;
|
||||
}
|
||||
|
||||
export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalClosed(id: number): void;
|
||||
$acceptTerminalOpened(id: number, name: string): void;
|
||||
@@ -1115,6 +1138,7 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalRendererInput(id: number, data: string): void;
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
$acceptProcessInput(id: number, data: string): void;
|
||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||
@@ -1123,6 +1147,8 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptProcessRequestCwd(id: number): void;
|
||||
$acceptProcessRequestLatency(id: number): number;
|
||||
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
$requestAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
$requestDefaultShellAndArgs(): Promise<IShellAndArgsDto>;
|
||||
}
|
||||
|
||||
export interface ExtHostSCMShape {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeature
|
||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
|
||||
export class ExtHostApiCommands {
|
||||
|
||||
@@ -414,15 +415,21 @@ export class ExtHostApiCommands {
|
||||
});
|
||||
}
|
||||
|
||||
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[][]> {
|
||||
private _executeSelectionRangeProvider(resource: URI, positions: types.Position[]): Promise<vscode.SelectionRange[]> {
|
||||
const pos = positions.map(typeConverters.Position.from);
|
||||
const args = {
|
||||
resource,
|
||||
position: pos[0],
|
||||
positions: pos
|
||||
};
|
||||
return this._commands.executeCommand<modes.SelectionRange[][]>('_executeSelectionRangeProvider', args).then(result => {
|
||||
return result.map(oneResult => oneResult.map(typeConverters.SelectionRange.to));
|
||||
return this._commands.executeCommand<IRange[][]>('_executeSelectionRangeProvider', args).then(result => {
|
||||
return result.map(ranges => {
|
||||
let node: types.SelectionRange | undefined;
|
||||
for (const range of ranges.reverse()) {
|
||||
node = new types.SelectionRange(typeConverters.Range.to(range), node);
|
||||
}
|
||||
return node!;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainThreadEditorInsetsShape } from './extHost.protocol';
|
||||
import { MainThreadEditorInsetsShape, ExtHostEditorInsetsShape } from './extHost.protocol';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
export class ExtHostEditorInsets implements ExtHostEditorInsets {
|
||||
export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
|
||||
|
||||
private _handlePool = 0;
|
||||
private _disposables = new DisposableStore();
|
||||
@@ -39,7 +38,7 @@ export class ExtHostEditorInsets implements ExtHostEditorInsets {
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
createWebviewEditorInset(editor: vscode.TextEditor, range: vscode.Range, options: vscode.WebviewOptions | undefined, extension: IExtensionDescription): vscode.WebviewEditorInset {
|
||||
createWebviewEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions | undefined, extension: IExtensionDescription): vscode.WebviewEditorInset {
|
||||
|
||||
let apiEditor: ExtHostTextEditor | undefined;
|
||||
for (const candidate of this._editors.getVisibleTextEditors()) {
|
||||
@@ -62,6 +61,10 @@ export class ExtHostEditorInsets implements ExtHostEditorInsets {
|
||||
private _html: string = '';
|
||||
private _options: vscode.WebviewOptions;
|
||||
|
||||
get resourceRoot(): Promise<string> {
|
||||
return that._proxy.$getResourceRoot(handle);
|
||||
}
|
||||
|
||||
set options(value: vscode.WebviewOptions) {
|
||||
this._options = value;
|
||||
that._proxy.$setOptions(handle, value);
|
||||
@@ -92,7 +95,8 @@ export class ExtHostEditorInsets implements ExtHostEditorInsets {
|
||||
const inset = new class implements vscode.WebviewEditorInset {
|
||||
|
||||
readonly editor: vscode.TextEditor = editor;
|
||||
readonly range: vscode.Range = range;
|
||||
readonly line: number = line;
|
||||
readonly height: number = height;
|
||||
readonly webview: vscode.Webview = webview;
|
||||
readonly onDidDispose: vscode.Event<void> = onDidDispose.event;
|
||||
|
||||
@@ -109,7 +113,7 @@ export class ExtHostEditorInsets implements ExtHostEditorInsets {
|
||||
}
|
||||
};
|
||||
|
||||
this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.document.uri, typeConverters.Range.from(range), options || {}, extension.identifier, extension.extensionLocation);
|
||||
this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.document.uri, line + 1, height, options || {}, extension.identifier, extension.extensionLocation);
|
||||
this._insets.set(handle, { editor, inset, onDidReceiveMessage });
|
||||
|
||||
return inset;
|
||||
|
||||
@@ -210,7 +210,7 @@ export class CommandsConverter {
|
||||
this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this);
|
||||
}
|
||||
|
||||
toInternal2(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined {
|
||||
toInternal(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined {
|
||||
|
||||
if (!command) {
|
||||
return undefined;
|
||||
@@ -240,40 +240,6 @@ export class CommandsConverter {
|
||||
return result;
|
||||
}
|
||||
|
||||
toInternal(command: vscode.Command): CommandDto;
|
||||
toInternal(command: undefined): undefined;
|
||||
toInternal(command: vscode.Command | undefined): CommandDto | undefined;
|
||||
toInternal(command: vscode.Command | undefined): CommandDto | undefined {
|
||||
|
||||
if (!command) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result: CommandDto = {
|
||||
$ident: undefined,
|
||||
id: command.command,
|
||||
title: command.title,
|
||||
};
|
||||
|
||||
if (command.command && isNonEmptyArray(command.arguments)) {
|
||||
// we have a contributed command with arguments. that
|
||||
// means we don't want to send the arguments around
|
||||
|
||||
const id = ++this._cachIdPool;
|
||||
this._cache.set(id, command);
|
||||
result.$ident = id;
|
||||
|
||||
result.id = this._delegatingCommandId;
|
||||
result.arguments = [id];
|
||||
}
|
||||
|
||||
if (command.tooltip) {
|
||||
result.tooltip = command.tooltip;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fromInternal(command: modes.Command): vscode.Command | undefined {
|
||||
|
||||
const id = ObjectIdentifier.of(command);
|
||||
|
||||
@@ -650,9 +650,9 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
const label = this.label;
|
||||
const contextValue = this.contextValue;
|
||||
const comments = this._comments.map(cmt => { return convertToModeComment2(this, this._commentController, cmt, this._commandsConverter, this._commentsMap, this._acceptInputDisposables.value!); });
|
||||
const acceptInputCommand = this._acceptInputCommand ? this._commandsConverter.toInternal2(this._acceptInputCommand, this._acceptInputDisposables.value) : undefined;
|
||||
const additionalCommands = (this._additionalCommands ? this._additionalCommands.map(x => this._commandsConverter.toInternal2(x, this._acceptInputDisposables.value!)) : []) as CommandDto[];
|
||||
const deleteCommand = this._deleteCommand ? this._commandsConverter.toInternal2(this._deleteCommand, this._acceptInputDisposables.value) : undefined;
|
||||
const acceptInputCommand = this._acceptInputCommand ? this._commandsConverter.toInternal(this._acceptInputCommand, this._acceptInputDisposables.value) : undefined;
|
||||
const additionalCommands = (this._additionalCommands ? this._additionalCommands.map(x => this._commandsConverter.toInternal(x, this._acceptInputDisposables.value!)) : []) as CommandDto[];
|
||||
const deleteCommand = this._deleteCommand ? this._commandsConverter.toInternal(this._deleteCommand, this._acceptInputDisposables.value) : undefined;
|
||||
const collapsibleState = convertToCollapsibleState(this._collapseState);
|
||||
|
||||
this._proxy.$updateCommentThread(
|
||||
@@ -951,9 +951,9 @@ function convertToModeComment2(thread: ExtHostCommentThread, commentController:
|
||||
userName: vscodeComment.author ? vscodeComment.author.name : vscodeComment.userName,
|
||||
userIconPath: iconPath,
|
||||
isDraft: vscodeComment.isDraft,
|
||||
selectCommand: vscodeComment.selectCommand ? commandsConverter.toInternal2(vscodeComment.selectCommand, disposables) : undefined,
|
||||
editCommand: vscodeComment.editCommand ? commandsConverter.toInternal2(vscodeComment.editCommand, disposables) : undefined,
|
||||
deleteCommand: vscodeComment.deleteCommand ? commandsConverter.toInternal2(vscodeComment.deleteCommand, disposables) : undefined,
|
||||
selectCommand: vscodeComment.selectCommand ? commandsConverter.toInternal(vscodeComment.selectCommand, disposables) : undefined,
|
||||
editCommand: vscodeComment.editCommand ? commandsConverter.toInternal(vscodeComment.editCommand, disposables) : undefined,
|
||||
deleteCommand: vscodeComment.deleteCommand ? commandsConverter.toInternal(vscodeComment.deleteCommand, disposables) : undefined,
|
||||
label: vscodeComment.label,
|
||||
commentReactions: reactions ? reactions.map(reaction => convertToReaction2(commentController.reactionProvider, reaction)) : undefined
|
||||
};
|
||||
@@ -971,7 +971,7 @@ function convertToComment(provider: vscode.DocumentCommentProvider | vscode.Work
|
||||
userIconPath: iconPath,
|
||||
canEdit: canEdit,
|
||||
canDelete: canDelete,
|
||||
selectCommand: vscodeComment.command ? commandsConverter.toInternal2(vscodeComment.command, disposables) : undefined,
|
||||
selectCommand: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command, disposables) : undefined,
|
||||
isDraft: vscodeComment.isDraft,
|
||||
commentReactions: vscodeComment.commentReactions ? vscodeComment.commentReactions.map(reaction => convertToReaction(provider, reaction)) : undefined
|
||||
};
|
||||
|
||||
@@ -12,8 +12,9 @@ import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/s
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export interface IExtensionMemento {
|
||||
get<T>(key: string): T | undefined;
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
update(key: string, value: any): Promise<boolean>;
|
||||
update(key: string, value: any): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IExtensionContext {
|
||||
|
||||
@@ -104,6 +104,36 @@ class FsLinkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
class ConsumerFileSystem implements vscode.FileSystem {
|
||||
|
||||
constructor(private _proxy: MainThreadFileSystemShape) { }
|
||||
|
||||
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
|
||||
return this._proxy.$stat(uri);
|
||||
}
|
||||
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
|
||||
return this._proxy.$readdir(uri);
|
||||
}
|
||||
createDirectory(uri: vscode.Uri): Promise<void> {
|
||||
return this._proxy.$mkdir(uri);
|
||||
}
|
||||
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
|
||||
return (await this._proxy.$readFile(uri)).buffer;
|
||||
}
|
||||
writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; } = { create: true, overwrite: true }): Promise<void> {
|
||||
return this._proxy.$writeFile(uri, VSBuffer.wrap(content), options);
|
||||
}
|
||||
delete(uri: vscode.Uri, options: { recursive: boolean; } = { recursive: false }): Promise<void> {
|
||||
return this._proxy.$delete(uri, { ...options, useTrash: false }); //todo@joh useTrash
|
||||
}
|
||||
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; } = { overwrite: false }): Promise<void> {
|
||||
return this._proxy.$rename(oldUri, newUri, options);
|
||||
}
|
||||
copy(source: vscode.Uri, destination: vscode.Uri, options: { overwrite: boolean } = { overwrite: false }): Promise<void> {
|
||||
return this._proxy.$copy(source, destination, options);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
|
||||
private readonly _proxy: MainThreadFileSystemShape;
|
||||
@@ -113,9 +143,10 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
private readonly _watches = new Map<number, IDisposable>();
|
||||
|
||||
private _linkProviderRegistration: IDisposable;
|
||||
// Used as a handle both for file system providers and resource label formatters (being lazy)
|
||||
private _handlePool: number = 0;
|
||||
|
||||
readonly fileSystem: vscode.FileSystem;
|
||||
|
||||
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
|
||||
this._usedSchemes.add(Schemas.file);
|
||||
@@ -128,6 +159,8 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
this._usedSchemes.add(Schemas.mailto);
|
||||
this._usedSchemes.add(Schemas.data);
|
||||
this._usedSchemes.add(Schemas.command);
|
||||
|
||||
this.fileSystem = new ConsumerFileSystem(this._proxy);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -223,31 +256,31 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$stat(handle: number, resource: UriComponents): Promise<files.IStat> {
|
||||
return Promise.resolve(this.getProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
}
|
||||
|
||||
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]> {
|
||||
return Promise.resolve(this.getProvider(handle).readDirectory(URI.revive(resource)));
|
||||
return Promise.resolve(this._getFsProvider(handle).readDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$readFile(handle: number, resource: UriComponents): Promise<VSBuffer> {
|
||||
return Promise.resolve(this.getProvider(handle).readFile(URI.revive(resource))).then(data => VSBuffer.wrap(data));
|
||||
return Promise.resolve(this._getFsProvider(handle).readFile(URI.revive(resource))).then(data => VSBuffer.wrap(data));
|
||||
}
|
||||
|
||||
$writeFile(handle: number, resource: UriComponents, content: VSBuffer, opts: files.FileWriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).writeFile(URI.revive(resource), content.buffer, opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).writeFile(URI.revive(resource), content.buffer, opts));
|
||||
}
|
||||
|
||||
$delete(handle: number, resource: UriComponents, opts: files.FileDeleteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).delete(URI.revive(resource), opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).delete(URI.revive(resource), opts));
|
||||
}
|
||||
|
||||
$rename(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
return Promise.resolve(this._getFsProvider(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
}
|
||||
|
||||
$copy(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.copy) {
|
||||
throw new Error('FileSystemProvider does not implement "copy"');
|
||||
}
|
||||
@@ -255,11 +288,11 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$mkdir(handle: number, resource: UriComponents): Promise<void> {
|
||||
return Promise.resolve(this.getProvider(handle).createDirectory(URI.revive(resource)));
|
||||
return Promise.resolve(this._getFsProvider(handle).createDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$watch(handle: number, session: number, resource: UriComponents, opts: files.IWatchOptions): void {
|
||||
const subscription = this.getProvider(handle).watch(URI.revive(resource), opts);
|
||||
const subscription = this._getFsProvider(handle).watch(URI.revive(resource), opts);
|
||||
this._watches.set(session, subscription);
|
||||
}
|
||||
|
||||
@@ -272,7 +305,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$open(handle: number, resource: UriComponents, opts: files.FileOpenOptions): Promise<number> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.open) {
|
||||
throw new Error('FileSystemProvider does not implement "open"');
|
||||
}
|
||||
@@ -280,7 +313,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$close(handle: number, fd: number): Promise<void> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.close) {
|
||||
throw new Error('FileSystemProvider does not implement "close"');
|
||||
}
|
||||
@@ -288,7 +321,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$read(handle: number, fd: number, pos: number, length: number): Promise<VSBuffer> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.read) {
|
||||
throw new Error('FileSystemProvider does not implement "read"');
|
||||
}
|
||||
@@ -299,14 +332,14 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}
|
||||
|
||||
$write(handle: number, fd: number, pos: number, data: VSBuffer): Promise<number> {
|
||||
const provider = this.getProvider(handle);
|
||||
const provider = this._getFsProvider(handle);
|
||||
if (!provider.write) {
|
||||
throw new Error('FileSystemProvider does not implement "write"');
|
||||
}
|
||||
return Promise.resolve(provider.write(fd, pos, data.buffer, 0, data.byteLength));
|
||||
}
|
||||
|
||||
private getProvider(handle: number): vscode.FileSystemProvider {
|
||||
private _getFsProvider(handle: number): vscode.FileSystemProvider {
|
||||
const provider = this._fsProvider.get(handle);
|
||||
if (!provider) {
|
||||
const err = new Error();
|
||||
|
||||
@@ -133,7 +133,7 @@ class CodeLensAdapter {
|
||||
result.lenses.push({
|
||||
cacheId: [cacheId, i],
|
||||
range: typeConvert.Range.from(lenses[i].range),
|
||||
command: this._commands.toInternal2(lenses[i].command, disposables)
|
||||
command: this._commands.toInternal(lenses[i].command, disposables)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ class CodeLensAdapter {
|
||||
}
|
||||
|
||||
newLens = newLens || lens;
|
||||
symbol.command = this._commands.toInternal2(newLens.command || CodeLensAdapter._badCmd, disposables);
|
||||
symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd, disposables);
|
||||
return symbol;
|
||||
});
|
||||
}
|
||||
@@ -368,7 +368,7 @@ class CodeActionAdapter {
|
||||
actions.push({
|
||||
_isSynthetic: true,
|
||||
title: candidate.title,
|
||||
command: this._commands.toInternal2(candidate, disposables),
|
||||
command: this._commands.toInternal(candidate, disposables),
|
||||
});
|
||||
} else {
|
||||
if (codeActionContext.only) {
|
||||
@@ -382,7 +382,7 @@ class CodeActionAdapter {
|
||||
// new school: convert code action
|
||||
actions.push({
|
||||
title: candidate.title,
|
||||
command: candidate.command && this._commands.toInternal2(candidate.command, disposables),
|
||||
command: candidate.command && this._commands.toInternal(candidate.command, disposables),
|
||||
diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.Diagnostic.from),
|
||||
edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit),
|
||||
kind: candidate.kind && candidate.kind.value,
|
||||
@@ -735,7 +735,7 @@ class SuggestAdapter {
|
||||
i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
|
||||
k: item.commitCharacters,
|
||||
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
m: this._commands.toInternal2(item.command, disposables),
|
||||
m: this._commands.toInternal(item.command, disposables),
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
|
||||
@@ -38,7 +38,9 @@ export class ExtensionMemento implements IExtensionMemento {
|
||||
return this._init;
|
||||
}
|
||||
|
||||
get<T>(key: string, defaultValue: T): T {
|
||||
get<T>(key: string): T | undefined;
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
get<T>(key: string, defaultValue?: T): T {
|
||||
let value = this._value[key];
|
||||
if (typeof value === 'undefined') {
|
||||
value = defaultValue;
|
||||
@@ -46,11 +48,9 @@ export class ExtensionMemento implements IExtensionMemento {
|
||||
return value;
|
||||
}
|
||||
|
||||
update(key: string, value: any): Promise<boolean> {
|
||||
update(key: string, value: any): Promise<void> {
|
||||
this._value[key] = value;
|
||||
return this._storage
|
||||
.setValue(this._shared, this._id, this._value)
|
||||
.then(() => true);
|
||||
return this._storage.setValue(this._shared, this._id, this._value);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -427,7 +427,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
|
||||
this._acceptInputCommand = acceptInputCommand;
|
||||
|
||||
const internal = this._commands.converter.toInternal2(acceptInputCommand, this._acceptInputDisposables.value);
|
||||
const internal = this._commands.converter.toInternal(acceptInputCommand, this._acceptInputDisposables.value);
|
||||
this._proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal });
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
|
||||
this._statusBarCommands = statusBarCommands;
|
||||
|
||||
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal2(c, this._statusBarDisposables.value!)) as CommandDto[];
|
||||
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c, this._statusBarDisposables.value!)) as CommandDto[];
|
||||
this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal });
|
||||
}
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@ class ExtHostTreeView<T> extends Disposable {
|
||||
description: extensionTreeItem.description,
|
||||
resourceUri: extensionTreeItem.resourceUri,
|
||||
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : undefined,
|
||||
command: extensionTreeItem.command ? this.commands.toInternal2(extensionTreeItem.command, disposable) : undefined,
|
||||
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command, disposable) : undefined,
|
||||
contextValue: extensionTreeItem.contextValue,
|
||||
icon,
|
||||
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
|
||||
|
||||
@@ -2319,3 +2319,8 @@ export enum ExtensionExecutionContext {
|
||||
Local = 1,
|
||||
Remote = 2
|
||||
}
|
||||
|
||||
export enum ExtensionKind {
|
||||
UI = 1,
|
||||
Workspace = 2
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
this._onMessageEmitter.dispose();
|
||||
}
|
||||
|
||||
public get resourceRoot(): Promise<string> {
|
||||
return this._proxy.$getResourceRoot(this._handle);
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
this.assertNotDisposed();
|
||||
return this._html;
|
||||
|
||||
@@ -125,10 +125,11 @@ export function createApiFactory(
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(LogOutputChannelFactory, initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
if (initData.remoteAuthority) {
|
||||
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
extHostTask.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remoteAuthority,
|
||||
authority: initData.remote.authority,
|
||||
platform: process.platform
|
||||
});
|
||||
|
||||
@@ -150,7 +151,7 @@ export function createApiFactory(
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register an output channel for exthost log
|
||||
const outputChannelName = initData.remoteAuthority ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host");
|
||||
const outputChannelName = initData.remote.isRemote ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host");
|
||||
extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile);
|
||||
|
||||
// Register API-ish commands
|
||||
@@ -255,10 +256,22 @@ export function createApiFactory(
|
||||
return extHostClipboard;
|
||||
},
|
||||
get shell() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTerminalService.getDefaultShell(configProvider);
|
||||
},
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remoteAuthority });
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
get remoteName() {
|
||||
if (!initData.remote.authority) {
|
||||
return undefined;
|
||||
}
|
||||
const pos = initData.remote.authority.indexOf('+');
|
||||
if (pos < 0) {
|
||||
// funky? bad authority?
|
||||
return initData.remote.authority;
|
||||
}
|
||||
return initData.remote.authority.substr(0, pos);
|
||||
}
|
||||
};
|
||||
if (!initData.environment.extensionTestsLocationURI) {
|
||||
@@ -266,17 +279,21 @@ export function createApiFactory(
|
||||
Object.freeze(env);
|
||||
}
|
||||
|
||||
const extensionKind = initData.remote.isRemote
|
||||
? extHostTypes.ExtensionKind.Workspace
|
||||
: extHostTypes.ExtensionKind.UI;
|
||||
|
||||
// namespace: extensions
|
||||
const extensions: typeof vscode.extensions = {
|
||||
getExtension(extensionId: string): Extension<any> | undefined {
|
||||
const desc = extensionRegistry.getExtensionDescription(extensionId);
|
||||
if (desc) {
|
||||
return new Extension(extensionService, desc);
|
||||
return new Extension(extensionService, desc, extensionKind);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
get all(): Extension<any>[] {
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc, extensionKind));
|
||||
},
|
||||
get onDidChange() {
|
||||
return extensionRegistry.onDidChange;
|
||||
@@ -501,12 +518,13 @@ export function createApiFactory(
|
||||
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
|
||||
return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options);
|
||||
},
|
||||
createWebviewTextEditorInset(editor: vscode.TextEditor, range: vscode.Range, options: vscode.WebviewOptions): vscode.WebviewEditorInset {
|
||||
createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions): vscode.WebviewEditorInset {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostEditorInsets.createWebviewEditorInset(editor, range, options, extension);
|
||||
return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension);
|
||||
},
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
if (typeof nameOrOptions === 'object') {
|
||||
nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi);
|
||||
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
|
||||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
@@ -656,6 +674,10 @@ export function createApiFactory(
|
||||
registerFileSystemProvider(scheme, provider, options) {
|
||||
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
|
||||
},
|
||||
get fs() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostFileSystem.fileSystem;
|
||||
},
|
||||
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
return extHostSearch.registerFileSearchProvider(scheme, provider);
|
||||
}),
|
||||
@@ -820,6 +842,7 @@ export function createApiFactory(
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
CustomExecution: extHostTypes.CustomExecution,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
@@ -887,16 +910,18 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
private _extensionService: ExtHostExtensionService;
|
||||
private _identifier: ExtensionIdentifier;
|
||||
|
||||
public id: string;
|
||||
public extensionPath: string;
|
||||
public packageJSON: IExtensionDescription;
|
||||
readonly id: string;
|
||||
readonly extensionPath: string;
|
||||
readonly packageJSON: IExtensionDescription;
|
||||
readonly extensionKind: vscode.ExtensionKind;
|
||||
|
||||
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription) {
|
||||
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription, kind: extHostTypes.ExtensionKind) {
|
||||
this._extensionService = extensionService;
|
||||
this._identifier = description.identifier;
|
||||
this.id = description.identifier.value;
|
||||
this.extensionPath = path.normalize(originalFSPath(description.extensionLocation));
|
||||
this.packageJSON = description;
|
||||
this.extensionKind = kind;
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
|
||||
@@ -36,9 +36,15 @@ import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/work
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
|
||||
interface ITestRunner {
|
||||
/** Old test runner API, as exported from `vscode/lib/testrunner` */
|
||||
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
||||
}
|
||||
|
||||
interface INewTestRunner {
|
||||
/** New test runner API, as explained in the extension test doc */
|
||||
run(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IHostUtils {
|
||||
exit(code?: number): void;
|
||||
exists(path: string): Promise<boolean>;
|
||||
@@ -153,7 +159,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
const extensionPaths = await this.getExtensionPathIndex();
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new VSCodeNodeModuleFactory(this._extensionApiFactory, extensionPaths, this._registry, configProvider));
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar), this._environment));
|
||||
if (this._initData.remoteAuthority) {
|
||||
if (this._initData.remote.isRemote) {
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new OpenNodeModuleFactory(
|
||||
this._extHostContext.getProxy(MainContext.MainThreadWindow),
|
||||
this._extHostContext.getProxy(MainContext.MainThreadTelemetry),
|
||||
@@ -340,7 +346,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
});
|
||||
}
|
||||
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<IExtensionContext> {
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
||||
|
||||
const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
|
||||
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
|
||||
@@ -361,7 +367,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
globalStoragePath: this._storagePath.globalValue(extensionDescription),
|
||||
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier),
|
||||
executionContext: this._initData.remoteAuthority ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local
|
||||
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -525,7 +531,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
const extensionTestsPath = originalFSPath(extensionTestsLocationURI);
|
||||
|
||||
// Require the test runner via node require from the provided path
|
||||
let testRunner: ITestRunner | undefined;
|
||||
let testRunner: ITestRunner | INewTestRunner | undefined;
|
||||
let requireError: Error | undefined;
|
||||
try {
|
||||
testRunner = <any>require.__$__nodeRequire(extensionTestsPath);
|
||||
@@ -533,10 +539,10 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
requireError = error;
|
||||
}
|
||||
|
||||
// Execute the runner if it follows our spec
|
||||
// Execute the runner if it follows the old `run` spec
|
||||
if (testRunner && typeof testRunner.run === 'function') {
|
||||
return new Promise<void>((c, e) => {
|
||||
testRunner!.run(extensionTestsPath, (error, failures) => {
|
||||
const oldTestRunnerCallback = (error: Error, failures: number | undefined) => {
|
||||
if (error) {
|
||||
e(error.toString());
|
||||
} else {
|
||||
@@ -545,7 +551,22 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
// after tests have run, we shutdown the host
|
||||
this._gracefulExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
|
||||
});
|
||||
};
|
||||
|
||||
const runResult = testRunner!.run(extensionTestsPath, oldTestRunnerCallback);
|
||||
|
||||
// Using the new API `run(): Promise<void>`
|
||||
if (runResult && runResult.then) {
|
||||
runResult
|
||||
.then(() => {
|
||||
c();
|
||||
this._gracefulExit(0);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
e(err.toString());
|
||||
this._gracefulExit(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -562,7 +583,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => {
|
||||
// If extension tests are running, give the exit code to the renderer
|
||||
if (this._initData.remoteAuthority && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
if (this._initData.remote.isRemote && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
@@ -20,7 +20,8 @@ import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
|
||||
@@ -115,9 +116,9 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
env?: { [key: string]: string | null },
|
||||
waitOnExit?: boolean,
|
||||
strictEnv?: boolean,
|
||||
runInBackground?: boolean
|
||||
hideFromUser?: boolean
|
||||
): void {
|
||||
this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, runInBackground).then(terminal => {
|
||||
this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser).then(terminal => {
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
});
|
||||
@@ -312,7 +313,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
|
||||
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.runInBackground);
|
||||
terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.hideFromUser);
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
@@ -338,12 +339,22 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return terminalEnvironment.getDefaultShell(
|
||||
fetchSetting,
|
||||
this._isWorkspaceShellAllowed,
|
||||
getDefaultShell(platform.platform),
|
||||
getSystemShell(platform.platform),
|
||||
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
||||
process.env.windir
|
||||
);
|
||||
}
|
||||
|
||||
private _getDefaultShellArgs(configProvider: ExtHostConfigProvider): string[] | string | undefined {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed);
|
||||
}
|
||||
|
||||
public async resolveTerminalRenderer(id: number): Promise<vscode.TerminalRenderer> {
|
||||
// Check to see if the extension host already knows about this terminal.
|
||||
for (const terminalRenderer of this._terminalRenderers) {
|
||||
@@ -399,6 +410,11 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void {
|
||||
this._getTerminalByIdEventually(id).then(() => {
|
||||
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
@@ -472,6 +488,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
};
|
||||
}
|
||||
|
||||
private async _getNonInheritedEnv(): Promise<platform.IProcessEnvironment> {
|
||||
const env = await getMainProcessParentEnv();
|
||||
env.VSCODE_IPC_HOOK_CLI = process.env['VSCODE_IPC_HOOK_CLI']!;
|
||||
return env;
|
||||
}
|
||||
|
||||
public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name: shellLaunchConfigDto.name,
|
||||
@@ -485,20 +507,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
if (!shellLaunchConfig.executable) {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
terminalEnvironment.mergeDefaultShellPathAndArgs(
|
||||
shellLaunchConfig,
|
||||
fetchSetting,
|
||||
isWorkspaceShellAllowed || false,
|
||||
getDefaultShell(platform.platform),
|
||||
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
|
||||
process.env.windir
|
||||
);
|
||||
shellLaunchConfig.executable = this.getDefaultShell(configProvider);
|
||||
shellLaunchConfig.args = this._getDefaultShellArgs(configProvider);
|
||||
}
|
||||
|
||||
// Get the initial cwd
|
||||
@@ -519,6 +529,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
const envFromConfig = this._apiInspectConfigToPlain(configProvider.getConfiguration('terminal.integrated').inspect<ITerminalEnvironment>(`env.${platformKey}`));
|
||||
const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2();
|
||||
const variableResolver = workspaceFolders ? new ExtHostVariableResolverService(workspaceFolders, this._extHostDocumentsAndEditors, configProvider) : undefined;
|
||||
const baseEnv = terminalConfig.get<boolean>('inheritEnv', true) ? process.env as platform.IProcessEnvironment : await this._getNonInheritedEnv();
|
||||
const env = terminalEnvironment.createTerminalEnvironment(
|
||||
shellLaunchConfig,
|
||||
lastActiveWorkspace,
|
||||
@@ -527,14 +538,15 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
isWorkspaceShellAllowed,
|
||||
pkg.version,
|
||||
terminalConfig.get<boolean>('setLocaleVariables', false),
|
||||
// Always inherit the environment as we need to be running in a login shell, this may
|
||||
// change when macOS servers are supported
|
||||
process.env as platform.IProcessEnvironment
|
||||
baseEnv
|
||||
);
|
||||
|
||||
// Fork the process and listen for messages
|
||||
this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env);
|
||||
const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, terminalConfig.get('windowsEnableConpty') as boolean, this._logService);
|
||||
// TODO: Support conpty on remote, it doesn't seem to work for some reason?
|
||||
// TODO: When conpty is enabled, only enable it when accessibilityMode is off
|
||||
const enableConpty = false; //terminalConfig.get('windowsEnableConpty') as boolean;
|
||||
const p = new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService);
|
||||
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
|
||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||
p.onProcessData(data => this._proxy.$sendProcessData(id, data));
|
||||
@@ -573,6 +585,18 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return id;
|
||||
}
|
||||
|
||||
public $requestAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
return detectAvailableShells();
|
||||
}
|
||||
|
||||
public async $requestDefaultShellAndArgs(): Promise<IShellAndArgsDto> {
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
return Promise.resolve({
|
||||
shell: this.getDefaultShell(configProvider),
|
||||
args: this._getDefaultShellArgs(configProvider)
|
||||
});
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove listeners
|
||||
this._terminalProcesses[id].dispose();
|
||||
|
||||
Reference in New Issue
Block a user