Merge from vscode 1ce89e2cb720d69c496c2815c4696ee4fd4429a6 (#6779)

* Merge from vscode 1ce89e2cb720d69c496c2815c4696ee4fd4429a6

* redisable accounts because of issues
This commit is contained in:
Anthony Dresser
2019-08-15 23:56:46 -07:00
committed by GitHub
parent fb4e3c6a05
commit 6f297efb88
166 changed files with 1941 additions and 1279 deletions

View File

@@ -225,11 +225,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
getCommands(filterInternal: boolean = false): Thenable<string[]> {
return extHostCommands.getCommands(filterInternal);
},
onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => {
checkProposedApiEnabled(extension);
return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables);
}),
}
};
// namespace: env

View File

@@ -21,7 +21,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model'
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import * as modes from 'vs/editor/common/modes';
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -119,8 +119,6 @@ export interface MainThreadClipboardShape extends IDisposable {
export interface MainThreadCommandsShape extends IDisposable {
$registerCommand(id: string): void;
$registerCommandListener(): void;
$unregisterCommandListener(): void;
$unregisterCommand(id: string): void;
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined>;
$getCommands(): Promise<string[]>;
@@ -246,7 +244,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
}
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean }): void;
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void>;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
@@ -739,7 +737,6 @@ export interface MainThreadWindowShape extends IDisposable {
export interface ExtHostCommandsShape {
$executeContributedCommand<T>(id: string, ...args: any[]): Promise<T>;
$getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>;
$handleDidExecuteCommand(command: ICommandEvent): void;
}
export interface ExtHostConfigurationShape {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { validateConstraint } from 'vs/base/common/types';
import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { cloneAndChange } from 'vs/base/common/objects';
@@ -17,7 +17,6 @@ import { revive } from 'vs/base/common/marshalling';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -36,9 +35,6 @@ export class ExtHostCommands implements ExtHostCommandsShape {
readonly _serviceBrand: any;
private readonly _onDidExecuteCommand: Emitter<vscode.CommandExecutionEvent>;
readonly onDidExecuteCommand: Event<vscode.CommandExecutionEvent>;
private readonly _commands = new Map<string, CommandHandler>();
private readonly _proxy: MainThreadCommandsShape;
private readonly _converter: CommandsConverter;
@@ -50,11 +46,6 @@ export class ExtHostCommands implements ExtHostCommandsShape {
@ILogService logService: ILogService
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadCommands);
this._onDidExecuteCommand = new Emitter<vscode.CommandExecutionEvent>({
onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(),
onLastListenerRemove: () => this._proxy.$unregisterCommandListener(),
});
this.onDidExecuteCommand = Event.filter(this._onDidExecuteCommand.event, e => e.command[0] !== '_'); // filter 'private' commands
this._logService = logService;
this._converter = new CommandsConverter(this);
this._argumentProcessors = [
@@ -119,22 +110,13 @@ export class ExtHostCommands implements ExtHostCommandsShape {
});
}
$handleDidExecuteCommand(command: ICommandEvent): void {
this._onDidExecuteCommand.fire({
command: command.commandId,
arguments: command.args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg))
});
}
executeCommand<T>(id: string, ...args: any[]): Promise<T> {
this._logService.trace('ExtHostCommands#executeCommand', id);
if (this._commands.has(id)) {
// we stay inside the extension host and support
// to pass any kind of parameters around
const res = this._executeContributedCommand<T>(id, args);
this._onDidExecuteCommand.fire({ command: id, arguments: args });
return res;
return this._executeContributedCommand<T>(id, args);
} else {
// automagically convert some argument types

View File

@@ -0,0 +1,291 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TernarySearchTree } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { MainThreadTelemetryShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import * as vscode from 'vscode';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { endsWith } from 'vs/base/common/strings';
import { IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { platform } from 'vs/base/common/process';
import { AzdataNodeModuleFactory, SqlopsNodeModuleFactory } from 'sql/workbench/api/common/extHostRequireInterceptor'; // {{SQL CARBON EDIT}}
import { IExtensionApiFactory as sqlIApiFactory } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}}
interface LoadFunction {
(request: string, parent: { filename: string; }, isMain: any): any;
}
export interface INodeModuleFactory { //{{SQL CARBON EDIT}} export interface
readonly nodeModuleName: string | string[];
load(request: string, parent: URI, isMain: any, original: LoadFunction): any;
alternativeModuleName?(name: string): string | undefined;
}
export abstract class RequireInterceptor {
protected readonly _factories: Map<string, INodeModuleFactory>;
protected readonly _alternatives: ((moduleName: string) => string | undefined)[];
constructor(
private _apiFactory: sqlIApiFactory, // {{SQL CARBON EDIT}} replace with ours
private _extensionRegistry: ExtensionDescriptionRegistry,
@IInstantiationService private readonly _instaService: IInstantiationService,
@IExtHostConfiguration private readonly _extHostConfiguration: IExtHostConfiguration,
@IExtHostExtensionService private readonly _extHostExtensionService: IExtHostExtensionService,
@IExtHostInitDataService private readonly _initData: IExtHostInitDataService
) {
this._factories = new Map<string, INodeModuleFactory>();
this._alternatives = [];
}
async install(): Promise<void> {
this._installInterceptor();
const configProvider = await this._extHostConfiguration.getConfigProvider();
const extensionPaths = await this._extHostExtensionService.getExtensionPathIndex();
this.register(new VSCodeNodeModuleFactory(this._apiFactory.vscode, extensionPaths, this._extensionRegistry, configProvider)); // {{SQL CARBON EDIT}} // add node module
this.register(new AzdataNodeModuleFactory(this._apiFactory.azdata, extensionPaths)); // {{SQL CARBON EDIT}} // add node module
this.register(new SqlopsNodeModuleFactory(this._apiFactory.sqlops, extensionPaths)); // {{SQL CARBON EDIT}} // add node module
this.register(this._instaService.createInstance(KeytarNodeModuleFactory));
if (this._initData.remote.isRemote) {
this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths));
}
}
protected abstract _installInterceptor(): void;
public register(interceptor: INodeModuleFactory): void {
if (Array.isArray(interceptor.nodeModuleName)) {
for (let moduleName of interceptor.nodeModuleName) {
this._factories.set(moduleName, interceptor);
}
} else {
this._factories.set(interceptor.nodeModuleName, interceptor);
}
if (typeof interceptor.alternativeModuleName === 'function') {
this._alternatives.push((moduleName) => {
return interceptor.alternativeModuleName!(moduleName);
});
}
}
}
//#region --- vscode-module
class VSCodeNodeModuleFactory implements INodeModuleFactory {
public readonly nodeModuleName = 'vscode';
private readonly _extApiImpl = new Map<string, typeof vscode>();
private _defaultApiImpl?: typeof vscode;
constructor(
private readonly _apiFactory: IExtensionApiFactory,
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
private readonly _extensionRegistry: ExtensionDescriptionRegistry,
private readonly _configProvider: ExtHostConfigProvider
) {
}
public load(_request: string, parent: URI): any {
// get extension id from filename and api for extension
const ext = this._extensionPaths.findSubstr(parent.fsPath);
if (ext) {
let apiImpl = this._extApiImpl.get(ExtensionIdentifier.toKey(ext.identifier));
if (!apiImpl) {
apiImpl = this._apiFactory(ext, this._extensionRegistry, this._configProvider);
this._extApiImpl.set(ExtensionIdentifier.toKey(ext.identifier), apiImpl);
}
return apiImpl;
}
// fall back to a default implementation
if (!this._defaultApiImpl) {
let extensionPathsPretty = '';
this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`);
console.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`);
this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider);
}
return this._defaultApiImpl;
}
}
//#endregion
//#region --- keytar-module
interface IKeytarModule {
getPassword(service: string, account: string): Promise<string | null>;
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
findPassword(service: string): Promise<string | null>;
}
class KeytarNodeModuleFactory implements INodeModuleFactory {
public readonly nodeModuleName: string = 'keytar';
private alternativeNames: Set<string> | undefined;
private _impl: IKeytarModule;
constructor(
@IExtHostRpcService rpcService: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
) {
const { environment } = initData;
const mainThreadKeytar = rpcService.getProxy(MainContext.MainThreadKeytar);
if (environment.appRoot) {
let appRoot = environment.appRoot.fsPath;
if (platform === 'win32') {
appRoot = appRoot.replace(/\\/g, '/');
}
if (appRoot[appRoot.length - 1] === '/') {
appRoot = appRoot.substr(0, appRoot.length - 1);
}
this.alternativeNames = new Set();
this.alternativeNames.add(`${appRoot}/node_modules.asar/keytar`);
this.alternativeNames.add(`${appRoot}/node_modules/keytar`);
}
this._impl = {
getPassword: (service: string, account: string): Promise<string | null> => {
return mainThreadKeytar.$getPassword(service, account);
},
setPassword: (service: string, account: string, password: string): Promise<void> => {
return mainThreadKeytar.$setPassword(service, account, password);
},
deletePassword: (service: string, account: string): Promise<boolean> => {
return mainThreadKeytar.$deletePassword(service, account);
},
findPassword: (service: string): Promise<string | null> => {
return mainThreadKeytar.$findPassword(service);
}
};
}
public load(_request: string, _parent: URI): any {
return this._impl;
}
public alternativeModuleName(name: string): string | undefined {
const length = name.length;
// We need at least something like: `?/keytar` which requires
// more than 7 characters.
if (length <= 7 || !this.alternativeNames) {
return undefined;
}
const sep = length - 7;
if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && endsWith(name, 'keytar')) {
name = name.replace(/\\/g, '/');
if (this.alternativeNames.has(name)) {
return 'keytar';
}
}
return undefined;
}
}
//#endregion
//#region --- opn/open-module
interface OpenOptions {
wait: boolean;
app: string | string[];
}
interface IOriginalOpen {
(target: string, options?: OpenOptions): Thenable<any>;
}
interface IOpenModule {
(target: string, options?: OpenOptions): Thenable<void>;
}
class OpenNodeModuleFactory implements INodeModuleFactory {
public readonly nodeModuleName: string[] = ['open', 'opn'];
private _extensionId: string | undefined;
private _original?: IOriginalOpen;
private _impl: IOpenModule;
private _mainThreadTelemetry: MainThreadTelemetryShape;
constructor(
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
@IExtHostRpcService rpcService: IExtHostRpcService,
) {
this._mainThreadTelemetry = rpcService.getProxy(MainContext.MainThreadTelemetry);
const mainThreadWindow = rpcService.getProxy(MainContext.MainThreadWindow);
this._impl = (target, options) => {
const uri: URI = URI.parse(target);
// If we have options use the original method.
if (options) {
return this.callOriginal(target, options);
}
if (uri.scheme === 'http' || uri.scheme === 'https') {
return mainThreadWindow.$openUri(uri, { allowTunneling: true });
} else if (uri.scheme === 'mailto') {
return mainThreadWindow.$openUri(uri, {});
}
return this.callOriginal(target, options);
};
}
public load(request: string, parent: URI, isMain: any, original: LoadFunction): any {
// get extension id from filename and api for extension
const extension = this._extensionPaths.findSubstr(parent.fsPath);
if (extension) {
this._extensionId = extension.identifier.value;
this.sendShimmingTelemetry();
}
this._original = original(request, { filename: parent.fsPath }, isMain);
return this._impl;
}
private callOriginal(target: string, options: OpenOptions | undefined): Thenable<any> {
this.sendNoForwardTelemetry();
return this._original!(target, options);
}
private sendShimmingTelemetry(): void {
if (!this._extensionId) {
return;
}
type ShimmingOpenClassification = {
extension: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
this._mainThreadTelemetry.$publicLog2<{ extension: string }, ShimmingOpenClassification>('shimming.open', { extension: this._extensionId });
}
private sendNoForwardTelemetry(): void {
if (!this._extensionId) {
return;
}
type ShimmingOpenCallNoForwardClassification = {
extension: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
this._mainThreadTelemetry.$publicLog2<{ extension: string }, ShimmingOpenCallNoForwardClassification>('shimming.open.call.noForward', { extension: this._extensionId });
}
}
//#endregion

View File

@@ -55,10 +55,21 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
private commands: ExtHostCommands,
private logService: ILogService
) {
function isTreeViewItemHandleArg(arg: any): boolean {
return arg && arg.$treeViewId && arg.$treeItemHandle;
}
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$treeViewId && arg.$treeItemHandle) {
if (isTreeViewItemHandleArg(arg)) {
return this.convertArgument(arg);
} else if (Array.isArray(arg) && (arg.length > 0)) {
return arg.map(item => {
if (isTreeViewItemHandleArg(item)) {
return this.convertArgument(item);
}
return item;
});
}
return arg;
}
@@ -187,13 +198,10 @@ export class ExtHostTreeView<T> extends Disposable {
private refreshPromise: Promise<void> = Promise.resolve();
private refreshQueue: Promise<void> = Promise.resolve();
constructor(private viewId: string, options: vscode.TreeViewOptions<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
constructor(private viewId: string, options: vscode.TreeViewOptions2<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
super();
this.dataProvider = options.treeDataProvider;
// {{SQL CARBON EDIT}}
if (this.proxy) {
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll });
}
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
if (this.dataProvider.onDidChangeTreeData) {
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
}