mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 02:58:31 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -11,9 +11,8 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as EditorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Model as EditorModel } from 'vs/editor/common/model/model';
|
||||
import { TestThreadService } from './testThreadService';
|
||||
import { TextModel as EditorModel } from 'vs/editor/common/model/textModel';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
@@ -32,10 +31,11 @@ import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import * as vscode from 'vscode';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import 'vs/workbench/parts/search/electron-browser/search.contribution';
|
||||
import { NoopLogService } from 'vs/platform/log/common/log';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
|
||||
const defaultSelector = { scheme: 'far' };
|
||||
const model: EditorCommon.IModel = EditorModel.createFromString(
|
||||
const model: ITextModel = EditorModel.createFromString(
|
||||
[
|
||||
'This is the first line',
|
||||
'This is the second line',
|
||||
@@ -45,7 +45,7 @@ const model: EditorCommon.IModel = EditorModel.createFromString(
|
||||
undefined,
|
||||
URI.parse('far://testing/file.b'));
|
||||
|
||||
let threadService: TestThreadService;
|
||||
let rpcProtocol: TestRPCProtocol;
|
||||
let extHost: ExtHostLanguageFeatures;
|
||||
let mainThread: MainThreadLanguageFeatures;
|
||||
let commands: ExtHostCommands;
|
||||
@@ -63,7 +63,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
let inst: IInstantiationService;
|
||||
{
|
||||
let instantiationService = new TestInstantiationService();
|
||||
threadService = new TestThreadService();
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
instantiationService.stub(IHeapService, {
|
||||
_serviceBrand: undefined,
|
||||
trackRecursive(args) {
|
||||
@@ -98,36 +98,36 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
inst = instantiationService;
|
||||
}
|
||||
|
||||
const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(threadService);
|
||||
const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol);
|
||||
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
versionId: model.getVersionId(),
|
||||
modeId: model.getLanguageIdentifier().language,
|
||||
url: model.uri,
|
||||
uri: model.uri,
|
||||
lines: model.getValue().split(model.getEOL()),
|
||||
EOL: model.getEOL(),
|
||||
}]
|
||||
});
|
||||
const extHostDocuments = new ExtHostDocuments(threadService, extHostDocumentsAndEditors);
|
||||
threadService.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
|
||||
const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
|
||||
|
||||
const heapService = new ExtHostHeapService();
|
||||
|
||||
commands = new ExtHostCommands(threadService, heapService, new NoopLogService());
|
||||
threadService.set(ExtHostContext.ExtHostCommands, commands);
|
||||
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));
|
||||
commands = new ExtHostCommands(rpcProtocol, heapService, new NullLogService());
|
||||
rpcProtocol.set(ExtHostContext.ExtHostCommands, commands);
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol));
|
||||
ExtHostApiCommands.register(commands);
|
||||
|
||||
const diagnostics = new ExtHostDiagnostics(threadService);
|
||||
threadService.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
|
||||
const diagnostics = new ExtHostDiagnostics(rpcProtocol);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
|
||||
|
||||
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, heapService, diagnostics);
|
||||
threadService.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
|
||||
extHost = new ExtHostLanguageFeatures(rpcProtocol, extHostDocuments, commands, heapService, diagnostics);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
|
||||
|
||||
mainThread = <MainThreadLanguageFeatures>threadService.setTestInstance(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, threadService));
|
||||
mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, rpcProtocol));
|
||||
|
||||
threadService.sync().then(done, done);
|
||||
rpcProtocol.sync().then(done, done);
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
@@ -140,7 +140,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
while (disposables.length) {
|
||||
disposables.pop().dispose();
|
||||
}
|
||||
threadService.sync()
|
||||
rpcProtocol.sync()
|
||||
.then(() => done(), err => done(err));
|
||||
});
|
||||
|
||||
@@ -154,13 +154,11 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true)
|
||||
];
|
||||
|
||||
// threadService.sync().then(() => {
|
||||
TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
|
||||
assert.equal(err.length, 4);
|
||||
done();
|
||||
return [];
|
||||
});
|
||||
// });
|
||||
});
|
||||
|
||||
test('WorkspaceSymbols, back and forth', function (done) {
|
||||
@@ -182,7 +180,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
threadService.sync().then(() => {
|
||||
rpcProtocol.sync().then(() => {
|
||||
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {
|
||||
|
||||
for (let info of value) {
|
||||
@@ -204,11 +202,11 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
await threadService.sync();
|
||||
await rpcProtocol.sync();
|
||||
let symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '');
|
||||
assert.equal(symbols.length, 1);
|
||||
|
||||
await threadService.sync();
|
||||
await rpcProtocol.sync();
|
||||
symbols = await commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', '*');
|
||||
assert.equal(symbols.length, 1);
|
||||
});
|
||||
@@ -223,13 +221,11 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
commands.executeCommand('vscode.executeDefinitionProvider', true, false)
|
||||
];
|
||||
|
||||
// threadService.sync().then(() => {
|
||||
TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
|
||||
assert.equal(err.length, 4);
|
||||
done();
|
||||
return [];
|
||||
});
|
||||
// });
|
||||
});
|
||||
|
||||
test('Definition, back and forth', function () {
|
||||
@@ -249,7 +245,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.uri, new types.Position(0, 0)).then(values => {
|
||||
assert.equal(values.length, 4);
|
||||
for (let v of values) {
|
||||
@@ -295,7 +291,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
threadService.sync().then(() => {
|
||||
rpcProtocol.sync().then(() => {
|
||||
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {
|
||||
assert.equal(values.length, 2);
|
||||
let [first, second] = values;
|
||||
@@ -325,7 +321,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4)).then(list => {
|
||||
|
||||
assert.ok(list instanceof types.CompletionList);
|
||||
@@ -375,7 +371,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
threadService.sync().then(() => {
|
||||
rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.CompletionList>('vscode.executeCompletionItemProvider', model.uri, new types.Position(0, 4)).then(list => {
|
||||
assert.ok(list instanceof types.CompletionList);
|
||||
assert.equal(list.isIncomplete, true);
|
||||
@@ -393,7 +389,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -404,6 +400,35 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
});
|
||||
});
|
||||
|
||||
test('vscode.executeCodeActionProvider results seem to be missing their `command` property #45124', function () {
|
||||
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
|
||||
provideCodeActions(document, range): vscode.CodeAction[] {
|
||||
return [{
|
||||
command: {
|
||||
arguments: [document, range],
|
||||
command: 'command',
|
||||
title: 'command_title',
|
||||
},
|
||||
kind: types.CodeActionKind.Empty.append('foo'),
|
||||
title: 'title',
|
||||
}];
|
||||
}
|
||||
}));
|
||||
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.CodeAction[]>('vscode.executeCodeActionProvider', model.uri, new types.Range(0, 0, 1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
assert.ok(first.command);
|
||||
assert.equal(first.command.command, 'command');
|
||||
assert.equal(first.command.title, 'command_title');
|
||||
assert.equal(first.kind.value, 'foo');
|
||||
assert.equal(first.title, 'title');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// --- code lens
|
||||
|
||||
test('CodeLens, back and forth', function () {
|
||||
@@ -420,7 +445,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.uri).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -442,7 +467,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return commands.executeCommand<vscode.DocumentLink[]>('vscode.executeLinkProvider', model.uri).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
|
||||
@@ -8,11 +8,10 @@
|
||||
import * as assert from 'assert';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { MainThreadCommandsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { OneGetThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { NoopLogService } from 'vs/platform/log/common/log';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostCommands', function () {
|
||||
|
||||
@@ -21,16 +20,15 @@ suite('ExtHostCommands', function () {
|
||||
let lastUnregister: string;
|
||||
|
||||
const shape = new class extends mock<MainThreadCommandsShape>() {
|
||||
$registerCommand(id: string): TPromise<any> {
|
||||
return undefined;
|
||||
$registerCommand(id: string): void {
|
||||
//
|
||||
}
|
||||
$unregisterCommand(id: string): TPromise<any> {
|
||||
$unregisterCommand(id: string): void {
|
||||
lastUnregister = id;
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined, new NoopLogService());
|
||||
const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), undefined, new NullLogService());
|
||||
commands.registerCommand('foo', (): any => { }).dispose();
|
||||
assert.equal(lastUnregister, 'foo');
|
||||
assert.equal(CommandsRegistry.getCommand('foo'), undefined);
|
||||
@@ -42,16 +40,15 @@ suite('ExtHostCommands', function () {
|
||||
let unregisterCounter = 0;
|
||||
|
||||
const shape = new class extends mock<MainThreadCommandsShape>() {
|
||||
$registerCommand(id: string): TPromise<any> {
|
||||
return undefined;
|
||||
$registerCommand(id: string): void {
|
||||
//
|
||||
}
|
||||
$unregisterCommand(id: string): TPromise<any> {
|
||||
$unregisterCommand(id: string): void {
|
||||
unregisterCounter += 1;
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const commands = new ExtHostCommands(OneGetThreadService(shape), undefined, new NoopLogService());
|
||||
const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), undefined, new NullLogService());
|
||||
const reg = commands.registerCommand('foo', (): any => { });
|
||||
reg.dispose();
|
||||
reg.dispose();
|
||||
|
||||
@@ -12,10 +12,11 @@ import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration
|
||||
import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { TestThreadService } from './testThreadService';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostConfiguration', function () {
|
||||
|
||||
@@ -31,7 +32,7 @@ suite('ExtHostConfiguration', function () {
|
||||
if (!shape) {
|
||||
shape = new class extends mock<MainThreadConfigurationShape>() { };
|
||||
}
|
||||
return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestThreadService(), null), createConfigurationData(contents));
|
||||
return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService()), createConfigurationData(contents));
|
||||
}
|
||||
|
||||
function createConfigurationData(contents: any): IConfigurationInitData {
|
||||
@@ -40,7 +41,7 @@ suite('ExtHostConfiguration', function () {
|
||||
user: new ConfigurationModel(contents),
|
||||
workspace: new ConfigurationModel(),
|
||||
folders: Object.create(null),
|
||||
configurationScopes: []
|
||||
configurationScopes: {}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -135,7 +136,7 @@ suite('ExtHostConfiguration', function () {
|
||||
test('inspect in no workspace context', function () {
|
||||
const testObject = new ExtHostConfiguration(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
new ExtHostWorkspace(new TestThreadService(), null),
|
||||
new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService()),
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
@@ -149,7 +150,7 @@ suite('ExtHostConfiguration', function () {
|
||||
}, ['editor.wordWrap']),
|
||||
workspace: new ConfigurationModel({}, []),
|
||||
folders: Object.create(null),
|
||||
configurationScopes: []
|
||||
configurationScopes: {}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -177,11 +178,11 @@ suite('ExtHostConfiguration', function () {
|
||||
folders[workspaceUri.toString()] = workspace;
|
||||
const testObject = new ExtHostConfiguration(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
new ExtHostWorkspace(new TestThreadService(), {
|
||||
new ExtHostWorkspace(new TestRPCProtocol(), {
|
||||
'id': 'foo',
|
||||
'folders': [aWorkspaceFolder(URI.file('foo'), 0)],
|
||||
'name': 'foo'
|
||||
}),
|
||||
}, new NullLogService()),
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
@@ -195,7 +196,7 @@ suite('ExtHostConfiguration', function () {
|
||||
}, ['editor.wordWrap']),
|
||||
workspace,
|
||||
folders,
|
||||
configurationScopes: []
|
||||
configurationScopes: {}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -250,11 +251,11 @@ suite('ExtHostConfiguration', function () {
|
||||
|
||||
const testObject = new ExtHostConfiguration(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
new ExtHostWorkspace(new TestThreadService(), {
|
||||
new ExtHostWorkspace(new TestRPCProtocol(), {
|
||||
'id': 'foo',
|
||||
'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)],
|
||||
'name': 'foo'
|
||||
}),
|
||||
}, new NullLogService()),
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
@@ -269,7 +270,7 @@ suite('ExtHostConfiguration', function () {
|
||||
}, ['editor.wordWrap']),
|
||||
workspace,
|
||||
folders,
|
||||
configurationScopes: []
|
||||
configurationScopes: {}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -458,11 +459,11 @@ suite('ExtHostConfiguration', function () {
|
||||
const workspaceFolder = aWorkspaceFolder(URI.file('folder1'), 0);
|
||||
const testObject = new ExtHostConfiguration(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
new ExtHostWorkspace(new TestThreadService(), {
|
||||
new ExtHostWorkspace(new TestRPCProtocol(), {
|
||||
'id': 'foo',
|
||||
'folders': [workspaceFolder],
|
||||
'name': 'foo'
|
||||
}),
|
||||
}, new NullLogService()),
|
||||
createConfigurationData({
|
||||
'farboo': {
|
||||
'config': false,
|
||||
|
||||
@@ -6,23 +6,22 @@
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { DiagnosticCollection } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { Diagnostic, DiagnosticSeverity, Range } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { MainThreadDiagnosticsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
|
||||
suite('ExtHostDiagnostics', () => {
|
||||
|
||||
class DiagnosticsShape extends mock<MainThreadDiagnosticsShape>() {
|
||||
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any> {
|
||||
return TPromise.as(null);
|
||||
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
//
|
||||
}
|
||||
$clear(owner: string): TPromise<any> {
|
||||
return TPromise.as(null);
|
||||
$clear(owner: string): void {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +162,9 @@ suite('ExtHostDiagnostics', () => {
|
||||
|
||||
test('diagnostics collection, set tuple overrides, #11547', function () {
|
||||
|
||||
let lastEntries: [URI, IMarkerData[]][];
|
||||
let lastEntries: [UriComponents, IMarkerData[]][];
|
||||
let collection = new DiagnosticCollection('test', new class extends DiagnosticsShape {
|
||||
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any> {
|
||||
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
lastEntries = entries;
|
||||
return super.$changeMany(owner, entries);
|
||||
}
|
||||
@@ -237,9 +236,9 @@ suite('ExtHostDiagnostics', () => {
|
||||
|
||||
test('diagnostic capping', function () {
|
||||
|
||||
let lastEntries: [URI, IMarkerData[]][];
|
||||
let lastEntries: [UriComponents, IMarkerData[]][];
|
||||
let collection = new DiagnosticCollection('test', new class extends DiagnosticsShape {
|
||||
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any> {
|
||||
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
lastEntries = entries;
|
||||
return super.$changeMany(owner, entries);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Position } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { MainThreadDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorModel';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
|
||||
|
||||
|
||||
@@ -10,44 +10,58 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { TextDocumentSaveReason, TextEdit, Position, EndOfLine } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { MainThreadTextEditorsShape, WorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
|
||||
import { OneGetThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import * as vscode from 'vscode';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { isResourceTextEdit, ResourceTextEdit } from 'vs/editor/common/modes';
|
||||
|
||||
suite('ExtHostDocumentSaveParticipant', () => {
|
||||
|
||||
let resource = URI.parse('foo:bar');
|
||||
let mainThreadEditors = new class extends mock<MainThreadEditorsShape>() { };
|
||||
let mainThreadEditors = new class extends mock<MainThreadTextEditorsShape>() { };
|
||||
let documents: ExtHostDocuments;
|
||||
let nullLogService = new NullLogService();
|
||||
let nullExtensionDescription: IExtensionDescription = {
|
||||
id: 'nullExtensionDescription',
|
||||
name: 'Null Extension Description',
|
||||
publisher: 'vscode',
|
||||
enableProposedApi: false,
|
||||
engines: undefined,
|
||||
extensionFolderPath: undefined,
|
||||
isBuiltin: false,
|
||||
version: undefined
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(OneGetThreadService(null));
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null));
|
||||
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
modeId: 'foo',
|
||||
url: resource,
|
||||
uri: resource,
|
||||
versionId: 1,
|
||||
lines: ['foo'],
|
||||
EOL: '\n',
|
||||
}]
|
||||
});
|
||||
documents = new ExtHostDocuments(OneGetThreadService(null), documentsAndEditors);
|
||||
documents = new ExtHostDocuments(SingleProxyRPCProtocol(null), documentsAndEditors);
|
||||
});
|
||||
|
||||
test('no listeners, no problem', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => assert.ok(true));
|
||||
});
|
||||
|
||||
test('event delivery', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
@@ -61,10 +75,10 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, immutable', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
@@ -77,9 +91,9 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, bad listener', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('💀');
|
||||
});
|
||||
|
||||
@@ -92,13 +106,13 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, bad listener doesn\'t prevent more events', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let sub1 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('💀');
|
||||
});
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub2 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
@@ -111,14 +125,14 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, in subscriber order', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let counter = 0;
|
||||
let sub1 = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
assert.equal(counter++, 0);
|
||||
});
|
||||
|
||||
let sub2 = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
assert.equal(counter++, 1);
|
||||
});
|
||||
|
||||
@@ -128,42 +142,39 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, ignore bad listeners', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 5, errors: 1 });
|
||||
test('event delivery, ignore bad listeners', async () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 5, errors: 1 });
|
||||
|
||||
let callCount = 0;
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
callCount += 1;
|
||||
throw new Error('boom');
|
||||
});
|
||||
|
||||
return TPromise.join([
|
||||
participant.$participateInSave(resource, SaveReason.EXPLICIT),
|
||||
participant.$participateInSave(resource, SaveReason.EXPLICIT),
|
||||
participant.$participateInSave(resource, SaveReason.EXPLICIT),
|
||||
participant.$participateInSave(resource, SaveReason.EXPLICIT)
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
|
||||
]).then(values => {
|
||||
sub.dispose();
|
||||
assert.equal(callCount, 2);
|
||||
});
|
||||
sub.dispose();
|
||||
assert.equal(callCount, 2);
|
||||
});
|
||||
|
||||
test('event delivery, overall timeout', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 20, errors: 5 });
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 20, errors: 5 });
|
||||
|
||||
let callCount = 0;
|
||||
let sub1 = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
callCount += 1;
|
||||
event.waitUntil(TPromise.timeout(17));
|
||||
});
|
||||
|
||||
let sub2 = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
callCount += 1;
|
||||
event.waitUntil(TPromise.timeout(17));
|
||||
});
|
||||
|
||||
let sub3 = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub3 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
callCount += 1;
|
||||
});
|
||||
|
||||
@@ -178,9 +189,9 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
|
||||
event.waitUntil(TPromise.timeout(10));
|
||||
event.waitUntil(TPromise.timeout(10));
|
||||
@@ -194,9 +205,9 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil must be called sync', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
|
||||
event.waitUntil(new TPromise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
@@ -217,9 +228,9 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil will timeout', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors, { timeout: 5, errors: 3 });
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 5, errors: 3 });
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (event) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
event.waitUntil(TPromise.timeout(15));
|
||||
});
|
||||
|
||||
@@ -232,14 +243,14 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil failure handling', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, mainThreadEditors);
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
||||
|
||||
let sub1 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
e.waitUntil(TPromise.wrapError(new Error('dddd')));
|
||||
});
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub2 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
@@ -252,15 +263,15 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
|
||||
test('event delivery, pushEdits sync', () => {
|
||||
|
||||
let edits: IWorkspaceResourceEdit[];
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock<MainThreadEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) {
|
||||
edits = _edits;
|
||||
let dto: WorkspaceEditDto;
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
|
||||
dto = _edits;
|
||||
return TPromise.as(true);
|
||||
}
|
||||
});
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
e.waitUntil(TPromise.as([TextEdit.setEndOfLine(EndOfLine.CRLF)]));
|
||||
});
|
||||
@@ -268,25 +279,26 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
|
||||
assert.equal(edits.length, 1);
|
||||
assert.equal(edits[0].edits.length, 2);
|
||||
assert.equal(dto.edits.length, 1);
|
||||
assert.ok(isResourceTextEdit(dto.edits[0]));
|
||||
assert.equal((<ResourceTextEdit>dto.edits[0]).edits.length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, concurrent change', () => {
|
||||
|
||||
let edits: IWorkspaceResourceEdit[];
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock<MainThreadEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) {
|
||||
let edits: WorkspaceEditDto;
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
|
||||
edits = _edits;
|
||||
return TPromise.as(true);
|
||||
}
|
||||
});
|
||||
|
||||
let sub = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
|
||||
// concurrent change from somewhere
|
||||
documents.$acceptModelChanged(resource.toString(), {
|
||||
documents.$acceptModelChanged(resource, {
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
|
||||
rangeLength: undefined,
|
||||
@@ -310,19 +322,24 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
|
||||
test('event delivery, two listeners -> two document states', () => {
|
||||
|
||||
const participant = new ExtHostDocumentSaveParticipant(documents, new class extends mock<MainThreadEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: IWorkspaceResourceEdit[]) {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto) {
|
||||
|
||||
for (const { resource, edits } of _edits) {
|
||||
for (const { newText, range } of edits) {
|
||||
documents.$acceptModelChanged(resource.toString(), {
|
||||
for (const edit of dto.edits) {
|
||||
if (!isResourceTextEdit(edit)) {
|
||||
continue;
|
||||
}
|
||||
const { resource, edits } = edit;
|
||||
const uri = URI.revive(resource);
|
||||
for (const { text, range } of edits) {
|
||||
documents.$acceptModelChanged(uri, {
|
||||
changes: [{
|
||||
range,
|
||||
text,
|
||||
rangeLength: undefined,
|
||||
text: newText
|
||||
}],
|
||||
eol: undefined,
|
||||
versionId: documents.getDocumentData(resource).version + 1
|
||||
versionId: documents.getDocumentData(uri).version + 1
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
@@ -333,7 +350,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
|
||||
const document = documents.getDocumentData(resource).document;
|
||||
|
||||
let sub1 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
// the document state we started with
|
||||
assert.equal(document.version, 1);
|
||||
assert.equal(document.getText(), 'foo');
|
||||
@@ -341,7 +358,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
});
|
||||
|
||||
let sub2 = participant.onWillSaveTextDocumentEvent(function (e) {
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
// the document state AFTER the first listener kicked in
|
||||
assert.equal(document.version, 2);
|
||||
assert.equal(document.getText(), 'barfoo');
|
||||
@@ -359,4 +376,23 @@ suite('ExtHostDocumentSaveParticipant', () => {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('Log failing listener', function () {
|
||||
let didLogSomething = false;
|
||||
let participant = new ExtHostDocumentSaveParticipant(new class extends NullLogService {
|
||||
error(message: string | Error, ...args: any[]): void {
|
||||
didLogSomething = true;
|
||||
}
|
||||
}, documents, mainThreadEditors);
|
||||
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('boom');
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
assert.equal(didLogSomething, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
|
||||
suite('ExtHostDocumentsAndEditors', () => {
|
||||
|
||||
@@ -17,7 +15,9 @@ suite('ExtHostDocumentsAndEditors', () => {
|
||||
|
||||
setup(function () {
|
||||
editors = new ExtHostDocumentsAndEditors({
|
||||
get() { return undefined; }
|
||||
getProxy: () => { return undefined; },
|
||||
set: undefined,
|
||||
assertRegistered: undefined
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ suite('ExtHostDocumentsAndEditors', () => {
|
||||
EOL: '\n',
|
||||
isDirty: true,
|
||||
modeId: 'fooLang',
|
||||
url: URI.parse('foo:bar'),
|
||||
uri: URI.parse('foo:bar'),
|
||||
versionId: 1,
|
||||
lines: [
|
||||
'first',
|
||||
@@ -37,7 +37,7 @@ suite('ExtHostDocumentsAndEditors', () => {
|
||||
}]
|
||||
});
|
||||
|
||||
return new TPromise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
editors.onDidRemoveDocuments(e => {
|
||||
try {
|
||||
@@ -52,7 +52,7 @@ suite('ExtHostDocumentsAndEditors', () => {
|
||||
});
|
||||
|
||||
editors.$acceptDocumentsAndEditorsDelta({
|
||||
removedDocuments: ['foo:bar']
|
||||
removedDocuments: [URI.parse('foo:bar')]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -10,11 +10,10 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
|
||||
import { setUnexpectedErrorHandler, errorHandler } from 'vs/base/common/errors';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as EditorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Model as EditorModel } from 'vs/editor/common/model/model';
|
||||
import { TextModel as EditorModel } from 'vs/editor/common/model/textModel';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
import { TestThreadService } from './testThreadService';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
@@ -25,7 +24,7 @@ import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapSe
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen';
|
||||
import { DocumentSymbolProviderRegistry, DocumentHighlightKind, Hover } from 'vs/editor/common/modes';
|
||||
import { DocumentSymbolProviderRegistry, DocumentHighlightKind, Hover, ResourceTextEdit } from 'vs/editor/common/modes';
|
||||
import { getCodeLensData } from 'vs/editor/contrib/codelens/codelens';
|
||||
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDeclaration/goToDeclaration';
|
||||
import { getHover } from 'vs/editor/contrib/hover/getHover';
|
||||
@@ -44,10 +43,11 @@ import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import * as vscode from 'vscode';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { NoopLogService } from 'vs/platform/log/common/log';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { ITextModel, EndOfLineSequence } from 'vs/editor/common/model';
|
||||
|
||||
const defaultSelector = { scheme: 'far' };
|
||||
const model: EditorCommon.IModel = EditorModel.createFromString(
|
||||
const model: ITextModel = EditorModel.createFromString(
|
||||
[
|
||||
'This is the first line',
|
||||
'This is the second line',
|
||||
@@ -60,14 +60,14 @@ const model: EditorCommon.IModel = EditorModel.createFromString(
|
||||
let extHost: ExtHostLanguageFeatures;
|
||||
let mainThread: MainThreadLanguageFeatures;
|
||||
let disposables: vscode.Disposable[] = [];
|
||||
let threadService: TestThreadService;
|
||||
let rpcProtocol: TestRPCProtocol;
|
||||
let originalErrorHandler: (e: any) => any;
|
||||
|
||||
suite('ExtHostLanguageFeatures', function () {
|
||||
|
||||
suiteSetup(() => {
|
||||
|
||||
threadService = new TestThreadService();
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
// Use IInstantiationService to get typechecking when instantiating
|
||||
let inst: IInstantiationService;
|
||||
@@ -87,33 +87,33 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
originalErrorHandler = errorHandler.getUnexpectedErrorHandler();
|
||||
setUnexpectedErrorHandler(() => { });
|
||||
|
||||
const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(threadService);
|
||||
const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol);
|
||||
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
versionId: model.getVersionId(),
|
||||
modeId: model.getLanguageIdentifier().language,
|
||||
url: model.uri,
|
||||
uri: model.uri,
|
||||
lines: model.getValue().split(model.getEOL()),
|
||||
EOL: model.getEOL(),
|
||||
}]
|
||||
});
|
||||
const extHostDocuments = new ExtHostDocuments(threadService, extHostDocumentsAndEditors);
|
||||
threadService.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
|
||||
const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
|
||||
|
||||
const heapService = new ExtHostHeapService();
|
||||
|
||||
const commands = new ExtHostCommands(threadService, heapService, new NoopLogService());
|
||||
threadService.set(ExtHostContext.ExtHostCommands, commands);
|
||||
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));
|
||||
const commands = new ExtHostCommands(rpcProtocol, heapService, new NullLogService());
|
||||
rpcProtocol.set(ExtHostContext.ExtHostCommands, commands);
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol));
|
||||
|
||||
const diagnostics = new ExtHostDiagnostics(threadService);
|
||||
threadService.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
|
||||
const diagnostics = new ExtHostDiagnostics(rpcProtocol);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
|
||||
|
||||
extHost = new ExtHostLanguageFeatures(threadService, extHostDocuments, commands, heapService, diagnostics);
|
||||
threadService.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
|
||||
extHost = new ExtHostLanguageFeatures(rpcProtocol, extHostDocuments, commands, heapService, diagnostics);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost);
|
||||
|
||||
mainThread = <MainThreadLanguageFeatures>threadService.setTestInstance(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, threadService));
|
||||
mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, rpcProtocol));
|
||||
});
|
||||
|
||||
suiteTeardown(() => {
|
||||
@@ -126,7 +126,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
while (disposables.length) {
|
||||
disposables.pop().dispose();
|
||||
}
|
||||
return threadService.sync();
|
||||
return rpcProtocol.sync();
|
||||
});
|
||||
|
||||
// --- outline
|
||||
@@ -139,10 +139,10 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
});
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 1);
|
||||
d1.dispose();
|
||||
return threadService.sync();
|
||||
return rpcProtocol.sync();
|
||||
});
|
||||
|
||||
});
|
||||
@@ -159,7 +159,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDocumentSymbols(model).then(value => {
|
||||
assert.equal(value.entries.length, 1);
|
||||
@@ -174,7 +174,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDocumentSymbols(model).then(value => {
|
||||
assert.equal(value.entries.length, 1);
|
||||
@@ -201,7 +201,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getCodeLensData(model).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
});
|
||||
@@ -221,7 +221,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getCodeLensData(model).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -245,7 +245,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getCodeLensData(model).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -272,7 +272,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -296,7 +296,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
@@ -318,7 +318,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
@@ -343,7 +343,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -361,7 +361,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getImplementationsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [entry] = value;
|
||||
@@ -381,7 +381,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getTypeDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [entry] = value;
|
||||
@@ -401,7 +401,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
getHover(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [entry] = value;
|
||||
@@ -419,7 +419,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
getHover(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -444,7 +444,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getHover(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
let [first, second] = value as Hover[];
|
||||
@@ -468,7 +468,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
getHover(model, new EditorPosition(1, 1)).then(value => {
|
||||
|
||||
@@ -487,7 +487,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getOccurrencesAtPosition(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -511,7 +511,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getOccurrencesAtPosition(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -535,7 +535,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getOccurrencesAtPosition(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -560,7 +560,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getOccurrencesAtPosition(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -584,7 +584,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideReferences(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
@@ -604,7 +604,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideReferences(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -630,7 +630,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideReferences(model, new EditorPosition(1, 2)).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -641,7 +641,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
|
||||
// --- quick fix
|
||||
|
||||
test('Quick Fix, data conversion', function () {
|
||||
test('Quick Fix, command data conversion', function () {
|
||||
|
||||
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
|
||||
provideCodeActions(): vscode.Command[] {
|
||||
@@ -652,7 +652,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getCodeActions(model, model.getFullModelRange()).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
|
||||
@@ -665,6 +665,34 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
});
|
||||
});
|
||||
|
||||
test('Quick Fix, code action data conversion', function () {
|
||||
|
||||
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
|
||||
provideCodeActions(): vscode.CodeAction[] {
|
||||
return [
|
||||
{
|
||||
title: 'Testing1',
|
||||
command: { title: 'Testing1Command', command: 'test1' },
|
||||
kind: types.CodeActionKind.Empty.append('test.scope')
|
||||
}
|
||||
];
|
||||
}
|
||||
}));
|
||||
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getCodeActions(model, model.getFullModelRange()).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
|
||||
const [first] = value;
|
||||
assert.equal(first.title, 'Testing1');
|
||||
assert.equal(first.command.title, 'Testing1Command');
|
||||
assert.equal(first.command.id, 'test1');
|
||||
assert.equal(first.kind, 'test.scope');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('Cannot read property \'id\' of undefined, #29469', function () {
|
||||
|
||||
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
|
||||
@@ -677,7 +705,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getCodeActions(model, model.getFullModelRange()).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
});
|
||||
@@ -697,7 +725,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getCodeActions(model, model.getFullModelRange()).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
});
|
||||
@@ -720,7 +748,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return getWorkspaceSymbols('').then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
@@ -742,7 +770,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return rename(model, new EditorPosition(1, 1), 'newName').then(value => {
|
||||
throw Error();
|
||||
@@ -760,7 +788,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return rename(model, new EditorPosition(1, 1), 'newName').then(value => {
|
||||
assert.equal(value.rejectReason, 'evil');
|
||||
@@ -784,7 +812,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return rename(model, new EditorPosition(1, 1), 'newName').then(value => {
|
||||
assert.equal(value.edits.length, 1);
|
||||
@@ -809,10 +837,11 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return rename(model, new EditorPosition(1, 1), 'newName').then(value => {
|
||||
assert.equal(value.edits.length, 2); // least relevant renamer
|
||||
assert.equal(value.edits.length, 1); // least relevant renamer
|
||||
assert.equal((<ResourceTextEdit[]>value.edits)[0].edits.length, 2); // least relevant renamer
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -837,7 +866,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideSignatureHelp(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.ok(value);
|
||||
@@ -852,7 +881,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideSignatureHelp(model, new EditorPosition(1, 1)).then(value => {
|
||||
assert.equal(value, undefined);
|
||||
@@ -876,7 +905,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return provideSuggestionItems(model, new EditorPosition(1, 1), 'none').then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
assert.equal(value[0].suggestion.insertText, 'testing2');
|
||||
@@ -898,7 +927,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return provideSuggestionItems(model, new EditorPosition(1, 1), 'none').then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
assert.equal(value[0].suggestion.insertText, 'weak-selector');
|
||||
@@ -920,7 +949,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return provideSuggestionItems(model, new EditorPosition(1, 1), 'none').then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
assert.equal(value[0].suggestion.insertText, 'strong-1'); // sort by label
|
||||
@@ -944,7 +973,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}, []));
|
||||
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
return provideSuggestionItems(model, new EditorPosition(1, 1), 'none').then(value => {
|
||||
assert.equal(value[0].container.incomplete, undefined);
|
||||
@@ -960,7 +989,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, []));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
|
||||
provideSuggestionItems(model, new EditorPosition(1, 1), 'none').then(value => {
|
||||
assert.equal(value[0].container.incomplete, true);
|
||||
@@ -977,14 +1006,14 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }).then(value => {
|
||||
assert.equal(value.length, 2);
|
||||
let [first, second] = value;
|
||||
assert.equal(first.text, 'testing');
|
||||
assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });
|
||||
|
||||
assert.equal(second.eol, EditorCommon.EndOfLineSequence.LF);
|
||||
assert.equal(second.eol, EndOfLineSequence.LF);
|
||||
assert.equal(second.text, '');
|
||||
assert.equal(second.range, undefined);
|
||||
});
|
||||
@@ -998,7 +1027,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 });
|
||||
});
|
||||
});
|
||||
@@ -1016,7 +1045,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -1033,7 +1062,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -1054,7 +1083,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
return [new types.TextEdit(new types.Range(0, 0, 1, 1), 'doc')];
|
||||
}
|
||||
}));
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -1070,7 +1099,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 });
|
||||
});
|
||||
});
|
||||
@@ -1083,7 +1112,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}, [';']));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getOnTypeFormattingEdits(model, new EditorPosition(1, 1), ';', { insertSpaces: true, tabSize: 2 }).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -1102,7 +1131,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getLinks(model).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
@@ -1127,7 +1156,7 @@ suite('ExtHostLanguageFeatures', function () {
|
||||
}
|
||||
}));
|
||||
|
||||
return threadService.sync().then(() => {
|
||||
return rpcProtocol.sync().then(() => {
|
||||
return getLinks(model).then(value => {
|
||||
assert.equal(value.length, 1);
|
||||
let [first] = value;
|
||||
|
||||
@@ -6,91 +6,83 @@
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { MainThreadMessageService } from 'vs/workbench/api/electron-browser/mainThreadMessageService';
|
||||
import { TPromise as Promise } from 'vs/base/common/winjs.base';
|
||||
import { IMessageService, IChoiceService } from 'vs/platform/message/common/message';
|
||||
import { TPromise as Promise, TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService, INotification, NoOpNotification, INotificationHandle } from 'vs/platform/notification/common/notification';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
||||
const emptyChoiceService = new class implements IChoiceService {
|
||||
_serviceBrand: 'choiceService';
|
||||
choose(severity, message, options, modal): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
};
|
||||
|
||||
const emptyCommandService: ICommandService = {
|
||||
_serviceBrand: undefined,
|
||||
onWillExecuteCommand: () => ({ dispose: () => { } }),
|
||||
executeCommand: (commandId: string, ...args: any[]): TPromise<any> => {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
};
|
||||
|
||||
const emptyNotificationService = new class implements INotificationService {
|
||||
_serviceBrand: 'notificiationService';
|
||||
notify(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
info(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
warn(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
error(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
};
|
||||
|
||||
class EmptyNotificationService implements INotificationService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private withNotify: (notification: INotification) => void) {
|
||||
}
|
||||
|
||||
notify(notification: INotification): INotificationHandle {
|
||||
this.withNotify(notification);
|
||||
|
||||
return new NoOpNotification();
|
||||
}
|
||||
info(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
warn(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
error(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
suite('ExtHostMessageService', function () {
|
||||
|
||||
test('propagte handle on select', function () {
|
||||
|
||||
let service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
assert.equal(m.actions.length, 1);
|
||||
setImmediate(() => m.actions[0].run());
|
||||
return () => { };
|
||||
}
|
||||
} as IMessageService, {
|
||||
choose(severity, message, options, modal) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IChoiceService);
|
||||
let service = new MainThreadMessageService(null, new EmptyNotificationService(notification => {
|
||||
assert.equal(notification.actions.primary.length, 1);
|
||||
setImmediate(() => notification.actions.primary[0].run());
|
||||
}), emptyCommandService, emptyChoiceService, null);
|
||||
|
||||
return service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
|
||||
assert.equal(handle, 42);
|
||||
});
|
||||
});
|
||||
|
||||
test('isCloseAffordance', function () {
|
||||
|
||||
let actions: Action[];
|
||||
let service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
actions = m.actions;
|
||||
}
|
||||
} as IMessageService, {
|
||||
choose(severity, message, options, modal) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IChoiceService);
|
||||
|
||||
// default close action
|
||||
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: false, handle: 0 }]);
|
||||
assert.equal(actions.length, 2);
|
||||
let [first, second] = actions;
|
||||
assert.equal(first.label, 'a thing');
|
||||
assert.equal(second.label, 'Close');
|
||||
|
||||
// override close action
|
||||
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
|
||||
assert.equal(actions.length, 1);
|
||||
first = actions[0];
|
||||
assert.equal(first.label, 'a thing');
|
||||
});
|
||||
|
||||
test('hide on select', function () {
|
||||
|
||||
let actions: Action[];
|
||||
let c: number;
|
||||
let service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
c = 0;
|
||||
actions = m.actions;
|
||||
return () => {
|
||||
c += 1;
|
||||
};
|
||||
}
|
||||
} as IMessageService, {
|
||||
choose(severity, message, options, modal) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IChoiceService);
|
||||
|
||||
service.$showMessage(1, '', {}, [{ title: 'a thing', isCloseAffordance: true, handle: 0 }]);
|
||||
assert.equal(actions.length, 1);
|
||||
|
||||
actions[0].run();
|
||||
assert.equal(c, 1);
|
||||
});
|
||||
|
||||
suite('modal', () => {
|
||||
test('calls choice service', () => {
|
||||
const service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IMessageService, {
|
||||
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
|
||||
choose(severity, message, options, modal) {
|
||||
assert.equal(severity, 1);
|
||||
assert.equal(message, 'h');
|
||||
@@ -98,7 +90,7 @@ suite('ExtHostMessageService', function () {
|
||||
assert.equal(options[1], 'Cancel');
|
||||
return Promise.as(0);
|
||||
}
|
||||
} as IChoiceService);
|
||||
} as IChoiceService, null);
|
||||
|
||||
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
|
||||
assert.equal(handle, 42);
|
||||
@@ -106,15 +98,11 @@ suite('ExtHostMessageService', function () {
|
||||
});
|
||||
|
||||
test('returns undefined when cancelled', () => {
|
||||
const service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IMessageService, {
|
||||
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
|
||||
choose(severity, message, options, modal) {
|
||||
return Promise.as(1);
|
||||
}
|
||||
} as IChoiceService);
|
||||
} as IChoiceService, null);
|
||||
|
||||
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
|
||||
assert.equal(handle, undefined);
|
||||
@@ -122,16 +110,12 @@ suite('ExtHostMessageService', function () {
|
||||
});
|
||||
|
||||
test('hides Cancel button when not needed', () => {
|
||||
const service = new MainThreadMessageService(null, {
|
||||
show(sev: number, m: { actions: Action[] }) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
} as IMessageService, {
|
||||
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
|
||||
choose(severity, message, options, modal) {
|
||||
assert.equal(options.length, 1);
|
||||
return Promise.as(0);
|
||||
}
|
||||
} as IChoiceService);
|
||||
} as IChoiceService, null);
|
||||
|
||||
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
|
||||
assert.equal(handle, 42);
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as assert from 'assert';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { MainThreadEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { MainThreadTextEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostTextEditorOptions, ExtHostTextEditor } from 'vs/workbench/api/node/extHostTextEditor';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import URI from 'vs/base/common/uri';
|
||||
@@ -21,7 +21,7 @@ suite('ExtHostTextEditor', () => {
|
||||
let doc = new ExtHostDocumentData(undefined, URI.file(''), [
|
||||
'aaaa bbbb+cccc abc'
|
||||
], '\n', 'text', 1, false);
|
||||
editor = new ExtHostTextEditor(null, 'fake', doc, [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, 1);
|
||||
editor = new ExtHostTextEditor(null, 'fake', doc, [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1);
|
||||
});
|
||||
|
||||
test('disposed editor', () => {
|
||||
@@ -48,7 +48,7 @@ suite('ExtHostTextEditorOptions', () => {
|
||||
|
||||
setup(() => {
|
||||
calls = [];
|
||||
let mockProxy: MainThreadEditorsShape = {
|
||||
let mockProxy: MainThreadTextEditorsShape = {
|
||||
dispose: undefined,
|
||||
$trySetOptions: (id: string, options: ITextEditorConfigurationUpdate) => {
|
||||
assert.equal(id, '1');
|
||||
|
||||
@@ -7,49 +7,50 @@
|
||||
import * as assert from 'assert';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
||||
import { MainContext, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { MainContext, MainThreadTextEditorsShape, WorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { OneGetThreadService, TestThreadService } from 'vs/workbench/test/electron-browser/api/testThreadService';
|
||||
import { SingleProxyRPCProtocol, TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
|
||||
import { ResourceTextEdit } from 'vs/editor/common/modes';
|
||||
|
||||
suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
|
||||
|
||||
const resource = URI.parse('foo:bar');
|
||||
let editors: ExtHostEditors;
|
||||
let workspaceResourceEdits: IWorkspaceResourceEdit[];
|
||||
let workspaceResourceEdits: WorkspaceEditDto;
|
||||
|
||||
setup(() => {
|
||||
workspaceResourceEdits = null;
|
||||
|
||||
let threadService = new TestThreadService();
|
||||
threadService.setTestInstance(MainContext.MainThreadEditors, new class extends mock<MainThreadEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean> {
|
||||
let rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(MainContext.MainThreadTextEditors, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_workspaceResourceEdits: WorkspaceEditDto): TPromise<boolean> {
|
||||
workspaceResourceEdits = _workspaceResourceEdits;
|
||||
return TPromise.as(true);
|
||||
}
|
||||
});
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(OneGetThreadService(null));
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null));
|
||||
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
modeId: 'foo',
|
||||
url: resource,
|
||||
uri: resource,
|
||||
versionId: 1337,
|
||||
lines: ['foo'],
|
||||
EOL: '\n',
|
||||
}]
|
||||
});
|
||||
editors = new ExtHostEditors(threadService, documentsAndEditors);
|
||||
editors = new ExtHostEditors(rpcProtocol, documentsAndEditors);
|
||||
});
|
||||
|
||||
test('uses version id if document available', () => {
|
||||
let edit = new extHostTypes.WorkspaceEdit();
|
||||
edit.replace(resource, new extHostTypes.Range(0, 0, 0, 0), 'hello');
|
||||
return editors.applyWorkspaceEdit(edit).then((result) => {
|
||||
assert.equal(workspaceResourceEdits.length, 1);
|
||||
assert.equal(workspaceResourceEdits[0].modelVersionId, 1337);
|
||||
assert.equal(workspaceResourceEdits.edits.length, 1);
|
||||
assert.equal((<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId, 1337);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,8 +58,8 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
|
||||
let edit = new extHostTypes.WorkspaceEdit();
|
||||
edit.replace(URI.parse('foo:bar2'), new extHostTypes.Range(0, 0, 0, 0), 'hello');
|
||||
return editors.applyWorkspaceEdit(edit).then((result) => {
|
||||
assert.equal(workspaceResourceEdits.length, 1);
|
||||
assert.ok(typeof workspaceResourceEdits[0].modelVersionId === 'undefined');
|
||||
assert.equal(workspaceResourceEdits.edits.length, 1);
|
||||
assert.ok(typeof (<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId === 'undefined');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { MainThreadTreeViewsShape, MainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TreeDataProvider, TreeItem } from 'vscode';
|
||||
import { TestThreadService } from './testThreadService';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
|
||||
@@ -19,7 +20,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { TreeItemCollapsibleState, ITreeItem } from 'vs/workbench/common/views';
|
||||
import { NoopLogService } from 'vs/platform/log/common/log';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostTreeView', function () {
|
||||
|
||||
@@ -27,18 +28,23 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
onRefresh = new Emitter<{ [treeItemHandle: string]: ITreeItem }>();
|
||||
|
||||
$registerView(treeViewId: string): void {
|
||||
$registerTreeViewDataProvider(treeViewId: string): void {
|
||||
}
|
||||
|
||||
$refresh(viewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): void {
|
||||
this.onRefresh.fire(itemsToRefresh);
|
||||
}
|
||||
|
||||
$reveal(): TPromise<void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let testObject: ExtHostTreeViews;
|
||||
let target: RecordingShape;
|
||||
let onDidChangeTreeNode: Emitter<{ key: string }>;
|
||||
let onDidChangeTreeKey: Emitter<string>;
|
||||
let onDidChangeTreeNodeWithId: Emitter<{ key: string }>;
|
||||
let tree, labels, nodes;
|
||||
|
||||
setup(() => {
|
||||
@@ -56,7 +62,7 @@ suite('ExtHostTreeView', function () {
|
||||
labels = {};
|
||||
nodes = {};
|
||||
|
||||
let threadService = new TestThreadService();
|
||||
let rpcProtocol = new TestRPCProtocol();
|
||||
// Use IInstantiationService to get typechecking when instantiating
|
||||
let inst: IInstantiationService;
|
||||
{
|
||||
@@ -64,15 +70,15 @@ suite('ExtHostTreeView', function () {
|
||||
inst = instantiationService;
|
||||
}
|
||||
|
||||
threadService.setTestInstance(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, threadService));
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol));
|
||||
target = new RecordingShape();
|
||||
testObject = new ExtHostTreeViews(target, new ExtHostCommands(threadService, new ExtHostHeapService(), new NoopLogService()));
|
||||
testObject = new ExtHostTreeViews(target, new ExtHostCommands(rpcProtocol, new ExtHostHeapService(), new NullLogService()));
|
||||
onDidChangeTreeNode = new Emitter<{ key: string }>();
|
||||
onDidChangeTreeKey = new Emitter<string>();
|
||||
testObject.registerTreeDataProvider('testNodeTreeProvider', aNodeTreeDataProvider());
|
||||
testObject.registerTreeDataProvider('testStringTreeProvider', aStringTreeDataProvider());
|
||||
onDidChangeTreeNodeWithId = new Emitter<{ key: string }>();
|
||||
testObject.registerTreeDataProvider('testNodeTreeProvider', aNodeTreeDataProvider(), (fn) => fn);
|
||||
testObject.registerTreeDataProvider('testNodeWithIdTreeProvider', aNodeWithIdTreeDataProvider(), (fn) => fn);
|
||||
|
||||
testObject.$getElements('testNodeTreeProvider').then(elements => {
|
||||
testObject.$getChildren('testNodeTreeProvider').then(elements => {
|
||||
for (const element of elements) {
|
||||
testObject.$getChildren('testNodeTreeProvider', element.handle);
|
||||
}
|
||||
@@ -80,61 +86,82 @@ suite('ExtHostTreeView', function () {
|
||||
});
|
||||
|
||||
test('construct node tree', () => {
|
||||
return testObject.$getElements('testNodeTreeProvider')
|
||||
return testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['0/0:a', '0/1:b']);
|
||||
assert.deepEqual(actuals, ['0/0:a', '0/0:b']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a')
|
||||
.then(children => {
|
||||
const actuals = children.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['0/0:a/0:aa', '0/0:a/1:ab']);
|
||||
assert.deepEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a/1:ab').then(children => assert.equal(children.length, 0))
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.equal(children.length, 0))
|
||||
]);
|
||||
}),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/1:b')
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b')
|
||||
.then(children => {
|
||||
const actuals = children.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['0/1:b/0:ba', '0/1:b/1:bb']);
|
||||
assert.deepEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/1:b/0:ba').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/1:b/1:bb').then(children => assert.equal(children.length, 0))
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.equal(children.length, 0))
|
||||
]);
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('construct string tree', () => {
|
||||
return testObject.$getElements('testStringTreeProvider')
|
||||
test('construct id tree', () => {
|
||||
return testObject.$getChildren('testNodeWithIdTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['a', 'b']);
|
||||
assert.deepEqual(actuals, ['1/a', '1/b']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testStringTreeProvider', 'a')
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
|
||||
.then(children => {
|
||||
const actuals = children.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['aa', 'ab']);
|
||||
assert.deepEqual(actuals, ['1/aa', '1/ab']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testStringTreeProvider', 'aa').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testStringTreeProvider', 'ab').then(children => assert.equal(children.length, 0))
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.equal(children.length, 0))
|
||||
]);
|
||||
}),
|
||||
testObject.$getChildren('testStringTreeProvider', 'b')
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/b')
|
||||
.then(children => {
|
||||
const actuals = children.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['ba', 'bb']);
|
||||
assert.deepEqual(actuals, ['1/ba', '1/bb']);
|
||||
return TPromise.join([
|
||||
testObject.$getChildren('testStringTreeProvider', 'ba').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testStringTreeProvider', 'bb').then(children => assert.equal(children.length, 0))
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.equal(children.length, 0)),
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.equal(children.length, 0))
|
||||
]);
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('error is thrown if id is not unique', (done) => {
|
||||
tree['a'] = {
|
||||
'aa': {},
|
||||
};
|
||||
tree['b'] = {
|
||||
'aa': {},
|
||||
'ba': {}
|
||||
};
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['1/a', '1/b']);
|
||||
return testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
|
||||
.then(() => testObject.$getChildren('testNodeWithIdTreeProvider', '1/b'))
|
||||
.then(() => { assert.fail('Should fail with duplicate id'); done(); }, () => done());
|
||||
});
|
||||
});
|
||||
onDidChangeTreeNode.fire();
|
||||
});
|
||||
|
||||
test('refresh root', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.equal(undefined, actuals);
|
||||
@@ -146,10 +173,11 @@ suite('ExtHostTreeView', function () {
|
||||
test('refresh a parent node', () => {
|
||||
return new TPromise((c, e) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/1:b'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
|
||||
handle: '0/1:b',
|
||||
assert.deepEqual(['0/0:b'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: 'b',
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
c(null);
|
||||
});
|
||||
@@ -159,11 +187,12 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
test('refresh a leaf node', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/1:b/1:bb'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/1:b/1:bb']), {
|
||||
handle: '0/1:b/1:bb',
|
||||
parentHandle: '0/1:b',
|
||||
label: 'bb'
|
||||
assert.deepEqual(['0/0:b/0:bb'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), {
|
||||
handle: '0/0:b/0:bb',
|
||||
parentHandle: '0/0:b',
|
||||
label: 'bb',
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
done();
|
||||
});
|
||||
@@ -172,15 +201,17 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
test('refresh parent and child node trigger refresh only on parent - scenario 1', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/1:b', '0/0:a/0:aa'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
|
||||
handle: '0/1:b',
|
||||
assert.deepEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: 'b',
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
|
||||
handle: '0/0:a/0:aa',
|
||||
parentHandle: '0/0:a',
|
||||
label: 'aa',
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
done();
|
||||
});
|
||||
@@ -191,15 +222,17 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
test('refresh parent and child node trigger refresh only on parent - scenario 2', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/0:a/0:aa', '0/1:b'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/1:b']), {
|
||||
handle: '0/1:b',
|
||||
assert.deepEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals));
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: 'b',
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
|
||||
handle: '0/0:a/0:aa',
|
||||
parentHandle: '0/0:a',
|
||||
label: 'aa',
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
done();
|
||||
});
|
||||
@@ -215,6 +248,7 @@ suite('ExtHostTreeView', function () {
|
||||
assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), {
|
||||
handle: '0/0:aa',
|
||||
label: 'aa',
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
done();
|
||||
});
|
||||
@@ -234,7 +268,7 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
test('refresh calls are throttled on elements', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/0:a', '0/1:b'], Object.keys(actuals));
|
||||
assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -246,7 +280,7 @@ suite('ExtHostTreeView', function () {
|
||||
|
||||
test('refresh calls are throttled on unknown elements', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepEqual(['0/0:a', '0/1:b'], Object.keys(actuals));
|
||||
assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -280,16 +314,148 @@ suite('ExtHostTreeView', function () {
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
});
|
||||
|
||||
test('generate unique handles from labels by escaping them', () => {
|
||||
test('generate unique handles from labels by escaping them', (done) => {
|
||||
tree = {
|
||||
'a/0:b': {}
|
||||
};
|
||||
|
||||
onDidChangeTreeNode.fire();
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepEqual(elements.map(e => e.handle), ['0/0:a//0:b']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return testObject.$getElements('testNodeTreeProvider')
|
||||
test('tree with duplicate labels', (done) => {
|
||||
|
||||
const dupItems = {
|
||||
'adup1': 'c',
|
||||
'adup2': 'g',
|
||||
'bdup1': 'e',
|
||||
'hdup1': 'i',
|
||||
'hdup2': 'l',
|
||||
'jdup1': 'k'
|
||||
};
|
||||
|
||||
labels['c'] = 'a';
|
||||
labels['e'] = 'b';
|
||||
labels['g'] = 'a';
|
||||
labels['i'] = 'h';
|
||||
labels['l'] = 'h';
|
||||
labels['k'] = 'j';
|
||||
|
||||
tree[dupItems['adup1']] = {};
|
||||
tree['d'] = {};
|
||||
|
||||
const bdup1Tree = {};
|
||||
bdup1Tree['h'] = {};
|
||||
bdup1Tree[dupItems['hdup1']] = {};
|
||||
bdup1Tree['j'] = {};
|
||||
bdup1Tree[dupItems['jdup1']] = {};
|
||||
bdup1Tree[dupItems['hdup2']] = {};
|
||||
|
||||
tree[dupItems['bdup1']] = bdup1Tree;
|
||||
tree['f'] = {};
|
||||
tree[dupItems['adup2']] = {};
|
||||
|
||||
onDidChangeTreeNode.fire();
|
||||
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['0/0:a', '0/0:b', '0/1:a', '0/0:d', '0/1:b', '0/0:f', '0/2:a']);
|
||||
return testObject.$getChildren('testNodeTreeProvider', '0/1:b')
|
||||
.then(elements => {
|
||||
const actuals = elements.map(e => e.handle);
|
||||
assert.deepEqual(actuals, ['0/1:b/0:h', '0/1:b/1:h', '0/1:b/0:j', '0/1:b/1:j', '0/1:b/2:h']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('getChildren is not returned from cache if refreshed', (done) => {
|
||||
tree = {
|
||||
'c': {}
|
||||
};
|
||||
|
||||
onDidChangeTreeNode.fire();
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepEqual(elements.map(e => e.handle), ['0/0:c']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('getChildren is returned from cache if not refreshed', () => {
|
||||
tree = {
|
||||
'c': {}
|
||||
};
|
||||
|
||||
return testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepEqual(elements.map(e => e.handle), ['0/0:a//0:b']);
|
||||
assert.deepEqual(elements.map(e => e.handle), ['0/0:a', '0/0:b']);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will throw an error if getParent is not implemented', () => {
|
||||
const treeView = testObject.registerTreeDataProvider('treeDataProvider', aNodeTreeDataProvider(), (fn) => fn);
|
||||
return treeView.reveal({ key: 'a' })
|
||||
.then(() => assert.fail('Reveal should throw an error as getParent is not implemented'), () => null);
|
||||
});
|
||||
|
||||
test('reveal will return empty array for root element', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.registerTreeDataProvider('treeDataProvider', aCompleteNodeTreeDataProvider(), (fn) => fn);
|
||||
return treeView.reveal({ key: 'a' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepEqual({ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1]));
|
||||
assert.deepEqual([], revealTarget.args[0][2]);
|
||||
assert.equal(void 0, revealTarget.args[0][3]);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will return parents array for an element', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.registerTreeDataProvider('treeDataProvider', aCompleteNodeTreeDataProvider(), (fn) => fn);
|
||||
return treeView.reveal({ key: 'aa' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepEqual({ handle: '0/0:a/0:aa', label: 'aa', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
|
||||
assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
|
||||
assert.equal(void 0, revealTarget.args[0][3]);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will return parents array for deeper element with no selection', () => {
|
||||
tree = {
|
||||
'b': {
|
||||
'ba': {
|
||||
'bac': {}
|
||||
}
|
||||
}
|
||||
};
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.registerTreeDataProvider('treeDataProvider', aCompleteNodeTreeDataProvider(), (fn) => fn);
|
||||
return treeView.reveal({ key: 'bac' }, { select: false })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: 'bac', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1]));
|
||||
assert.deepEqual([
|
||||
{ handle: '0/0:b', label: 'b', collapsibleState: TreeItemCollapsibleState.Collapsed },
|
||||
{ handle: '0/0:b/0:ba', label: 'ba', collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' }
|
||||
], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepEqual({ select: false }, revealTarget.args[0][3]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -315,15 +481,33 @@ suite('ExtHostTreeView', function () {
|
||||
};
|
||||
}
|
||||
|
||||
function aStringTreeDataProvider(): TreeDataProvider<string> {
|
||||
function aCompleteNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: string): string[] => {
|
||||
return getChildren(element);
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: string): TreeItem => {
|
||||
return getTreeItem(element);
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
return getTreeItem(element.key);
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeKey.event
|
||||
getParent: ({ key }: { key: string }): { key: string } => {
|
||||
const parentKey = key.substring(0, key.length - 1);
|
||||
return parentKey ? new Key(parentKey) : void 0;
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNode.event
|
||||
};
|
||||
}
|
||||
|
||||
function aNodeWithIdTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
const treeItem = getTreeItem(element.key);
|
||||
treeItem.id = element.key;
|
||||
return treeItem;
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNodeWithId.event
|
||||
};
|
||||
}
|
||||
|
||||
@@ -344,12 +528,7 @@ suite('ExtHostTreeView', function () {
|
||||
}
|
||||
let treeElement = getTreeElement(key);
|
||||
if (treeElement) {
|
||||
const children = Object.keys(treeElement);
|
||||
const collapsibleStateIndex = children.indexOf('collapsibleState');
|
||||
if (collapsibleStateIndex !== -1) {
|
||||
children.splice(collapsibleStateIndex, 1);
|
||||
}
|
||||
return children;
|
||||
return Object.keys(treeElement);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
@@ -358,15 +537,19 @@ suite('ExtHostTreeView', function () {
|
||||
const treeElement = getTreeElement(key);
|
||||
return {
|
||||
label: labels[key] || key,
|
||||
collapsibleState: treeElement ? treeElement['collapsibleState'] : TreeItemCollapsibleState.Collapsed
|
||||
collapsibleState: treeElement && Object.keys(treeElement).length ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None
|
||||
};
|
||||
}
|
||||
|
||||
function getNode(key: string): { key: string } {
|
||||
if (!nodes[key]) {
|
||||
nodes[key] = { key };
|
||||
nodes[key] = new Key(key);
|
||||
}
|
||||
return nodes[key];
|
||||
}
|
||||
|
||||
});
|
||||
class Key {
|
||||
constructor(readonly key: string) { }
|
||||
}
|
||||
|
||||
});
|
||||
@@ -362,6 +362,53 @@ suite('ExtHostTypes', function () {
|
||||
|
||||
});
|
||||
|
||||
// test('WorkspaceEdit should fail when editing deleted resource', () => {
|
||||
// const resource = URI.parse('file:///a.ts');
|
||||
|
||||
// const edit = new types.WorkspaceEdit();
|
||||
// edit.deleteResource(resource);
|
||||
// try {
|
||||
// edit.insert(resource, new types.Position(0, 0), '');
|
||||
// assert.fail(false, 'Should disallow edit of deleted resource');
|
||||
// } catch {
|
||||
// // expected
|
||||
// }
|
||||
// });
|
||||
|
||||
// test('WorkspaceEdit - keep order of text and file changes', function () {
|
||||
|
||||
// const edit = new types.WorkspaceEdit();
|
||||
// edit.replace(URI.parse('foo:a'), new types.Range(1, 1, 1, 1), 'foo');
|
||||
// edit.renameResource(URI.parse('foo:a'), URI.parse('foo:b'));
|
||||
// edit.replace(URI.parse('foo:a'), new types.Range(2, 1, 2, 1), 'bar');
|
||||
// edit.replace(URI.parse('foo:b'), new types.Range(3, 1, 3, 1), 'bazz');
|
||||
|
||||
// const all = edit.allEntries();
|
||||
// assert.equal(all.length, 3);
|
||||
|
||||
// function isFileChange(thing: [URI, types.TextEdit[]] | [URI, URI]): thing is [URI, URI] {
|
||||
// const [f, s] = thing;
|
||||
// return URI.isUri(f) && URI.isUri(s);
|
||||
// }
|
||||
|
||||
// function isTextChange(thing: [URI, types.TextEdit[]] | [URI, URI]): thing is [URI, types.TextEdit[]] {
|
||||
// const [f, s] = thing;
|
||||
// return URI.isUri(f) && Array.isArray(s);
|
||||
// }
|
||||
|
||||
// const [first, second, third] = all;
|
||||
// assert.equal(first[0].toString(), 'foo:a');
|
||||
// assert.ok(!isFileChange(first));
|
||||
// assert.ok(isTextChange(first) && first[1].length === 2);
|
||||
|
||||
// assert.equal(second[0].toString(), 'foo:a');
|
||||
// assert.ok(isFileChange(second));
|
||||
|
||||
// assert.equal(third[0].toString(), 'foo:b');
|
||||
// assert.ok(!isFileChange(third));
|
||||
// assert.ok(isTextChange(third) && third[1].length === 1);
|
||||
// });
|
||||
|
||||
test('DocumentLink', function () {
|
||||
assert.throws(() => new types.DocumentLink(null, null));
|
||||
assert.throws(() => new types.DocumentLink(new types.Range(1, 1, 1, 1), null));
|
||||
|
||||
@@ -9,12 +9,25 @@ import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { basename } from 'path';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { TestThreadService } from './testThreadService';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { normalize } from 'vs/base/common/paths';
|
||||
import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostWorkspace', function () {
|
||||
|
||||
const extensionDescriptor: IExtensionDescription = {
|
||||
id: 'nullExtensionDescription',
|
||||
name: 'ext',
|
||||
publisher: 'vscode',
|
||||
enableProposedApi: false,
|
||||
engines: undefined,
|
||||
extensionFolderPath: undefined,
|
||||
isBuiltin: false,
|
||||
version: undefined
|
||||
};
|
||||
|
||||
function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) {
|
||||
const actual = workspace.getRelativePath(input, includeWorkspace);
|
||||
if (actual === expected) {
|
||||
@@ -25,6 +38,488 @@ suite('ExtHostWorkspace', function () {
|
||||
}
|
||||
|
||||
test('asRelativePath', function () {
|
||||
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot');
|
||||
assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart',
|
||||
'/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart');
|
||||
|
||||
assertAsRelativePath(ws, '', '');
|
||||
assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
|
||||
assertAsRelativePath(ws, 'in/out', 'in/out');
|
||||
});
|
||||
|
||||
test('asRelativePath, same paths, #11402', function () {
|
||||
const root = '/home/aeschli/workspaces/samples/docker';
|
||||
const input = '/home/aeschli/workspaces/samples/docker';
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(ws, (input), input);
|
||||
|
||||
const input2 = '/home/aeschli/workspaces/samples/docker/a.file';
|
||||
assertAsRelativePath(ws, (input2), 'a.file');
|
||||
});
|
||||
|
||||
test('asRelativePath, no workspace', function () {
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService());
|
||||
assertAsRelativePath(ws, (''), '');
|
||||
assertAsRelativePath(ws, ('/foo/bar'), '/foo/bar');
|
||||
});
|
||||
|
||||
test('asRelativePath, multiple folders', function () {
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt');
|
||||
assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
|
||||
assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
});
|
||||
|
||||
test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () {
|
||||
const mrws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'file.txt', false);
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'files/out.txt', false);
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
|
||||
|
||||
const srws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService());
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt');
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false);
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true);
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
|
||||
});
|
||||
|
||||
test('getPath, legacy', function () {
|
||||
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
assert.equal(ws.getPath(), undefined);
|
||||
|
||||
ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService());
|
||||
assert.equal(ws.getPath(), undefined);
|
||||
|
||||
ws = new ExtHostWorkspace(new TestRPCProtocol(), undefined, new NullLogService());
|
||||
assert.equal(ws.getPath(), undefined);
|
||||
|
||||
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService());
|
||||
assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder');
|
||||
|
||||
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService());
|
||||
assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder');
|
||||
});
|
||||
|
||||
test('WorkspaceFolder has name and index', function () {
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
|
||||
const [one, two] = ws.getWorkspaceFolders();
|
||||
|
||||
assert.equal(one.name, 'One');
|
||||
assert.equal(one.index, 0);
|
||||
assert.equal(two.name, 'Two');
|
||||
assert.equal(two.index, 1);
|
||||
});
|
||||
|
||||
test('getContainingWorkspaceFolder', function () {
|
||||
const ws = new ExtHostWorkspace(new TestRPCProtocol(), {
|
||||
id: 'foo',
|
||||
name: 'Test',
|
||||
folders: [
|
||||
aWorkspaceFolderData(URI.file('/Coding/One'), 0),
|
||||
aWorkspaceFolderData(URI.file('/Coding/Two'), 1),
|
||||
aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)
|
||||
]
|
||||
}, new NullLogService());
|
||||
|
||||
let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));
|
||||
assert.equal(folder, undefined);
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'));
|
||||
assert.equal(folder.name, 'One');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'));
|
||||
assert.equal(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'));
|
||||
assert.equal(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'));
|
||||
assert.equal(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'));
|
||||
assert.equal(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true);
|
||||
assert.equal(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true);
|
||||
assert.equal(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'));
|
||||
assert.equal(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'));
|
||||
assert.equal(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true);
|
||||
assert.equal(folder, undefined);
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false);
|
||||
assert.equal(folder.name, 'Two');
|
||||
});
|
||||
|
||||
test('Multiroot change event should have a delta, #29641', function (done) {
|
||||
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
let finished = false;
|
||||
const finish = (error?) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
done(error);
|
||||
}
|
||||
};
|
||||
|
||||
let sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.added, []);
|
||||
assert.deepEqual(e.removed, []);
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.removed, []);
|
||||
assert.equal(e.added.length, 1);
|
||||
assert.equal(e.added[0].uri.toString(), 'foo:bar');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.removed, []);
|
||||
assert.equal(e.added.length, 1);
|
||||
assert.equal(e.added[0].uri.toString(), 'foo:bar2');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.equal(e.removed.length, 2);
|
||||
assert.equal(e.removed[0].uri.toString(), 'foo:bar');
|
||||
assert.equal(e.removed[1].uri.toString(), 'foo:bar2');
|
||||
|
||||
assert.equal(e.added.length, 1);
|
||||
assert.equal(e.added[0].uri.toString(), 'foo:bar3');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
|
||||
sub.dispose();
|
||||
finish();
|
||||
});
|
||||
|
||||
test('Multiroot change keeps existing workspaces live', function () {
|
||||
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
|
||||
|
||||
let firstFolder = ws.getWorkspaceFolders()[0];
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] });
|
||||
|
||||
assert.equal(ws.getWorkspaceFolders()[1], firstFolder);
|
||||
assert.equal(firstFolder.index, 1);
|
||||
assert.equal(firstFolder.name, 'renamed');
|
||||
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] });
|
||||
assert.equal(ws.getWorkspaceFolders()[2], firstFolder);
|
||||
assert.equal(firstFolder.index, 2);
|
||||
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] });
|
||||
|
||||
assert.notEqual(firstFolder, ws.workspace.folders[0]);
|
||||
});
|
||||
|
||||
test('updateWorkspaceFolders - invalid arguments', function () {
|
||||
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null, null));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1));
|
||||
|
||||
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
|
||||
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2));
|
||||
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
|
||||
});
|
||||
|
||||
test('updateWorkspaceFolders - valid arguments', function (done) {
|
||||
let finished = false;
|
||||
const finish = (error?) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
done(error);
|
||||
}
|
||||
};
|
||||
|
||||
const protocol = {
|
||||
getProxy: () => { return undefined; },
|
||||
set: undefined,
|
||||
assertRegistered: undefined
|
||||
};
|
||||
|
||||
const ws = new ExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
//
|
||||
// Add one folder
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
|
||||
assert.equal(1, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
|
||||
const firstAddedFolder = ws.getWorkspaceFolders()[0];
|
||||
|
||||
let gotEvent = false;
|
||||
let sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.removed, []);
|
||||
assert.equal(e.added.length, 1);
|
||||
assert.equal(e.added[0].uri.toString(), 'foo:bar');
|
||||
assert.equal(e.added[0], firstAddedFolder); // verify object is still live
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Add two more folders
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2'))));
|
||||
assert.equal(3, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
assert.equal(ws.workspace.folders[2].uri.toString(), URI.parse('foo:bar2').toString());
|
||||
|
||||
const secondAddedFolder = ws.getWorkspaceFolders()[1];
|
||||
const thirdAddedFolder = ws.getWorkspaceFolders()[2];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.removed, []);
|
||||
assert.equal(e.added.length, 2);
|
||||
assert.equal(e.added[0].uri.toString(), 'foo:bar1');
|
||||
assert.equal(e.added[1].uri.toString(), 'foo:bar2');
|
||||
assert.equal(e.added[0], secondAddedFolder);
|
||||
assert.equal(e.added[1], thirdAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1), aWorkspaceFolderData(URI.parse('foo:bar2'), 2)] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[2], thirdAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Remove one folder
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1));
|
||||
assert.equal(2, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.added, []);
|
||||
assert.equal(e.removed.length, 1);
|
||||
assert.equal(e.removed[0], thirdAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Rename folder
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2')));
|
||||
assert.equal(2, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
assert.equal(ws.workspace.folders[0].name, 'renamed 1');
|
||||
assert.equal(ws.workspace.folders[1].name, 'renamed 2');
|
||||
assert.equal(ws.getWorkspaceFolders()[0].name, 'renamed 1');
|
||||
assert.equal(ws.getWorkspaceFolders()[1].name, 'renamed 2');
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepEqual(e.added, []);
|
||||
assert.equal(e.removed.length, []);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0, 'renamed 1'), aWorkspaceFolderData(URI.parse('foo:bar1'), 1, 'renamed 2')] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], firstAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], secondAddedFolder); // verify object is still live
|
||||
assert.equal(ws.workspace.folders[0].name, 'renamed 1');
|
||||
assert.equal(ws.workspace.folders[1].name, 'renamed 2');
|
||||
assert.equal(ws.getWorkspaceFolders()[0].name, 'renamed 1');
|
||||
assert.equal(ws.getWorkspaceFolders()[1].name, 'renamed 2');
|
||||
|
||||
//
|
||||
// Add and remove folders
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4'))));
|
||||
assert.equal(2, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
|
||||
const fourthAddedFolder = ws.getWorkspaceFolders()[0];
|
||||
const fifthAddedFolder = ws.getWorkspaceFolders()[1];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.equal(e.added.length, 2);
|
||||
assert.equal(e.added[0], fourthAddedFolder);
|
||||
assert.equal(e.added[1], fifthAddedFolder);
|
||||
assert.equal(e.removed.length, 2);
|
||||
assert.equal(e.removed[0], firstAddedFolder);
|
||||
assert.equal(e.removed[1], secondAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], fourthAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], fifthAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Swap folders
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3'))));
|
||||
assert.equal(2, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
|
||||
assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.equal(e.added.length, 0);
|
||||
assert.equal(e.removed.length, 0);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live
|
||||
assert.equal(fifthAddedFolder.index, 0);
|
||||
assert.equal(fourthAddedFolder.index, 1);
|
||||
|
||||
//
|
||||
// Add one folder after the other without waiting for confirmation (not supported currently)
|
||||
//
|
||||
|
||||
assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5'))));
|
||||
|
||||
assert.equal(3, ws.workspace.folders.length);
|
||||
assert.equal(ws.workspace.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
assert.equal(ws.workspace.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
assert.equal(ws.workspace.folders[2].uri.toString(), URI.parse('foo:bar5').toString());
|
||||
|
||||
const sixthAddedFolder = ws.getWorkspaceFolders()[2];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.equal(e.added.length, 1);
|
||||
assert.equal(e.added[0], sixthAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({
|
||||
id: 'foo', name: 'Test', folders: [
|
||||
aWorkspaceFolderData(URI.parse('foo:bar4'), 0),
|
||||
aWorkspaceFolderData(URI.parse('foo:bar3'), 1),
|
||||
aWorkspaceFolderData(URI.parse('foo:bar5'), 2)
|
||||
]
|
||||
}); // simulate acknowledgement from main side
|
||||
assert.equal(gotEvent, true);
|
||||
sub.dispose();
|
||||
|
||||
assert.equal(ws.getWorkspaceFolders()[0], fifthAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[1], fourthAddedFolder); // verify object is still live
|
||||
assert.equal(ws.getWorkspaceFolders()[2], sixthAddedFolder); // verify object is still live
|
||||
|
||||
finish();
|
||||
});
|
||||
|
||||
test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {
|
||||
let ws = new ExtHostWorkspace(new TestRPCProtocol(), {
|
||||
id: 'foo', name: 'Test', folders: [
|
||||
aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)
|
||||
]
|
||||
}, new NullLogService());
|
||||
|
||||
assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));
|
||||
assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));
|
||||
});
|
||||
|
||||
function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {
|
||||
@@ -34,4 +529,8 @@ suite('ExtHostWorkspace', function () {
|
||||
name: name || basename(uri.path)
|
||||
};
|
||||
}
|
||||
|
||||
function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI, name?: string } {
|
||||
return { uri, name };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
import * as assert from 'assert';
|
||||
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { OneGetThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
|
||||
suite('MainThreadCommands', function () {
|
||||
|
||||
test('dispose on unregister', function () {
|
||||
|
||||
const commands = new MainThreadCommands(OneGetThreadService(null), undefined);
|
||||
const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined);
|
||||
assert.equal(CommandsRegistry.getCommand('foo'), undefined);
|
||||
|
||||
// register
|
||||
@@ -28,7 +28,7 @@ suite('MainThreadCommands', function () {
|
||||
|
||||
test('unregister all on dispose', function () {
|
||||
|
||||
const commands = new MainThreadCommands(OneGetThreadService(null), undefined);
|
||||
const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined);
|
||||
assert.equal(CommandsRegistry.getCommand('foo'), undefined);
|
||||
|
||||
commands.$registerCommand('foo');
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platf
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { MainThreadConfiguration } from 'vs/workbench/api/electron-browser/mainThreadConfiguration';
|
||||
import { OneGetThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService';
|
||||
|
||||
@@ -56,7 +56,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null);
|
||||
|
||||
@@ -65,7 +65,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc'));
|
||||
|
||||
@@ -74,7 +74,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', null);
|
||||
|
||||
@@ -83,7 +83,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null);
|
||||
|
||||
@@ -92,7 +92,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc'));
|
||||
|
||||
@@ -101,7 +101,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', URI.file('abc'));
|
||||
|
||||
@@ -110,7 +110,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', null);
|
||||
|
||||
@@ -119,7 +119,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update resource configuration without configuration target defaults to folder', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', URI.file('abc'));
|
||||
|
||||
@@ -128,7 +128,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update configuration with user configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.USER, 'extHostConfiguration.window', 'value', URI.file('abc'));
|
||||
|
||||
@@ -137,7 +137,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update configuration with workspace configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE, 'extHostConfiguration.window', 'value', URI.file('abc'));
|
||||
|
||||
@@ -146,7 +146,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('update configuration with folder configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE_FOLDER, 'extHostConfiguration.window', 'value', URI.file('abc'));
|
||||
|
||||
@@ -155,7 +155,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null);
|
||||
|
||||
@@ -164,7 +164,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc'));
|
||||
|
||||
@@ -173,7 +173,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', null);
|
||||
|
||||
@@ -182,7 +182,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null);
|
||||
|
||||
@@ -191,7 +191,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc'));
|
||||
|
||||
@@ -200,7 +200,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', URI.file('abc'));
|
||||
|
||||
@@ -209,7 +209,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', null);
|
||||
|
||||
@@ -218,7 +218,7 @@ suite('MainThreadConfiguration', function () {
|
||||
|
||||
test('remove configuration without configuration target defaults to folder', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, OneGetThreadService(null));
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(null));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', URI.file('abc'));
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { BoundModelReferenceCollection } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
suite('BoundModelReferenceCollection', () => {
|
||||
@@ -23,7 +23,7 @@ suite('BoundModelReferenceCollection', () => {
|
||||
let didDispose = false;
|
||||
|
||||
col.add({
|
||||
object: <any>{ textEditorModel: Model.createFromString('farboo') },
|
||||
object: <any>{ textEditorModel: TextModel.createFromString('farboo') },
|
||||
dispose() {
|
||||
didDispose = true;
|
||||
}
|
||||
@@ -39,20 +39,20 @@ suite('BoundModelReferenceCollection', () => {
|
||||
let disposed: number[] = [];
|
||||
|
||||
col.add({
|
||||
object: <any>{ textEditorModel: Model.createFromString('farboo') },
|
||||
object: <any>{ textEditorModel: TextModel.createFromString('farboo') },
|
||||
dispose() {
|
||||
disposed.push(0);
|
||||
}
|
||||
});
|
||||
col.add({
|
||||
object: <any>{ textEditorModel: Model.createFromString('boofar') },
|
||||
object: <any>{ textEditorModel: TextModel.createFromString('boofar') },
|
||||
dispose() {
|
||||
disposed.push(1);
|
||||
}
|
||||
});
|
||||
|
||||
col.add({
|
||||
object: <any>{ textEditorModel: Model.createFromString(new Array(71).join('x')) },
|
||||
object: <any>{ textEditorModel: TextModel.createFromString(new Array(71).join('x')) },
|
||||
dispose() {
|
||||
disposed.push(2);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
|
||||
import { OneGetThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { TestCodeEditorService } from 'vs/editor/test/browser/testCodeEditorService';
|
||||
@@ -53,7 +53,7 @@ suite('MainThreadDocumentsAndEditors', () => {
|
||||
|
||||
/* tslint:disable */
|
||||
new MainThreadDocumentsAndEditors(
|
||||
OneGetThreadService(new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
SingleProxyRPCProtocol(new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
$acceptDocumentsAndEditorsDelta(delta) { deltas.push(delta); }
|
||||
}),
|
||||
modelService,
|
||||
|
||||
@@ -7,34 +7,62 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
|
||||
import { OneGetThreadService, TestThreadService } from './testThreadService';
|
||||
import { SingleProxyRPCProtocol, TestRPCProtocol } from './testRPCProtocol';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { TestCodeEditorService } from 'vs/editor/test/browser/testCodeEditorService';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostDocumentsAndEditorsShape, IWorkspaceResourceEdit, ExtHostContext, ExtHostDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditorsShape, ExtHostContext, ExtHostDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import Event from 'vs/base/common/event';
|
||||
import { MainThreadEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
|
||||
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { TestFileService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IFileStat } from 'vs/platform/files/common/files';
|
||||
import { ResourceTextEdit } from 'vs/editor/common/modes';
|
||||
|
||||
suite('MainThreadEditors', () => {
|
||||
|
||||
const resource = URI.parse('foo:bar');
|
||||
|
||||
let modelService: IModelService;
|
||||
let editors: MainThreadEditors;
|
||||
let editors: MainThreadTextEditors;
|
||||
|
||||
const movedResources = new Map<URI, URI>();
|
||||
const createdResources = new Set<URI>();
|
||||
const deletedResources = new Set<URI>();
|
||||
|
||||
setup(() => {
|
||||
const configService = new TestConfigurationService();
|
||||
modelService = new ModelServiceImpl(null, configService);
|
||||
const codeEditorService = new TestCodeEditorService();
|
||||
|
||||
movedResources.clear();
|
||||
createdResources.clear();
|
||||
deletedResources.clear();
|
||||
|
||||
const fileService = new class extends TestFileService {
|
||||
async moveFile(from, target): TPromise<IFileStat> {
|
||||
movedResources.set(from, target);
|
||||
return createMockFileStat(target);
|
||||
}
|
||||
async createFile(uri): TPromise<IFileStat> {
|
||||
createdResources.add(uri);
|
||||
return createMockFileStat(uri);
|
||||
}
|
||||
async del(uri): TPromise<any> {
|
||||
deletedResources.add(uri);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const textFileService = new class extends mock<ITextFileService>() {
|
||||
isDirty() { return false; }
|
||||
models = <any>{
|
||||
@@ -52,37 +80,37 @@ suite('MainThreadEditors', () => {
|
||||
onEditorGroupMoved = Event.None;
|
||||
};
|
||||
|
||||
const testThreadService = new TestThreadService(true);
|
||||
testThreadService.setTestInstance(ExtHostContext.ExtHostDocuments, new class extends mock<ExtHostDocumentsShape>() {
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocuments, new class extends mock<ExtHostDocumentsShape>() {
|
||||
$acceptModelChanged(): void {
|
||||
}
|
||||
});
|
||||
testThreadService.setTestInstance(ExtHostContext.ExtHostDocumentsAndEditors, new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
$acceptDocumentsAndEditorsDelta(): void {
|
||||
}
|
||||
});
|
||||
|
||||
const documentAndEditor = new MainThreadDocumentsAndEditors(
|
||||
testThreadService,
|
||||
rpcProtocol,
|
||||
modelService,
|
||||
textFileService,
|
||||
workbenchEditorService,
|
||||
codeEditorService,
|
||||
null,
|
||||
null,
|
||||
fileService,
|
||||
null,
|
||||
null,
|
||||
editorGroupService,
|
||||
);
|
||||
|
||||
editors = new MainThreadEditors(
|
||||
editors = new MainThreadTextEditors(
|
||||
documentAndEditor,
|
||||
OneGetThreadService(null),
|
||||
SingleProxyRPCProtocol(null),
|
||||
codeEditorService,
|
||||
workbenchEditorService,
|
||||
editorGroupService,
|
||||
null,
|
||||
null,
|
||||
fileService,
|
||||
modelService
|
||||
);
|
||||
});
|
||||
@@ -91,11 +119,11 @@ suite('MainThreadEditors', () => {
|
||||
|
||||
let model = modelService.createModel('something', null, resource);
|
||||
|
||||
let workspaceResourceEdit: IWorkspaceResourceEdit = {
|
||||
let workspaceResourceEdit: ResourceTextEdit = {
|
||||
resource: resource,
|
||||
modelVersionId: model.getVersionId(),
|
||||
edits: [{
|
||||
newText: 'asdfg',
|
||||
text: 'asdfg',
|
||||
range: new Range(1, 1, 1, 1)
|
||||
}]
|
||||
};
|
||||
@@ -103,8 +131,35 @@ suite('MainThreadEditors', () => {
|
||||
// Act as if the user edited the model
|
||||
model.applyEdits([EditOperation.insert(new Position(0, 0), 'something')]);
|
||||
|
||||
return editors.$tryApplyWorkspaceEdit([workspaceResourceEdit]).then((result) => {
|
||||
return editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit] }).then((result) => {
|
||||
assert.equal(result, false);
|
||||
});
|
||||
});
|
||||
|
||||
test(`applyWorkspaceEdit with only resource edit`, () => {
|
||||
return editors.$tryApplyWorkspaceEdit({
|
||||
edits: [
|
||||
{ oldUri: resource, newUri: resource },
|
||||
{ oldUri: undefined, newUri: resource },
|
||||
{ oldUri: resource, newUri: undefined }
|
||||
]
|
||||
}).then((result) => {
|
||||
assert.equal(result, true);
|
||||
assert.equal(movedResources.get(resource), resource);
|
||||
assert.equal(createdResources.has(resource), true);
|
||||
assert.equal(deletedResources.has(resource), true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function createMockFileStat(target: URI): IFileStat {
|
||||
return {
|
||||
etag: '',
|
||||
isDirectory: false,
|
||||
name: target.path,
|
||||
mtime: 0,
|
||||
resource: target
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,12 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
|
||||
import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { toResource } from 'vs/base/test/common/utils';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
|
||||
import { snapshotToString } from 'vs/platform/files/common/files';
|
||||
|
||||
class ServiceAccessor {
|
||||
constructor( @ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService) {
|
||||
@@ -49,25 +52,25 @@ suite('MainThreadSaveParticipant', function () {
|
||||
let lineContent = '';
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), lineContent);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
|
||||
|
||||
// No new line if last line already empty
|
||||
lineContent = `Hello New Line${model.textEditorModel.getEOL()}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), lineContent);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
|
||||
|
||||
// New empty line added (single line)
|
||||
lineContent = 'Hello New Line';
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), `${lineContent}${model.textEditorModel.getEOL()}`);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
|
||||
|
||||
// New empty line added (multi line)
|
||||
lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), `${lineContent}${model.textEditorModel.getEOL()}`);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
|
||||
|
||||
done();
|
||||
});
|
||||
@@ -89,27 +92,56 @@ suite('MainThreadSaveParticipant', function () {
|
||||
let lineContent = `${textContent}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), lineContent);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
|
||||
|
||||
// No new line removal if last line is single new line
|
||||
lineContent = `${textContent}${eol}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), lineContent);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
|
||||
|
||||
// Remove new line (single line with two new lines)
|
||||
lineContent = `${textContent}${eol}${eol}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), `${textContent}${eol}`);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
|
||||
|
||||
// Remove new lines (multiple lines with multiple new lines)
|
||||
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
assert.equal(model.getValue(), `${textContent}${eol}${textContent}${eol}`);
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${textContent}${eol}`);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('trim final new lines bug#39750', function (done) {
|
||||
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8');
|
||||
|
||||
model.load().then(() => {
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
|
||||
|
||||
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
|
||||
|
||||
const textContent = 'Trim New Line';
|
||||
|
||||
// single line
|
||||
let lineContent = `${textContent}`;
|
||||
model.textEditorModel.setValue(lineContent);
|
||||
// apply edits and push to undo stack.
|
||||
let textEdits = [{ identifier: null, range: new Range(1, 14, 1, 14), text: '.', forceMoveMarkers: false }];
|
||||
model.textEditorModel.pushEditOperations([new Selection(1, 14, 1, 14)], textEdits, () => { return [new Selection(1, 15, 1, 15)]; });
|
||||
// undo
|
||||
model.textEditorModel.undo();
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}`);
|
||||
// trim final new lines should not mess the undo stack
|
||||
participant.participate(model, { reason: SaveReason.EXPLICIT });
|
||||
model.textEditorModel.redo();
|
||||
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}.`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
135
src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts
Normal file
135
src/vs/workbench/test/electron-browser/api/testRPCProtocol.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
export function SingleProxyRPCProtocol(thing: any): IRPCProtocol {
|
||||
return {
|
||||
getProxy<T>(): T {
|
||||
return thing;
|
||||
},
|
||||
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
return value;
|
||||
},
|
||||
assertRegistered: undefined
|
||||
};
|
||||
}
|
||||
|
||||
declare var Proxy; // TODO@TypeScript
|
||||
|
||||
export class TestRPCProtocol implements IRPCProtocol {
|
||||
|
||||
private _callCountValue: number = 0;
|
||||
private _idle: Promise<any>;
|
||||
private _completeIdle: Function;
|
||||
|
||||
private readonly _locals: { [id: string]: any; };
|
||||
private readonly _proxies: { [id: string]: any; };
|
||||
|
||||
constructor() {
|
||||
this._locals = Object.create(null);
|
||||
this._proxies = Object.create(null);
|
||||
}
|
||||
|
||||
private get _callCount(): number {
|
||||
return this._callCountValue;
|
||||
}
|
||||
|
||||
private set _callCount(value: number) {
|
||||
this._callCountValue = value;
|
||||
if (this._callCountValue === 0) {
|
||||
if (this._completeIdle) {
|
||||
this._completeIdle();
|
||||
}
|
||||
this._idle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
sync(): Promise<any> {
|
||||
return new Promise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
if (this._callCount === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this._idle) {
|
||||
this._idle = new Promise<any>((c, e) => {
|
||||
this._completeIdle = c;
|
||||
});
|
||||
}
|
||||
return this._idle;
|
||||
});
|
||||
}
|
||||
|
||||
public getProxy<T>(identifier: ProxyIdentifier<T>): T {
|
||||
if (!this._proxies[identifier.id]) {
|
||||
this._proxies[identifier.id] = this._createProxy(identifier.id);
|
||||
}
|
||||
return this._proxies[identifier.id];
|
||||
}
|
||||
|
||||
private _createProxy<T>(proxyId: string): T {
|
||||
let handler = {
|
||||
get: (target, name: string) => {
|
||||
if (!target[name] && name.charCodeAt(0) === CharCode.DollarSign) {
|
||||
target[name] = (...myArgs: any[]) => {
|
||||
return this._remoteCall(proxyId, name, myArgs);
|
||||
};
|
||||
}
|
||||
return target[name];
|
||||
}
|
||||
};
|
||||
return new Proxy(Object.create(null), handler);
|
||||
}
|
||||
|
||||
public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
this._locals[identifier.id] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
protected _remoteCall(proxyId: string, path: string, args: any[]): TPromise<any> {
|
||||
this._callCount++;
|
||||
|
||||
return new TPromise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
const instance = this._locals[proxyId];
|
||||
// pretend the args went over the wire... (invoke .toJSON on objects...)
|
||||
const wireArgs = simulateWireTransfer(args);
|
||||
let p: Thenable<any>;
|
||||
try {
|
||||
let result = (<Function>instance[path]).apply(instance, wireArgs);
|
||||
p = TPromise.is(result) ? result : TPromise.as(result);
|
||||
} catch (err) {
|
||||
p = TPromise.wrapError(err);
|
||||
}
|
||||
|
||||
return p.then(result => {
|
||||
this._callCount--;
|
||||
// pretend the result went over the wire... (invoke .toJSON on objects...)
|
||||
const wireResult = simulateWireTransfer(result);
|
||||
return wireResult;
|
||||
}, err => {
|
||||
this._callCount--;
|
||||
return TPromise.wrapError(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
|
||||
throw new Error('Not implemented!');
|
||||
}
|
||||
}
|
||||
|
||||
function simulateWireTransfer<T>(obj: T): T {
|
||||
if (!obj) {
|
||||
return obj;
|
||||
}
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IThreadService, ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
|
||||
|
||||
export function OneGetThreadService(thing: any): IThreadService {
|
||||
return {
|
||||
get<T>(): T {
|
||||
return thing;
|
||||
},
|
||||
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
return value;
|
||||
},
|
||||
assertRegistered: undefined
|
||||
};
|
||||
}
|
||||
|
||||
declare var Proxy; // TODO@TypeScript
|
||||
|
||||
export abstract class AbstractTestThreadService {
|
||||
|
||||
private _isMain: boolean;
|
||||
protected _locals: { [id: string]: any; };
|
||||
private _proxies: { [id: string]: any; } = Object.create(null);
|
||||
|
||||
constructor(isMain: boolean) {
|
||||
this._isMain = isMain;
|
||||
this._locals = Object.create(null);
|
||||
this._proxies = Object.create(null);
|
||||
}
|
||||
|
||||
public handle(rpcId: string, methodName: string, args: any[]): any {
|
||||
if (!this._locals[rpcId]) {
|
||||
throw new Error('Unknown actor ' + rpcId);
|
||||
}
|
||||
let actor = this._locals[rpcId];
|
||||
let method = actor[methodName];
|
||||
if (typeof method !== 'function') {
|
||||
throw new Error('Unknown method ' + methodName + ' on actor ' + rpcId);
|
||||
}
|
||||
return method.apply(actor, args);
|
||||
}
|
||||
|
||||
get<T>(identifier: ProxyIdentifier<T>): T {
|
||||
if (!this._proxies[identifier.id]) {
|
||||
this._proxies[identifier.id] = this._createProxy(identifier.id);
|
||||
}
|
||||
return this._proxies[identifier.id];
|
||||
}
|
||||
|
||||
private _createProxy<T>(id: string): T {
|
||||
let handler = {
|
||||
get: (target, name) => {
|
||||
return (...myArgs: any[]) => {
|
||||
return this._callOnRemote(id, name, myArgs);
|
||||
};
|
||||
}
|
||||
};
|
||||
return new Proxy({}, handler);
|
||||
}
|
||||
|
||||
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
if (identifier.isMain !== this._isMain) {
|
||||
throw new Error('Mismatch in object registration!');
|
||||
}
|
||||
this._locals[identifier.id] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
protected abstract _callOnRemote(proxyId: string, path: string, args: any[]): TPromise<any>;
|
||||
}
|
||||
|
||||
export class TestThreadService extends AbstractTestThreadService implements IThreadService {
|
||||
constructor(isMainProcess: boolean = false) {
|
||||
super(isMainProcess);
|
||||
}
|
||||
|
||||
private _callCountValue: number = 0;
|
||||
private _idle: TPromise<any>;
|
||||
private _completeIdle: Function;
|
||||
|
||||
private get _callCount(): number {
|
||||
return this._callCountValue;
|
||||
}
|
||||
|
||||
private set _callCount(value: number) {
|
||||
this._callCountValue = value;
|
||||
if (this._callCountValue === 0) {
|
||||
if (this._completeIdle) {
|
||||
this._completeIdle();
|
||||
}
|
||||
this._idle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
sync(): TPromise<any> {
|
||||
return new TPromise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
if (this._callCount === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this._idle) {
|
||||
this._idle = new TPromise<any>((c, e) => {
|
||||
this._completeIdle = c;
|
||||
}, function () {
|
||||
// no cancel
|
||||
});
|
||||
}
|
||||
return this._idle;
|
||||
});
|
||||
}
|
||||
|
||||
private _testInstances: { [id: string]: any; } = Object.create(null);
|
||||
setTestInstance<T>(identifier: ProxyIdentifier<T>, value: T): T {
|
||||
this._testInstances[identifier.id] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
get<T>(identifier: ProxyIdentifier<T>): T {
|
||||
let id = identifier.id;
|
||||
if (this._locals[id]) {
|
||||
return this._locals[id];
|
||||
}
|
||||
return super.get(identifier);
|
||||
}
|
||||
|
||||
protected _callOnRemote(proxyId: string, path: string, args: any[]): TPromise<any> {
|
||||
this._callCount++;
|
||||
|
||||
return new TPromise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
const instance = this._testInstances[proxyId];
|
||||
let p: Thenable<any>;
|
||||
try {
|
||||
let result = (<Function>instance[path]).apply(instance, args);
|
||||
p = TPromise.is(result) ? result : TPromise.as(result);
|
||||
} catch (err) {
|
||||
p = TPromise.wrapError(err);
|
||||
}
|
||||
|
||||
return p.then(result => {
|
||||
this._callCount--;
|
||||
return result;
|
||||
}, err => {
|
||||
this._callCount--;
|
||||
return TPromise.wrapError(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
|
||||
throw new Error('Not implemented!');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user