Merge remote-tracking branch 'origin/master' into misolori/new-icons

This commit is contained in:
Miguel Solorio
2019-06-28 11:05:33 -07:00
614 changed files with 10271 additions and 9127 deletions

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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));
}
}
}

View File

@@ -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) {

View File

@@ -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 {