Merge branch 'master' into joh/outline

This commit is contained in:
Johannes Rieken
2018-05-15 18:12:33 +02:00
91 changed files with 1429 additions and 575 deletions

View File

@@ -6,11 +6,17 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { asWinJsPromise } from 'vs/base/common/async';
import { IPickOptions, IInputOptions, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { InputBoxOptions } from 'vscode';
import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput } from 'vs/platform/quickinput/common/quickInput';
import { InputBoxOptions, CancellationToken } from 'vscode';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
interface MultiStepSession {
handle: number;
input: IQuickInput;
token: CancellationToken;
}
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
@@ -20,6 +26,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private _doSetError: (error: Error) => any;
private _contents: TPromise<MyQuickPickItems[]>;
private _token: number = 0;
private _multiStep: MultiStepSession;
constructor(
extHostContext: IExtHostContext,
@@ -32,7 +39,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
public dispose(): void {
}
$show(options: IPickOptions): TPromise<number | number[]> {
$show(multiStepHandle: number | undefined, options: IPickOptions): TPromise<number | number[]> {
const multiStep = typeof multiStepHandle === 'number';
if (multiStep && !(this._multiStep && multiStepHandle === this._multiStep.handle && !this._multiStep.token.isCancellationRequested)) {
return TPromise.as(undefined);
}
const input: IQuickInput = multiStep ? this._multiStep.input : this._quickInputService;
const myToken = ++this._token;
@@ -51,7 +64,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
});
if (options.canPickMany) {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
return asWinJsPromise(token => input.pick(this._contents, options as { canPickMany: true }, token)).then(items => {
if (items) {
return items.map(item => item.handle);
}
@@ -62,7 +75,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
}
});
} else {
return asWinJsPromise(token => this._quickInputService.pick(this._contents, options, token)).then(item => {
return asWinJsPromise(token => input.pick(this._contents, options, token)).then(item => {
if (item) {
return item.handle;
}
@@ -91,7 +104,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
// ---- input
$input(options: InputBoxOptions, validateInput: boolean): TPromise<string> {
$input(multiStepHandle: number | undefined, options: InputBoxOptions, validateInput: boolean): TPromise<string> {
const multiStep = typeof multiStepHandle === 'number';
if (multiStep && !(this._multiStep && multiStepHandle === this._multiStep.handle && !this._multiStep.token.isCancellationRequested)) {
return TPromise.as(undefined);
}
const input: IQuickInput = multiStep ? this._multiStep.input : this._quickInputService;
const inputOptions: IInputOptions = Object.create(null);
@@ -110,6 +129,27 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
};
}
return asWinJsPromise(token => this._quickInputService.input(inputOptions, token));
return asWinJsPromise(token => input.input(inputOptions, token));
}
// ---- Multi-step input
$multiStep(handle: number): TPromise<never> {
let outerReject: (err: any) => void;
let innerResolve: (value: void) => void;
const promise = new TPromise<never>((_, rej) => outerReject = rej, () => innerResolve(undefined));
this._quickInputService.multiStepInput((input, token) => {
this._multiStep = { handle, input, token };
const promise = new TPromise<void>(res => innerResolve = res);
token.onCancellationRequested(() => innerResolve(undefined));
return promise;
})
.then(() => promise.cancel(), err => outerReject(err))
.then(() => {
if (this._multiStep && this._multiStep.handle === handle) {
this._multiStep = null;
}
});
return promise;
}
}

View File

@@ -26,7 +26,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import {
TaskDefinitionDTO, TaskExecutionDTO, ProcessExecutionOptionsDTO, TaskPresentationOptionsDTO,
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO
} from 'vs/workbench/api/shared/tasks';
export { TaskDTO, TaskHandleDTO, TaskExecutionDTO, TaskFilterDTO };
@@ -46,6 +46,24 @@ namespace TaskExecutionDTO {
}
}
namespace TaskProcessStartedDTO {
export function from(value: TaskExecution, processId: number): TaskProcessStartedDTO {
return {
id: value.id,
processId
};
}
}
namespace TaskProcessEndedDTO {
export function from(value: TaskExecution, exitCode: number): TaskProcessEndedDTO {
return {
id: value.id,
exitCode
};
}
}
namespace TaskDefinitionDTO {
export function from(value: TaskIdentifier): TaskDefinitionDTO {
let result = Objects.assign(Object.create(null), value);
@@ -352,9 +370,13 @@ export class MainThreadTask implements MainThreadTaskShape {
this._taskService.onDidStateChange((event: TaskEvent) => {
let task = event.__task;
if (event.kind === TaskEventKind.Start) {
this._proxy.$taskStarted(TaskExecutionDTO.from(Task.getTaskExecution(task)));
this._proxy.$onDidStartTask(TaskExecutionDTO.from(Task.getTaskExecution(task)));
} else if (event.kind === TaskEventKind.ProcessStarted) {
this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(Task.getTaskExecution(task), event.processId));
} else if (event.kind === TaskEventKind.ProcessEnded) {
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(Task.getTaskExecution(task), event.exitCode));
} else if (event.kind === TaskEventKind.End) {
this._proxy.$taskEnded(TaskExecutionDTO.from(Task.getTaskExecution(task)));
this._proxy.$OnDidEndTask(TaskExecutionDTO.from(Task.getTaskExecution(task)));
}
});
}
@@ -417,7 +439,7 @@ export class MainThreadTask implements MainThreadTaskShape {
task: TaskDTO.from(task)
};
resolve(result);
}, (error) => {
}, (_error) => {
reject(new Error('Task not found'));
});
} else {

View File

@@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeViewer } from 'vs/workbench/common/views';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { distinct } from 'vs/base/common/arrays';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -34,6 +34,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
const treeViewer = this.viewsService.getTreeViewer(treeViewId);
if (treeViewer) {
treeViewer.dataProvider = dataProvider;
this.registerListeners(treeViewId, treeViewer);
} else {
this.notificationService.error('No view is registered with id: ' + treeViewId);
}
@@ -54,6 +55,12 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
private registerListeners(treeViewId: string, treeViewer: ITreeViewer): void {
this._register(treeViewer.onDidExpandItem(item => this._proxy.$setExpanded(treeViewId, item.handle, true)));
this._register(treeViewer.onDidCollapseItem(item => this._proxy.$setExpanded(treeViewId, item.handle, false)));
this._register(treeViewer.onDidChangeSelection(items => this._proxy.$setSelection(treeViewId, items.map(({ handle }) => handle))));
}
dispose(): void {
this._dataProviders.clear();
super.dispose();

View File

@@ -23,8 +23,6 @@ import { extHostNamedCustomer } from './extHostCustomers';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
private static readonly serializeTimeout = 500; // ms
private static readonly viewType = 'mainThreadWebview';
private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto'];
@@ -136,7 +134,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._webviews.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
return this._proxy.$deserializeWebviewPanel(handle, webview.state.viewType, webview.getTitle(), webview.state.state, webview.position, webview.options)
let state;
try {
state = JSON.parse(webview.state.state);
} catch {
state = {};
}
return this._proxy.$deserializeWebviewPanel(handle, webview.state.viewType, webview.getTitle(), state, webview.position, webview.options)
.then(undefined, () => {
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
});
@@ -148,38 +153,18 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
return false;
}
return this._revivers.has(webview.viewType) || webview.reviver !== null;
return (this._revivers.has(webview.viewType) || webview.reviver !== null);
}
private _onWillShutdown(): TPromise<boolean> {
const toRevive: WebviewPanelHandle[] = [];
this._webviews.forEach((view, key) => {
this._webviews.forEach((view) => {
if (this.canRevive(view)) {
toRevive.push(key);
view.state.state = view.webviewState;
}
});
const reviveResponses = toRevive.map(handle =>
TPromise.any([
this._proxy.$serializeWebviewPanel(handle).then(
state => ({ handle, state }),
() => ({ handle, state: null })),
TPromise.timeout(MainThreadWebviews.serializeTimeout).then(() => ({ handle, state: null }))
]).then(x => x.value));
return TPromise.as(false); // Don't veto shutdown
return TPromise.join(reviveResponses).then(results => {
for (const result of results) {
const view = this._webviews.get(result.handle);
if (view) {
if (result.state) {
view.state.state = result.state;
} else {
view.state = null;
}
}
}
return false; // Don't veto shutdown
});
}
private createWebviewEventDelegate(handle: WebviewPanelHandle) {

View File

@@ -31,7 +31,7 @@ import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalSer
import { ExtHostMessageService } from 'vs/workbench/api/node/extHostMessageService';
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
import { ExtHostLanguages } from 'vs/workbench/api/node/extHostLanguages';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/node/extHostLanguageFeatures';
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
@@ -95,6 +95,8 @@ export function createApiFactory(
extHostLogService: ExtHostLogService
): IExtensionApiFactory {
let schemeTransformer: ISchemeTransformer = null;
// Addressable instances
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
@@ -112,13 +114,13 @@ export function createApiFactory(
const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration));
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, schemeTransformer, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostLogService));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol));
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer));
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace));
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
@@ -384,13 +386,16 @@ export function createApiFactory(
return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest);
},
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any {
return extHostQuickOpen.showQuickPick(items, options, token);
return extHostQuickOpen.showQuickPick(undefined, items, options, token);
},
showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) {
return extHostQuickOpen.showWorkspaceFolderPick(options);
},
showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
return extHostQuickOpen.showInput(options, token);
return extHostQuickOpen.showInput(undefined, options, token);
},
multiStepInput<T>(handler: (input: vscode.QuickInput, token: vscode.CancellationToken) => Thenable<T>, token?: vscode.CancellationToken): Thenable<T> {
return extHostQuickOpen.multiStepInput(handler, token);
},
showOpenDialog(options) {
return extHostDialogs.showOpenDialog(options);

View File

@@ -48,7 +48,7 @@ import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/
import { ISingleEditOperation } from 'vs/editor/common/model';
import { IPatternInfo, IRawSearchQuery, IRawFileMatch2 } from 'vs/platform/search/common/search';
import { LogLevel } from 'vs/platform/log/common/log';
import { TaskExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO } from 'vs/workbench/api/shared/tasks';
import { TaskExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO } from 'vs/workbench/api/shared/tasks';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -332,10 +332,11 @@ export interface MyQuickPickItems extends IPickOpenEntry {
handle: number;
}
export interface MainThreadQuickOpenShape extends IDisposable {
$show(options: IPickOptions): TPromise<number | number[]>;
$show(multiStepHandle: number | undefined, options: IPickOptions): TPromise<number | number[]>;
$setItems(items: MyQuickPickItems[]): TPromise<any>;
$setError(error: Error): TPromise<any>;
$input(options: vscode.InputBoxOptions, validateInput: boolean): TPromise<string>;
$input(multiStepHandle: number | undefined, options: vscode.InputBoxOptions, validateInput: boolean): TPromise<string>;
$multiStep(handle: number): TPromise<never>;
}
export interface MainThreadStatusBarShape extends IDisposable {
@@ -371,7 +372,6 @@ export interface ExtHostWebviewsShape {
$onDidChangeWebviewPanelViewState(handle: WebviewPanelHandle, active: boolean, position: EditorPosition): void;
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Thenable<void>;
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorPosition, options: vscode.WebviewOptions): Thenable<void>;
$serializeWebviewPanel(webviewHandle: WebviewPanelHandle): Thenable<any>;
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -575,6 +575,8 @@ export interface ExtHostDocumentsAndEditorsShape {
export interface ExtHostTreeViewsShape {
$getChildren(treeViewId: string, treeItemHandle?: string): TPromise<ITreeItem[]>;
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
}
export interface ExtHostWorkspaceShape {
@@ -775,8 +777,10 @@ export interface ExtHostSCMShape {
export interface ExtHostTaskShape {
$provideTasks(handle: number): TPromise<TaskSet>;
$taskStarted(execution: TaskExecutionDTO): void;
$taskEnded(execution: TaskExecutionDTO): void;
$onDidStartTask(execution: TaskExecutionDTO): void;
$onDidStartTaskProcess(value: TaskProcessStartedDTO): void;
$onDidEndTaskProcess(value: TaskProcessEndedDTO): void;
$OnDidEndTask(execution: TaskExecutionDTO): void;
}
export interface IBreakpointDto {

View File

@@ -6,11 +6,12 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { wireCancellationToken, asWinJsPromise } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder, QuickInput } from 'vscode';
import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { isPromiseCanceledError } from 'vs/base/common/errors';
export type Item = string | QuickPickItem;
@@ -23,23 +24,25 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
private _onDidSelectItem: (handle: number) => void;
private _validateInput: (input: string) => string | Thenable<string>;
private _nextMultiStepHandle = 1;
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) {
this._proxy = mainContext.getProxy(MainContext.MainThreadQuickOpen);
this._workspace = workspace;
this._commands = commands;
}
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
showQuickPick(itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
showQuickPick(itemsOrItemsPromise: Item[] | Thenable<Item[]>, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
showQuickPick(multiStepHandle: number | undefined, itemsOrItemsPromise: Item[] | Thenable<Item[]>, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
// clear state from last invocation
this._onDidSelectItem = undefined;
const itemsPromise = <TPromise<Item[]>>TPromise.wrap(itemsOrItemsPromise);
const quickPickWidget = this._proxy.$show({
const quickPickWidget = this._proxy.$show(multiStepHandle, {
placeHolder: options && options.placeHolder,
matchOnDescription: options && options.matchOnDescription,
matchOnDetail: options && options.matchOnDetail,
@@ -115,12 +118,12 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
// ---- input
showInput(options?: InputBoxOptions, token: CancellationToken = CancellationToken.None): Thenable<string> {
showInput(multiStepHandle: number | undefined, options?: InputBoxOptions, token: CancellationToken = CancellationToken.None): Thenable<string> {
// global validate fn used in callback below
this._validateInput = options && options.validateInput;
const promise = this._proxy.$input(options, typeof this._validateInput === 'function');
const promise = this._proxy.$input(multiStepHandle, options, typeof this._validateInput === 'function');
return wireCancellationToken(token, promise, true);
}
@@ -142,4 +145,42 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0];
});
}
// ---- Multi-step input
multiStepInput<T>(handler: (input: QuickInput, token: CancellationToken) => Thenable<T>, clientToken: CancellationToken = CancellationToken.None): Thenable<T> {
const handle = this._nextMultiStepHandle++;
const remotePromise = this._proxy.$multiStep(handle);
const cancellationSource = new CancellationTokenSource();
const handlerPromise = TPromise.wrap(handler({
showQuickPick: this.showQuickPick.bind(this, handle),
showInputBox: this.showInput.bind(this, handle)
}, cancellationSource.token));
clientToken.onCancellationRequested(() => {
remotePromise.cancel();
cancellationSource.cancel();
});
return TPromise.join<void, T>([
remotePromise.then(() => {
throw new Error('Unexpectedly fulfilled promise.');
}, err => {
if (!isPromiseCanceledError(err)) {
throw err;
}
cancellationSource.cancel();
}),
handlerPromise.then(result => {
remotePromise.cancel();
return result;
}, err => {
remotePromise.cancel();
throw err;
})
]).then(([_, result]) => result, ([remoteErr, handlerErr]) => {
throw handlerErr || remoteErr;
});
}
}

View File

@@ -22,22 +22,35 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
type OneOrMore<T> = T | T[];
export interface ISchemeTransformer {
transformOutgoing(scheme: string): string;
}
export class ExtHostSearch implements ExtHostSearchShape {
private readonly _schemeTransformer: ISchemeTransformer;
private readonly _proxy: MainThreadSearchShape;
private readonly _searchProvider = new Map<number, vscode.SearchProvider>();
private _handlePool: number = 0;
private _fileSearchManager = new FileSearchManager();
constructor(mainContext: IMainContext) {
constructor(mainContext: IMainContext, schemeTransformer: ISchemeTransformer) {
this._schemeTransformer = schemeTransformer;
this._proxy = mainContext.getProxy(MainContext.MainThreadSearch);
}
private _transformScheme(scheme: string): string {
if (this._schemeTransformer) {
return this._schemeTransformer.transformOutgoing(scheme);
}
return scheme;
}
registerSearchProvider(scheme: string, provider: vscode.SearchProvider) {
const handle = this._handlePool++;
this._searchProvider.set(handle, provider);
this._proxy.$registerSearchProvider(handle, scheme);
this._proxy.$registerSearchProvider(handle, this._transformScheme(scheme));
return {
dispose: () => {
this._searchProvider.delete(handle);
@@ -175,7 +188,9 @@ class TextSearchResultsCollector {
}
private pushToCollector(): void {
const size = this._currentFileMatch.lineMatches.reduce((acc, match) => acc + match.offsetAndLengths.length, 0);
const size = this._currentFileMatch ?
this._currentFileMatch.lineMatches.reduce((acc, match) => acc + match.offsetAndLengths.length, 0) :
0;
this._batchedCollector.addItem(this._currentFileMatch, size);
}

View File

@@ -21,7 +21,7 @@ import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import * as vscode from 'vscode';
import {
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, ProcessExecutionOptionsDTO, ProcessExecutionDTO,
ShellExecutionOptionsDTO, ShellExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO
ShellExecutionOptionsDTO, ShellExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO
} from '../shared/tasks';
export { TaskExecutionDTO };
@@ -689,21 +689,47 @@ namespace TaskFilterDTO {
}
class TaskExecutionImpl implements vscode.TaskExecution {
constructor(readonly _id: string, private readonly _task: vscode.Task, private readonly _tasks: ExtHostTask) {
private readonly _onDidTaskProcessStarted: Emitter<vscode.TaskProcessStartEvent> = new Emitter<vscode.TaskProcessStartEvent>();
private readonly _onDidTaskProcessEnded: Emitter<vscode.TaskProcessEndEvent> = new Emitter<vscode.TaskProcessEndEvent>();
constructor(private readonly _tasks: ExtHostTask, readonly _id: string, private readonly _task: vscode.Task) {
}
get task(): vscode.Task {
public get task(): vscode.Task {
return this._task;
}
public terminate(): void {
this._tasks.terminateTask(this);
}
public get onDidStartProcess(): Event<vscode.TaskProcessStartEvent> {
return this._onDidTaskProcessStarted.event;
}
public fireDidStartProcess(value: TaskProcessStartedDTO): void {
this._onDidTaskProcessStarted.fire({
execution: this,
processId: value.processId
});
}
public get onDidEndProcess(): Event<vscode.TaskProcessEndEvent> {
return this._onDidTaskProcessEnded.event;
}
public fireDidEndProcess(value: TaskProcessEndedDTO): void {
this._onDidTaskProcessEnded.fire({
execution: this,
exitCode: value.exitCode
});
}
}
namespace TaskExecutionDTO {
export function to(value: TaskExecutionDTO, tasks: ExtHostTask): vscode.TaskExecution {
return new TaskExecutionImpl(value.id, TaskDTO.to(value.task, tasks.extHostWorkspace), tasks);
return new TaskExecutionImpl(tasks, value.id, TaskDTO.to(value.task, tasks.extHostWorkspace));
}
export function from(value: vscode.TaskExecution): TaskExecutionDTO {
return {
@@ -781,12 +807,26 @@ export class ExtHostTask implements ExtHostTaskShape {
}
}
public $taskStarted(execution: TaskExecutionDTO): void {
public $onDidStartTask(execution: TaskExecutionDTO): void {
this._onDidExecuteTask.fire({
execution: this.getTaskExecution(execution)
});
}
public $onDidStartTaskProcess(value: TaskProcessStartedDTO): void {
const execution = this.getTaskExecution(value.id);
if (execution) {
execution.fireDidStartProcess(value);
}
}
public $onDidEndTaskProcess(value: TaskProcessEndedDTO): void {
const execution = this.getTaskExecution(value.id);
if (execution) {
execution.fireDidEndProcess(value);
}
}
get taskExecutions(): vscode.TaskExecution[] {
let result: vscode.TaskExecution[] = [];
this._taskExecutions.forEach(value => result.push(value));
@@ -804,7 +844,7 @@ export class ExtHostTask implements ExtHostTaskShape {
return this._proxy.$terminateTask((execution as TaskExecutionImpl)._id);
}
public $taskEnded(execution: TaskExecutionDTO): void {
public $OnDidEndTask(execution: TaskExecutionDTO): void {
const _execution = this.getTaskExecution(execution);
this._taskExecutions.delete(execution.id);
this._onDidTerminateTask.fire({
@@ -834,12 +874,16 @@ export class ExtHostTask implements ExtHostTaskShape {
return this._handleCounter++;
}
private getTaskExecution(execution: TaskExecutionDTO, task?: vscode.Task): TaskExecutionImpl {
private getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): TaskExecutionImpl {
if (typeof execution === 'string') {
return this._taskExecutions.get(execution);
}
let result: TaskExecutionImpl = this._taskExecutions.get(execution.id);
if (result) {
return result;
}
result = new TaskExecutionImpl(execution.id, task ? task : TaskDTO.to(execution.task, this._extHostWorkspace), this);
result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, this._extHostWorkspace));
this._taskExecutions.set(execution.id, result);
return result;
}

View File

@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import * as vscode from 'vscode';
import { basename } from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { debounceEvent } from 'vs/base/common/event';
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
@@ -67,6 +67,22 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
return treeView.getChildren(treeItemHandle);
}
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
treeView.setExpanded(treeItemHandle, expanded);
}
$setSelection(treeViewId: string, treeItemHandles: string[]): void {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
throw new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
treeView.setSelection(treeItemHandles);
}
private createExtHostTreeViewer<T>(id: string, dataProvider: vscode.TreeDataProvider<T>): ExtHostTreeView<T> {
const treeView = new ExtHostTreeView<T>(id, dataProvider, this._proxy, this.commands.converter);
this.treeViews.set(id, treeView);
@@ -94,6 +110,15 @@ class ExtHostTreeView<T> extends Disposable {
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
private nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
private _selectedElements: T[] = [];
get selectedElements(): T[] { return this._selectedElements; }
private _onDidExpandElement: Emitter<T> = this._register(new Emitter<T>());
readonly onDidExpandElement: Event<T> = this._onDidExpandElement.event;
private _onDidCollapseElement: Emitter<T> = this._register(new Emitter<T>());
readonly onDidCollapseElement: Event<T> = this._onDidCollapseElement.event;
constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) {
super();
this.proxy.$registerTreeViewDataProvider(viewId);
@@ -127,6 +152,21 @@ class ExtHostTreeView<T> extends Disposable {
.then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), options)));
}
setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void {
const element = this.getExtensionElement(treeItemHandle);
if (element) {
if (expanded) {
this._onDidExpandElement.fire(element);
} else {
this._onDidCollapseElement.fire(element);
}
}
}
setSelection(treeItemHandles: TreeItemHandle[]): void {
this._selectedElements = treeItemHandles.map(handle => this.getExtensionElement(handle)).filter(element => !isUndefinedOrNull(element));
}
private resolveUnknownParentChain(element: T): TPromise<TreeNode[]> {
return this.resolveParent(element)
.then((parent) => {

View File

@@ -288,22 +288,6 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
return serializer.deserializeWebviewPanel(revivedPanel, state);
}
$serializeWebviewPanel(
webviewHandle: WebviewPanelHandle
): Thenable<any> {
const panel = this.getWebviewPanel(webviewHandle);
if (!panel) {
return TPromise.as(undefined);
}
const serialzer = this._serializers.get(panel.viewType);
if (!serialzer) {
return TPromise.as(undefined);
}
return serialzer.serializeWebviewPanel(panel);
}
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewPanel | undefined {
return this._webviewPanels.get(handle);
}

View File

@@ -88,6 +88,17 @@ export interface TaskExecutionDTO {
task: TaskDTO;
}
export interface TaskProcessStartedDTO {
id: string;
processId: number;
}
export interface TaskProcessEndedDTO {
id: string;
exitCode: number;
}
export interface TaskFilterDTO {
version?: string;
type?: string;