Vscode merge (#4582)

* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
This commit is contained in:
Anthony Dresser
2019-03-19 17:44:35 -07:00
committed by GitHub
parent 833d197412
commit 87765e8673
1879 changed files with 54505 additions and 38058 deletions

View File

@@ -9,9 +9,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// --- other interested parties
import { JSONValidationExtensionPoint } from 'vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint';
import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint';
import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint';
import { LanguageConfigurationFileHandler } from 'vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint';
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
// --- mainThread participants
import 'vs/workbench/api/node/apiCommands';

View File

@@ -20,6 +20,6 @@ export class MainThreadCommands implements MainThreadClipboardShape {
$writeText(value: string): Promise<void> {
clipboard.writeText(value);
return undefined;
return Promise.resolve();
}
}

View File

@@ -64,13 +64,14 @@ export class MainThreadCommands implements MainThreadCommandsShape {
}
$unregisterCommand(id: string): void {
if (this._disposables.has(id)) {
this._disposables.get(id).dispose();
const command = this._disposables.get(id);
if (command) {
command.dispose();
this._disposables.delete(id);
}
}
$executeCommand<T>(id: string, args: any[]): Promise<T> {
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined> {
for (let i = 0; i < args.length; i++) {
args[i] = revive(args[i], 0);
}
@@ -88,7 +89,7 @@ function _generateMarkdown(description: string | ICommandHandlerDescription): st
if (typeof description === 'string') {
return description;
} else {
let parts = [description.description];
const parts = [description.description];
parts.push('\n\n');
if (description.args) {
for (let arg of description.args) {

View File

@@ -11,26 +11,28 @@ import { keys } from 'vs/base/common/map';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentProviderFeatures } from '../node/extHost.protocol';
import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService';
import { COMMENTS_PANEL_ID, CommentsPanel, COMMENTS_PANEL_TITLE } from 'vs/workbench/parts/comments/electron-browser/commentsPanel';
import { ICommentService, ICommentInfo } from 'vs/workbench/contrib/comments/electron-browser/commentService';
import { COMMENTS_PANEL_ID, CommentsPanel, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/electron-browser/commentsPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { generateUuid } from 'vs/base/common/uuid';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommentsConfiguration } from 'vs/workbench/parts/comments/electron-browser/comments.contribution';
import { ICommentsConfiguration } from 'vs/workbench/contrib/comments/electron-browser/comments.contribution';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { Registry } from 'vs/platform/registry/common/platform';
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
import { IRange } from 'vs/editor/common/core/range';
import { Emitter, Event } from 'vs/base/common/event';
export class MainThreadDocumentCommentProvider implements modes.DocumentCommentProvider {
private _proxy: ExtHostCommentsShape;
private _handle: number;
private _features: CommentProviderFeatures;
get startDraftLabel(): string { return this._features.startDraftLabel; }
get deleteDraftLabel(): string { return this._features.deleteDraftLabel; }
get finishDraftLabel(): string { return this._features.finishDraftLabel; }
get reactionGroup(): modes.CommentReaction[] { return this._features.reactionGroup; }
private readonly _proxy: ExtHostCommentsShape;
private readonly _handle: number;
private readonly _features: CommentProviderFeatures;
get startDraftLabel(): string | undefined { return this._features.startDraftLabel; }
get deleteDraftLabel(): string | undefined { return this._features.deleteDraftLabel; }
get finishDraftLabel(): string | undefined { return this._features.finishDraftLabel; }
get reactionGroup(): modes.CommentReaction[] | undefined { return this._features.reactionGroup; }
constructor(proxy: ExtHostCommentsShape, handle: number, features: CommentProviderFeatures) {
this._proxy = proxy;
@@ -75,16 +77,330 @@ export class MainThreadDocumentCommentProvider implements modes.DocumentCommentP
}
onDidChangeCommentThreads = null;
// onDidChangeCommentThreads = null;
}
export class MainThreadCommentThread implements modes.CommentThread2 {
private _input?: modes.CommentInput;
get input(): modes.CommentInput | undefined {
return this._input;
}
set input(value: modes.CommentInput | undefined) {
this._input = value;
this._onDidChangeInput.fire(value);
}
private _onDidChangeInput = new Emitter<modes.CommentInput | undefined>();
get onDidChangeInput(): Event<modes.CommentInput | undefined> { return this._onDidChangeInput.event; }
private _label: string;
get label(): string {
return this._label;
}
set label(label: string) {
this._label = label;
this._onDidChangeLabel.fire(this._label);
}
private _onDidChangeLabel = new Emitter<string>();
get onDidChangeLabel(): Event<string> { return this._onDidChangeLabel.event; }
public get comments(): modes.Comment[] {
return this._comments;
}
public set comments(newComments: modes.Comment[]) {
this._comments = newComments;
this._onDidChangeComments.fire(this._comments);
}
private _onDidChangeComments = new Emitter<modes.Comment[]>();
get onDidChangeComments(): Event<modes.Comment[]> { return this._onDidChangeComments.event; }
set acceptInputCommand(newCommand: modes.Command) {
this._acceptInputCommand = newCommand;
this._onDidChangeAcceptInputCommand.fire(this._acceptInputCommand);
}
get acceptInputCommand(): modes.Command {
return this._acceptInputCommand!;
}
private _onDidChangeAcceptInputCommand = new Emitter<modes.Command>();
get onDidChangeAcceptInputCommand(): Event<modes.Command> { return this._onDidChangeAcceptInputCommand.event; }
set additionalCommands(newCommands: modes.Command[]) {
this._additionalCommands = newCommands;
this._onDidChangeAdditionalCommands.fire(this._additionalCommands);
}
get additionalCommands(): modes.Command[] {
return this._additionalCommands;
}
private _onDidChangeAdditionalCommands = new Emitter<modes.Command[]>();
get onDidChangeAdditionalCommands(): Event<modes.Command[]> { return this._onDidChangeAdditionalCommands.event; }
set range(range: IRange) {
this._range = range;
this._onDidChangeRange.fire(this._range);
}
get range(): IRange {
return this._range;
}
private _onDidChangeRange = new Emitter<IRange>();
public onDidChangeRange = this._onDidChangeRange.event;
get collapsibleState() {
return this._collapsibleState;
}
set collapsibleState(newState: modes.CommentThreadCollapsibleState) {
this._collapsibleState = newState;
this._onDidChangeCollasibleState.fire(this._collapsibleState);
}
private _onDidChangeCollasibleState = new Emitter<modes.CommentThreadCollapsibleState>();
public onDidChangeCollasibleState = this._onDidChangeCollasibleState.event;
constructor(
public commentThreadHandle: number,
public controller: MainThreadCommentController,
public extensionId: string,
public threadId: string,
public resource: string,
private _range: IRange,
private _comments: modes.Comment[],
private _acceptInputCommand: modes.Command | undefined,
private _additionalCommands: modes.Command[],
private _collapsibleState: modes.CommentThreadCollapsibleState
) {
}
dispose() { }
toJSON(): any {
return {
$mid: 7,
commentControlHandle: this.controller.handle,
commentThreadHandle: this.commentThreadHandle,
};
}
}
export class MainThreadCommentController {
get handle(): number {
return this._handle;
}
get id(): string {
return this._id;
}
get proxy(): ExtHostCommentsShape {
return this._proxy;
}
get label(): string {
return this._label;
}
private _reactions: modes.CommentReaction[] | undefined;
get reactions() {
return this._reactions;
}
set reactions(reactions: modes.CommentReaction[] | undefined) {
this._reactions = reactions;
}
private readonly _threads: Map<number, MainThreadCommentThread> = new Map<number, MainThreadCommentThread>();
public activeCommentThread?: MainThreadCommentThread;
constructor(
private readonly _proxy: ExtHostCommentsShape,
private readonly _commentService: ICommentService,
private readonly _handle: number,
private readonly _uniqueId: string,
private readonly _id: string,
private readonly _label: string,
private _features: CommentProviderFeatures
) { }
updateFeatures(features: CommentProviderFeatures) {
this._features = features;
}
createCommentThread(commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 {
let thread = new MainThreadCommentThread(
commentThreadHandle,
this,
'',
threadId,
URI.revive(resource).toString(),
range,
comments,
acceptInputCommand,
additionalCommands,
collapseState
);
this._threads.set(commentThreadHandle, thread);
this._commentService.updateComments(this._uniqueId, {
added: [thread],
removed: [],
changed: [],
draftMode: modes.DraftMode.NotSupported
});
return thread;
}
deleteCommentThread(commentThreadHandle: number) {
let thread = this.getKnownThread(commentThreadHandle);
this._threads.delete(commentThreadHandle);
this._commentService.updateComments(this._uniqueId, {
added: [],
removed: [thread],
changed: [],
draftMode: modes.DraftMode.NotSupported
});
thread.dispose();
}
updateComments(commentThreadHandle: number, comments: modes.Comment[]) {
let thread = this.getKnownThread(commentThreadHandle);
thread.comments = comments;
this._commentService.updateComments(this._uniqueId, {
added: [],
removed: [],
changed: [thread],
draftMode: modes.DraftMode.NotSupported
});
}
updateAcceptInputCommand(commentThreadHandle: number, acceptInputCommand: modes.Command) {
let thread = this.getKnownThread(commentThreadHandle);
thread.acceptInputCommand = acceptInputCommand;
}
updateAdditionalCommands(commentThreadHandle: number, additionalCommands: modes.Command[]) {
let thread = this.getKnownThread(commentThreadHandle);
thread.additionalCommands = additionalCommands;
}
updateCollapsibleState(commentThreadHandle: number, collapseState: modes.CommentThreadCollapsibleState) {
let thread = this.getKnownThread(commentThreadHandle);
thread.collapsibleState = collapseState;
}
updateCommentThreadRange(commentThreadHandle: number, range: IRange) {
let thread = this.getKnownThread(commentThreadHandle);
thread.range = range;
}
updateCommentThreadLabel(commentThreadHandle: number, label: string) {
let thread = this.getKnownThread(commentThreadHandle);
thread.label = label;
}
updateInput(input: string) {
let thread = this.activeCommentThread;
if (thread && thread.input) {
let commentInput = thread.input;
commentInput.value = input;
thread.input = commentInput;
}
}
private getKnownThread(commentThreadHandle: number) {
const thread = this._threads.get(commentThreadHandle);
if (!thread) {
throw new Error('unknown thread');
}
return thread;
}
async getDocumentComments(resource: URI, token) {
let ret: modes.CommentThread2[] = [];
for (let thread of keys(this._threads)) {
const commentThread = this._threads.get(thread)!;
if (commentThread.resource === resource.toString()) {
ret.push(commentThread);
}
}
let commentingRanges = await this._proxy.$provideCommentingRanges(this.handle, resource, token);
return <ICommentInfo>{
owner: this._uniqueId,
threads: ret,
commentingRanges: commentingRanges ?
{
resource: resource, ranges: commentingRanges, newCommentThreadCallback: (uri: UriComponents, range: IRange) => {
this._proxy.$createNewCommentWidgetCallback(this.handle, uri, range, token);
}
} : [],
draftMode: modes.DraftMode.NotSupported
};
}
async getCommentingRanges(resource: URI, token): Promise<IRange[]> {
let commentingRanges = await this._proxy.$provideCommentingRanges(this.handle, resource, token);
return commentingRanges || [];
}
getReactionGroup(): modes.CommentReaction[] | undefined {
return this._features.reactionGroup;
}
async toggleReaction(uri, thread: modes.CommentThread2, comment: modes.Comment, reaction: modes.CommentReaction, token): Promise<void> {
return this._proxy.$toggleReaction(this._handle, thread.commentThreadHandle, uri, comment, reaction);
}
getAllComments(): MainThreadCommentThread[] {
let ret: MainThreadCommentThread[] = [];
for (let thread of keys(this._threads)) {
ret.push(this._threads.get(thread)!);
}
return ret;
}
toJSON(): any {
return {
$mid: 6,
handle: this.handle
};
}
}
@extHostNamedCustomer(MainContext.MainThreadComments)
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
private _disposables: IDisposable[];
private _proxy: ExtHostCommentsShape;
private _activeCommentThreadDisposables: IDisposable[];
private readonly _proxy: ExtHostCommentsShape;
private _documentProviders = new Map<number, IDisposable>();
private _workspaceProviders = new Map<number, IDisposable>();
private _handlers = new Map<number, string>();
private _commentControllers = new Map<number, MainThreadCommentController>();
private _activeCommentThread?: MainThreadCommentThread;
private _input?: modes.CommentInput;
private _openPanelListener: IDisposable | null;
constructor(
@@ -97,7 +413,149 @@ export class MainThreadComments extends Disposable implements MainThreadComments
) {
super();
this._disposables = [];
this._activeCommentThreadDisposables = [];
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments);
this._disposables.push(this._commentService.onDidChangeActiveCommentThread(async thread => {
let controller = (thread as MainThreadCommentThread).controller;
if (!controller) {
return;
}
this._activeCommentThreadDisposables = dispose(this._activeCommentThreadDisposables);
this._activeCommentThread = thread as MainThreadCommentThread;
controller.activeCommentThread = this._activeCommentThread;
this._activeCommentThreadDisposables.push(this._activeCommentThread.onDidChangeInput(input => { // todo, dispose
this._input = input;
this._proxy.$onCommentWidgetInputChange(controller.handle, this._input ? this._input.value : undefined);
}));
await this._proxy.$onCommentWidgetInputChange(controller.handle, this._input ? this._input.value : undefined);
}));
}
$registerCommentController(handle: number, id: string, label: string): void {
const providerId = generateUuid();
this._handlers.set(handle, providerId);
const provider = new MainThreadCommentController(this._proxy, this._commentService, handle, providerId, id, label, {});
this._commentService.registerCommentController(providerId, provider);
this._commentControllers.set(handle, provider);
const commentsPanelAlreadyConstructed = this._panelService.getPanels().some(panel => panel.id === COMMENTS_PANEL_ID);
if (!commentsPanelAlreadyConstructed) {
this.registerPanel(commentsPanelAlreadyConstructed);
this.registerOpenPanelListener(commentsPanelAlreadyConstructed);
}
this._commentService.setWorkspaceComments(String(handle), []);
}
$unregisterCommentController(handle: number): void {
const providerId = this._handlers.get(handle);
this._commentService.unregisterCommentController(providerId);
this._handlers.delete(handle);
this._commentControllers.delete(handle);
}
$updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void {
let provider = this._commentControllers.get(handle);
if (!provider) {
return undefined;
}
provider.updateFeatures(features);
}
$createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], collapseState: modes.CommentThreadCollapsibleState): modes.CommentThread2 | undefined {
let provider = this._commentControllers.get(handle);
if (!provider) {
return undefined;
}
return provider.createCommentThread(commentThreadHandle, threadId, resource, range, comments, acceptInputCommand, additionalCommands, collapseState);
}
$deleteCommentThread(handle: number, commentThreadHandle: number) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
return provider.deleteCommentThread(commentThreadHandle);
}
$updateComments(handle: number, commentThreadHandle: number, comments: modes.Comment[]) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateComments(commentThreadHandle, comments);
}
$setInputValue(handle: number, input: string) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateInput(input);
}
$updateCommentThreadAcceptInputCommand(handle: number, commentThreadHandle: number, acceptInputCommand: modes.Command) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateAcceptInputCommand(commentThreadHandle, acceptInputCommand);
}
$updateCommentThreadAdditionalCommands(handle: number, commentThreadHandle: number, additionalCommands: modes.Command[]) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateAdditionalCommands(commentThreadHandle, additionalCommands);
}
$updateCommentThreadCollapsibleState(handle: number, commentThreadHandle: number, collapseState: modes.CommentThreadCollapsibleState): void {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateCollapsibleState(commentThreadHandle, collapseState);
}
$updateCommentThreadRange(handle: number, commentThreadHandle: number, range: any): void {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateCommentThreadRange(commentThreadHandle, range);
}
$updateCommentThreadLabel(handle: number, commentThreadHandle: number, label: string): void {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateCommentThreadLabel(commentThreadHandle, label);
}
$registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void {
@@ -110,6 +568,18 @@ export class MainThreadComments extends Disposable implements MainThreadComments
this._commentService.registerDataProvider(providerId, handler);
}
private registerPanel(commentsPanelAlreadyConstructed: boolean) {
if (!commentsPanelAlreadyConstructed) {
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
CommentsPanel,
COMMENTS_PANEL_ID,
COMMENTS_PANEL_TITLE,
'commentsPanel',
10
));
}
}
/**
* If the comments panel has never been opened, the constructor for it has not yet run so it has
* no listeners for comment threads being set or updated. Listen for the panel opening for the
@@ -122,20 +592,37 @@ export class MainThreadComments extends Disposable implements MainThreadComments
keys(this._workspaceProviders).forEach(handle => {
this._proxy.$provideWorkspaceComments(handle).then(commentThreads => {
if (commentThreads) {
const providerId = this._handlers.get(handle);
const providerId = this.getHandler(handle);
this._commentService.setWorkspaceComments(providerId, commentThreads);
}
});
});
this._openPanelListener.dispose();
this._openPanelListener = null;
keys(this._commentControllers).forEach(handle => {
let threads = this._commentControllers.get(handle)!.getAllComments();
if (threads.length) {
const providerId = this.getHandler(handle);
this._commentService.setWorkspaceComments(providerId, threads);
}
});
if (this._openPanelListener) {
this._openPanelListener.dispose();
this._openPanelListener = null;
}
}
});
}
}
private getHandler(handle: number) {
if (!this._handlers.has(handle)) {
throw new Error('Unknown handler');
}
return this._handlers.get(handle)!;
}
$registerWorkspaceCommentProvider(handle: number, extensionId: ExtensionIdentifier): void {
this._workspaceProviders.set(handle, undefined);
@@ -143,13 +630,9 @@ export class MainThreadComments extends Disposable implements MainThreadComments
this._handlers.set(handle, providerId);
const commentsPanelAlreadyConstructed = this._panelService.getPanels().some(panel => panel.id === COMMENTS_PANEL_ID);
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescriptor(
CommentsPanel,
COMMENTS_PANEL_ID,
COMMENTS_PANEL_TITLE,
'commentsPanel',
10
));
if (!commentsPanelAlreadyConstructed) {
this.registerPanel(commentsPanelAlreadyConstructed);
}
const openPanel = this._configurationService.getValue<ICommentsConfiguration>('comments').openPanel;
@@ -187,7 +670,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
$unregisterDocumentCommentProvider(handle: number): void {
this._documentProviders.delete(handle);
const handlerId = this._handlers.get(handle);
const handlerId = this.getHandler(handle);
this._commentService.unregisterDataProvider(handlerId);
this._handlers.delete(handle);
}
@@ -203,14 +686,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments
}
}
const handlerId = this._handlers.get(handle);
const handlerId = this.getHandler(handle);
this._commentService.removeWorkspaceComments(handlerId);
this._handlers.delete(handle);
}
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent) {
// notify comment service
const providerId = this._handlers.get(handle);
const providerId = this.getHandler(handle);
this._commentService.updateComments(providerId, event);
}
@@ -234,13 +717,16 @@ export class MainThreadComments extends Disposable implements MainThreadComments
async provideWorkspaceComments(): Promise<modes.CommentThread[]> {
const result: modes.CommentThread[] = [];
for (const handle of keys(this._workspaceProviders)) {
result.push(...await this._proxy.$provideWorkspaceComments(handle));
const result = await this._proxy.$provideWorkspaceComments(handle);
if (Array.isArray(result)) {
result.push(...result);
}
}
return result;
}
async provideDocumentComments(resource: URI): Promise<modes.CommentInfo[]> {
const result: modes.CommentInfo[] = [];
async provideDocumentComments(resource: URI): Promise<Array<modes.CommentInfo | null>> {
const result: Array<modes.CommentInfo | null> = [];
for (const handle of keys(this._documentProviders)) {
result.push(await this._proxy.$provideDocumentComments(handle, resource));
}
@@ -249,6 +735,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
dispose(): void {
this._disposables = dispose(this._disposables);
this._activeCommentThreadDisposables = dispose(this._activeCommentThreadDisposables);
this._workspaceProviders.forEach(value => dispose(value));
this._workspaceProviders.clear();
this._documentProviders.forEach(value => dispose(value));

View File

@@ -8,10 +8,9 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, getScopes } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationModel, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@extHostNamedCustomer(MainContext.MainThreadConfiguration)
@@ -22,7 +21,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
constructor(
extHostContext: IExtHostContext,
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
@IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
) {
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostConfiguration);
@@ -34,7 +33,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
}
private _getConfigurationData(): IConfigurationInitData {
const configurationData: IConfigurationInitData = { ...this.configurationService.getConfigurationData(), configurationScopes: {} };
const configurationData: IConfigurationInitData = { ...(this.configurationService.getConfigurationData()!), configurationScopes: {} };
// Send configurations scopes only in development mode.
if (!this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment) {
configurationData.configurationScopes = getScopes();
@@ -46,22 +45,22 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
this._configurationListener.dispose();
}
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resourceUriComponenets: UriComponents): Promise<void> {
$updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: any, resourceUriComponenets: UriComponents | undefined): Promise<void> {
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
return this.writeConfiguration(target, key, value, resource);
}
$removeConfigurationOption(target: ConfigurationTarget, key: string, resourceUriComponenets: UriComponents): Promise<void> {
$removeConfigurationOption(target: ConfigurationTarget | null, key: string, resourceUriComponenets: UriComponents | undefined): Promise<void> {
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
return this.writeConfiguration(target, key, undefined, resource);
}
private writeConfiguration(target: ConfigurationTarget, key: string, value: any, resource: URI): Promise<void> {
private writeConfiguration(target: ConfigurationTarget | null, key: string, value: any, resource: URI | null): Promise<void> {
target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource);
return this.configurationService.updateValue(key, value, { resource }, target, true);
}
private deriveConfigurationTarget(key: string, resource: URI): ConfigurationTarget {
private deriveConfigurationTarget(key: string, resource: URI | null): ConfigurationTarget {
if (resource && this._workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.RESOURCE) {

View File

@@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IRemoteConsoleLog, log, parse } from 'vs/base/node/console';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService';
import { IBroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
import { EXTENSION_LOG_BROADCAST_CHANNEL } from 'vs/platform/extensions/common/extensionHost';
@extHostNamedCustomer(MainContext.MainThreadConsole)

View File

@@ -8,29 +8,29 @@
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { URI as uri } from 'vs/base/common/uri';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDebugAdapterTrackerFactory } from 'vs/workbench/parts/debug/common/debug';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDebugAdapterTrackerFactory } from 'vs/workbench/contrib/debug/common/debug';
import {
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
} from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import severity from 'vs/base/common/severity';
import { AbstractDebugAdapter } from 'vs/workbench/parts/debug/node/debugAdapter';
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/common/debugUtils';
import { convertToVSCPaths, convertToDAPaths } from 'vs/workbench/contrib/debug/common/debugUtils';
@extHostNamedCustomer(MainContext.MainThreadDebugService)
export class MainThreadDebugService implements MainThreadDebugServiceShape, IDebugAdapterFactory {
private _proxy: ExtHostDebugServiceShape;
private readonly _proxy: ExtHostDebugServiceShape;
private _toDispose: IDisposable[];
private _breakpointEventsActive: boolean;
private _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
private readonly _debugAdapters: Map<number, ExtensionHostDebugAdapter>;
private _debugAdaptersHandleCounter = 1;
private _debugConfigurationProviders: Map<number, IDebugConfigurationProvider>;
private _debugAdapterDescriptorFactories: Map<number, IDebugAdapterDescriptorFactory>;
private _debugAdapterTrackerFactories: Map<number, IDebugAdapterTrackerFactory>;
private _sessions: Set<DebugSessionUUID>;
private readonly _debugConfigurationProviders: Map<number, IDebugConfigurationProvider>;
private readonly _debugAdapterDescriptorFactories: Map<number, IDebugAdapterDescriptorFactory>;
private readonly _debugAdapterTrackerFactories: Map<number, IDebugAdapterTrackerFactory>;
private readonly _sessions: Set<DebugSessionUUID>;
constructor(
extHostContext: IExtHostContext,
@@ -73,7 +73,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return da;
}
substituteVariables(folder: IWorkspaceFolder, config: IConfig): Promise<IConfig> {
substituteVariables(folder: IWorkspaceFolder | undefined, config: IConfig): Promise<IConfig> {
return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config));
}
@@ -144,13 +144,13 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
this.debugService.addFunctionBreakpoint(dto.functionName, dto.id);
}
}
return undefined;
return Promise.resolve();
}
public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Promise<void> {
breakpointIds.forEach(id => this.debugService.removeBreakpoints(id));
functionBreakpointIds.forEach(id => this.debugService.removeFunctionBreakpoints(id));
return undefined;
return Promise.resolve();
}
@@ -161,18 +161,18 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
};
if (hasProvide) {
provider.provideDebugConfigurations = (folder) => {
return Promise.resolve(this._proxy.$provideDebugConfigurations(handle, folder));
return this._proxy.$provideDebugConfigurations(handle, folder);
};
}
if (hasResolve) {
provider.resolveDebugConfiguration = (folder, config) => {
return Promise.resolve(this._proxy.$resolveDebugConfiguration(handle, folder, config));
return this._proxy.$resolveDebugConfiguration(handle, folder, config);
};
}
if (hasProvideDebugAdapter) {
console.info('DebugConfigurationProvider.debugAdapterExecutable is deprecated and will be removed soon; please use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead.');
provider.debugAdapterExecutable = (folder) => {
return Promise.resolve(this._proxy.$legacyDebugAdapterExecutable(handle, folder));
return this._proxy.$legacyDebugAdapterExecutable(handle, folder);
};
}
this._debugConfigurationProviders.set(handle, provider);
@@ -229,10 +229,17 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
}
public $startDebugging(_folderUri: uri | undefined, nameOrConfiguration: string | IConfig): Promise<boolean> {
private getSession(sessionId: DebugSessionUUID | undefined): IDebugSession | undefined {
if (sessionId) {
return this.debugService.getModel().getSessions(true).filter(s => s.getId() === sessionId).pop();
}
return undefined;
}
public $startDebugging(_folderUri: uri | undefined, nameOrConfiguration: string | IConfig, parentSessionID: DebugSessionUUID | undefined): Promise<boolean> {
const folderUri = _folderUri ? uri.revive(_folderUri) : undefined;
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
return this.debugService.startDebugging(launch, nameOrConfiguration).then(success => {
return this.debugService.startDebugging(launch, nameOrConfiguration, false, this.getSession(parentSessionID)).then(success => {
return success;
}, err => {
return Promise.reject(new Error(err && err.message ? err.message : 'cannot start debugging'));
@@ -262,26 +269,44 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) {
this._debugAdapters.get(handle).acceptMessage(convertToVSCPaths(message, false));
this.getDebugAdapter(handle).acceptMessage(convertToVSCPaths(message, false));
}
public $acceptDAError(handle: number, name: string, message: string, stack: string) {
this._debugAdapters.get(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`));
this.getDebugAdapter(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`));
}
public $acceptDAExit(handle: number, code: number, signal: string) {
this._debugAdapters.get(handle).fireExit(handle, code, signal);
this.getDebugAdapter(handle).fireExit(handle, code, signal);
}
private getDebugAdapter(handle: number): ExtensionHostDebugAdapter {
const adapter = this._debugAdapters.get(handle);
if (!adapter) {
throw new Error('Invalid debug adapter');
}
return adapter;
}
// dto helpers
getSessionDto(session: IDebugSession): IDebugSessionDto {
public $sessionCached(sessionID: string) {
// remember that the EH has cached the session and we do not have to send it again
this._sessions.add(sessionID);
}
getSessionDto(session: undefined): undefined;
getSessionDto(session: IDebugSession): IDebugSessionDto;
getSessionDto(session: IDebugSession | undefined): IDebugSessionDto | undefined;
getSessionDto(session: IDebugSession | undefined): IDebugSessionDto | undefined {
if (session) {
const sessionID = <DebugSessionUUID>session.getId();
if (this._sessions.has(sessionID)) {
return sessionID;
} else {
this._sessions.add(sessionID);
// this._sessions.add(sessionID); // #69534: see $sessionCached above
return {
id: sessionID,
type: session.configuration.type,
@@ -333,7 +358,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
/*
class ExtensionHostDebugAdapter extends AbstractDebugAdapter {
constructor(private _ds: MainThreadDebugService, private _handle: number, private _proxy: ExtHostDebugServiceShape, private _session: IDebugSession) {
constructor(private readonly _ds: MainThreadDebugService, private _handle: number, private _proxy: ExtHostDebugServiceShape, private _session: IDebugSession) {
super();
}

View File

@@ -21,7 +21,7 @@ class DecorationRequestsQueue {
private _timer: any;
constructor(
private _proxy: ExtHostDecorationsShape
private readonly _proxy: ExtHostDecorationsShape
) {
//
}
@@ -109,13 +109,17 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
}
$onDidChange(handle: number, resources: UriComponents[]): void {
const [emitter] = this._provider.get(handle);
emitter.fire(resources && resources.map(URI.revive));
const provider = this._provider.get(handle);
if (provider) {
const [emitter] = provider;
emitter.fire(resources && resources.map(URI.revive));
}
}
$unregisterDecorationProvider(handle: number): void {
if (this._provider.has(handle)) {
dispose(this._provider.get(handle));
const provider = this._provider.get(handle);
if (provider) {
dispose(provider);
this._provider.delete(handle);
}
}

View File

@@ -22,7 +22,7 @@ export class MainThreadDiagnostics implements MainThreadDiagnosticsShape {
}
dispose(): void {
this._activeOwners.forEach(owner => this._markerService.changeAll(owner, undefined));
this._activeOwners.forEach(owner => this._markerService.changeAll(owner, []));
}
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
@@ -43,7 +43,7 @@ export class MainThreadDiagnostics implements MainThreadDiagnosticsShape {
}
$clear(owner: string): void {
this._markerService.changeAll(owner, undefined);
this._markerService.changeAll(owner, []);
this._activeOwners.delete(owner);
}
}

View File

@@ -23,11 +23,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
//
}
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<URI[]> {
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<URI[] | undefined> {
return Promise.resolve(this._fileDialogService.showOpenDialog(MainThreadDialogs._convertOpenOptions(options)));
}
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<URI> {
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<URI | undefined> {
return Promise.resolve(this._fileDialogService.showSaveDialog(MainThreadDialogs._convertSaveOptions(options)));
}
@@ -41,7 +41,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
};
if (options.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value }));
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
}
return result;
}
@@ -53,7 +53,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
};
if (options.filters) {
result.filters = [];
forEach(options.filters, entry => result.filters.push({ name: entry.key, extensions: entry.value }));
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
}
return result;
}

View File

@@ -41,7 +41,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
$registerTextContentProvider(handle: number, scheme: string): void {
const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, {
provideTextContent: (uri: URI): Promise<ITextModel> => {
provideTextContent: (uri: URI): Promise<ITextModel | undefined> => {
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
if (typeof value === 'string') {
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
@@ -70,8 +70,9 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
}
// cancel and dispose an existing update
if (this._pendingUpdate.has(model.id)) {
this._pendingUpdate.get(model.id).cancel();
const pending = this._pendingUpdate.get(model.id);
if (pending) {
pending.cancel();
}
// create and keep update token
@@ -86,7 +87,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
// ignore this
return;
}
if (edits.length > 0) {
if (edits && edits.length > 0) {
// use the evil-edit as these models show in readonly-editor only
model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
}

View File

@@ -24,8 +24,8 @@ export class BoundModelReferenceCollection {
private _length = 0;
constructor(
private _maxAge: number = 1000 * 60 * 3,
private _maxLength: number = 1024 * 1024 * 80
private readonly _maxAge: number = 1000 * 60 * 3,
private readonly _maxLength: number = 1024 * 1024 * 80
) {
//
}
@@ -35,11 +35,11 @@ export class BoundModelReferenceCollection {
}
add(ref: IReference<ITextEditorModel>): void {
let length = ref.object.textEditorModel.getValueLength();
const length = ref.object.textEditorModel.getValueLength();
let handle: any;
let entry: { length: number, dispose(): void };
const dispose = () => {
let idx = this._data.indexOf(entry);
const idx = this._data.indexOf(entry);
if (idx >= 0) {
this._length -= length;
ref.dispose();
@@ -64,16 +64,16 @@ export class BoundModelReferenceCollection {
export class MainThreadDocuments implements MainThreadDocumentsShape {
private _modelService: IModelService;
private _textModelResolverService: ITextModelService;
private _textFileService: ITextFileService;
private _fileService: IFileService;
private _untitledEditorService: IUntitledEditorService;
private readonly _modelService: IModelService;
private readonly _textModelResolverService: ITextModelService;
private readonly _textFileService: ITextFileService;
private readonly _fileService: IFileService;
private readonly _untitledEditorService: IUntitledEditorService;
private _toDispose: IDisposable[];
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
private _proxy: ExtHostDocumentsShape;
private _modelIsSynced: { [modelId: string]: boolean; };
private readonly _proxy: ExtHostDocumentsShape;
private readonly _modelIsSynced: { [modelId: string]: boolean; };
private _modelReferenceCollection = new BoundModelReferenceCollection();
constructor(
@@ -130,16 +130,16 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean {
const model = this._modelService.getModel(e.resource);
return model && shouldSynchronizeModel(model);
return !!model && shouldSynchronizeModel(model);
}
private _onModelAdded(model: ITextModel): void {
// Same filter as in mainThreadEditorsTracker
if (!shouldSynchronizeModel(model)) {
// don't synchronize too large models
return null;
return;
}
let modelUrl = model.uri;
const modelUrl = model.uri;
this._modelIsSynced[modelUrl.toString()] = true;
this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => {
this._proxy.$acceptModelChanged(modelUrl, e, this._textFileService.isDirty(modelUrl));
@@ -148,7 +148,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void {
let { model, oldModeId } = event;
let modelUrl = model.uri;
const modelUrl = model.uri;
if (!this._modelIsSynced[modelUrl.toString()]) {
return;
}
@@ -156,7 +156,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
}
private _onModelRemoved(modelUrl: URI): void {
let strModelUrl = modelUrl.toString();
const strModelUrl = modelUrl.toString();
if (!this._modelIsSynced[strModelUrl]) {
return;
}
@@ -214,7 +214,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
}
private _handleUntitledScheme(uri: URI): Promise<boolean> {
let asFileUri = uri.with({ scheme: Schemas.file });
const asFileUri = uri.with({ scheme: Schemas.file });
return this._fileService.resolveFile(asFileUri).then(stats => {
// don't create a new file ontop of an existing file
return Promise.reject(new Error('file already exists on disk'));

View File

@@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, isCodeEditor, isDiffEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IEditor } from 'vs/editor/common/editorCommon';
@@ -25,7 +25,7 @@ import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/shar
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { IEditor as IWorkbenchEditor } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
@@ -70,7 +70,7 @@ class TextEditorSnapshot {
readonly id: string;
constructor(
readonly editor: ICodeEditor,
readonly editor: IActiveCodeEditor,
) {
this.id = `${editor.getId()},${editor.getModel().id}`;
}
@@ -85,8 +85,8 @@ class DocumentAndEditorStateDelta {
readonly addedDocuments: ITextModel[],
readonly removedEditors: TextEditorSnapshot[],
readonly addedEditors: TextEditorSnapshot[],
readonly oldActiveEditor: string,
readonly newActiveEditor: string,
readonly oldActiveEditor: string | null | undefined,
readonly newActiveEditor: string | null | undefined,
) {
this.isEmpty = this.removedDocuments.length === 0
&& this.addedDocuments.length === 0
@@ -131,7 +131,7 @@ class DocumentAndEditorState {
constructor(
readonly documents: Set<ITextModel>,
readonly textEditors: Map<string, TextEditorSnapshot>,
readonly activeEditor: string,
readonly activeEditor: string | null | undefined,
) {
//
}
@@ -230,14 +230,14 @@ class MainThreadDocumentAndEditorStateComputer {
// editor: only take those that have a not too large model
const editors = new Map<string, TextEditorSnapshot>();
let activeEditor: string | null = null;
let activeEditor: string | null = null; // Strict null work. This doesn't like being undefined!
for (const editor of this._codeEditorService.listCodeEditors()) {
if (editor.isSimpleWidget) {
continue;
}
const model = editor.getModel();
if (model && shouldSynchronizeModel(model)
if (editor.hasModel() && model && shouldSynchronizeModel(model)
&& !model.isDisposed() // model disposed
&& Boolean(this._modelService.getModel(model.uri)) // model disposing, the flag didn't flip yet but the model service already removed it
) {
@@ -257,7 +257,7 @@ class MainThreadDocumentAndEditorStateComputer {
// to match output panels or the active workbench editor with
// one of editor we have just computed
if (!activeEditor) {
let candidate: IEditor;
let candidate: IEditor | undefined;
if (this._activeEditorOrder === ActiveEditorOrder.Editor) {
candidate = this._getActiveEditorFromEditorPart() || this._getActiveEditorFromPanel();
} else {
@@ -282,8 +282,8 @@ class MainThreadDocumentAndEditorStateComputer {
}
}
private _getActiveEditorFromPanel(): IEditor {
let panel = this._panelService.getActivePanel();
private _getActiveEditorFromPanel(): IEditor | undefined {
const panel = this._panelService.getActivePanel();
if (panel instanceof BaseTextEditor && isCodeEditor(panel.getControl())) {
return panel.getControl();
} else {
@@ -291,7 +291,7 @@ class MainThreadDocumentAndEditorStateComputer {
}
}
private _getActiveEditorFromEditorPart(): IEditor {
private _getActiveEditorFromEditorPart(): IEditor | undefined {
let result = this._editorService.activeTextEditorWidget;
if (isDiffEditor(result)) {
result = result.getModifiedEditor();
@@ -304,8 +304,8 @@ class MainThreadDocumentAndEditorStateComputer {
export class MainThreadDocumentsAndEditors {
private _toDispose: IDisposable[];
private _proxy: ExtHostDocumentsAndEditorsShape;
private _stateComputer: MainThreadDocumentAndEditorStateComputer;
private readonly _proxy: ExtHostDocumentsAndEditorsShape;
private readonly _stateComputer: MainThreadDocumentAndEditorStateComputer;
private _textEditors = <{ [id: string]: MainThreadTextEditor }>Object.create(null);
private _onTextEditorAdd = new Emitter<MainThreadTextEditor[]>();
@@ -362,8 +362,8 @@ export class MainThreadDocumentsAndEditors {
private _onDelta(delta: DocumentAndEditorStateDelta): void {
let removedDocuments: URI[];
let removedEditors: string[] = [];
let addedEditors: MainThreadTextEditor[] = [];
const removedEditors: string[] = [];
const addedEditors: MainThreadTextEditor[] = [];
// removed models
removedDocuments = delta.removedDocuments.map(m => m.uri);
@@ -387,7 +387,7 @@ export class MainThreadDocumentsAndEditors {
}
}
let extHostDelta: IDocumentsAndEditorsDelta = Object.create(null);
const extHostDelta: IDocumentsAndEditorsDelta = Object.create(null);
let empty = true;
if (delta.newActiveEditor !== undefined) {
empty = false;
@@ -444,8 +444,8 @@ export class MainThreadDocumentsAndEditors {
};
}
private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn {
for (let workbenchEditor of this._editorService.visibleControls) {
private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn | undefined {
for (const workbenchEditor of this._editorService.visibleControls) {
if (editor.matches(workbenchEditor)) {
return editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
}
@@ -453,8 +453,8 @@ export class MainThreadDocumentsAndEditors {
return undefined;
}
findTextEditorIdFor(editor: IWorkbenchEditor): string {
for (let id in this._textEditors) {
findTextEditorIdFor(editor: IWorkbenchEditor): string | undefined {
for (const id in this._textEditors) {
if (this._textEditors[id].matches(editor)) {
return id;
}

View File

@@ -16,6 +16,7 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2
import { IApplyEditsOptions, IEditorPropertiesChangeData, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, IUndoStopOptions, TextEditorRevealType } from 'vs/workbench/api/node/extHost.protocol';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { IEditor } from 'vs/workbench/common/editor';
import { withNullAsUndefined } from 'vs/base/common/types';
export interface IFocusTracker {
onGainedFocus(): void;
@@ -24,14 +25,14 @@ export interface IFocusTracker {
export class MainThreadTextEditorProperties {
public static readFromEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): MainThreadTextEditorProperties {
public static readFromEditor(previousProperties: MainThreadTextEditorProperties | null, model: ITextModel, codeEditor: ICodeEditor | null): MainThreadTextEditorProperties {
const selections = MainThreadTextEditorProperties._readSelectionsFromCodeEditor(previousProperties, codeEditor);
const options = MainThreadTextEditorProperties._readOptionsFromCodeEditor(previousProperties, model, codeEditor);
const visibleRanges = MainThreadTextEditorProperties._readVisibleRangesFromCodeEditor(previousProperties, codeEditor);
return new MainThreadTextEditorProperties(selections, options, visibleRanges);
}
private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Selection[] {
private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, codeEditor: ICodeEditor | null): Selection[] {
let result: Selection[] | null = null;
if (codeEditor) {
result = codeEditor.getSelections();
@@ -45,10 +46,14 @@ export class MainThreadTextEditorProperties {
return result;
}
private static _readOptionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): IResolvedTextEditorConfiguration {
private static _readOptionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, model: ITextModel, codeEditor: ICodeEditor | null): IResolvedTextEditorConfiguration {
if (model.isDisposed()) {
// shutdown time
return previousProperties.options;
if (previousProperties) {
// shutdown time
return previousProperties.options;
} else {
throw new Error('No valid properties');
}
}
let cursorStyle: TextEditorCursorStyle;
@@ -80,12 +85,13 @@ export class MainThreadTextEditorProperties {
return {
insertSpaces: modelOptions.insertSpaces,
tabSize: modelOptions.tabSize,
indentSize: modelOptions.indentSize,
cursorStyle: cursorStyle,
lineNumbers: lineNumbers
};
}
private static _readVisibleRangesFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Range[] {
private static _readVisibleRangesFromCodeEditor(previousProperties: MainThreadTextEditorProperties | null, codeEditor: ICodeEditor | null): Range[] {
if (codeEditor) {
return codeEditor.getVisibleRanges();
}
@@ -99,8 +105,8 @@ export class MainThreadTextEditorProperties {
) {
}
public generateDelta(oldProps: MainThreadTextEditorProperties, selectionChangeSource: string): IEditorPropertiesChangeData {
let delta: IEditorPropertiesChangeData = {
public generateDelta(oldProps: MainThreadTextEditorProperties | null, selectionChangeSource: string | null): IEditorPropertiesChangeData | null {
const delta: IEditorPropertiesChangeData = {
options: null,
selections: null,
visibleRanges: null
@@ -109,7 +115,7 @@ export class MainThreadTextEditorProperties {
if (!oldProps || !MainThreadTextEditorProperties._selectionsEqual(oldProps.selections, this.selections)) {
delta.selections = {
selections: this.selections,
source: selectionChangeSource
source: withNullAsUndefined(selectionChangeSource)
};
}
@@ -162,6 +168,7 @@ export class MainThreadTextEditorProperties {
}
return (
a.tabSize === b.tabSize
&& a.indentSize === b.indentSize
&& a.insertSpaces === b.insertSpaces
&& a.cursorStyle === b.cursorStyle
&& a.lineNumbers === b.lineNumbers
@@ -175,12 +182,12 @@ export class MainThreadTextEditorProperties {
*/
export class MainThreadTextEditor {
private _id: string;
private readonly _id: string;
private _model: ITextModel;
private _modelService: IModelService;
private readonly _modelService: IModelService;
private _modelListeners: IDisposable[];
private _codeEditor: ICodeEditor;
private _focusTracker: IFocusTracker;
private _codeEditor: ICodeEditor | null;
private readonly _focusTracker: IFocusTracker;
private _codeEditorListeners: IDisposable[];
private _properties: MainThreadTextEditorProperties;
@@ -200,7 +207,6 @@ export class MainThreadTextEditor {
this._modelService = modelService;
this._codeEditorListeners = [];
this._properties = null;
this._onPropertiesChanged = new Emitter<IEditorPropertiesChangeData>();
this._modelListeners = [];
@@ -213,20 +219,20 @@ export class MainThreadTextEditor {
}
public dispose(): void {
this._model = null;
this._model = null!;
this._modelListeners = dispose(this._modelListeners);
this._codeEditor = null;
this._codeEditorListeners = dispose(this._codeEditorListeners);
}
private _updatePropertiesNow(selectionChangeSource: string): void {
private _updatePropertiesNow(selectionChangeSource: string | null): void {
this._setProperties(
MainThreadTextEditorProperties.readFromEditor(this._properties, this._model, this._codeEditor),
selectionChangeSource
);
}
private _setProperties(newProperties: MainThreadTextEditorProperties, selectionChangeSource: string): void {
private _setProperties(newProperties: MainThreadTextEditorProperties, selectionChangeSource: string | null): void {
const delta = newProperties.generateDelta(this._properties, selectionChangeSource);
this._properties = newProperties;
if (delta) {
@@ -242,15 +248,15 @@ export class MainThreadTextEditor {
return this._model;
}
public getCodeEditor(): ICodeEditor {
public getCodeEditor(): ICodeEditor | null {
return this._codeEditor;
}
public hasCodeEditor(codeEditor: ICodeEditor): boolean {
public hasCodeEditor(codeEditor: ICodeEditor | null): boolean {
return (this._codeEditor === codeEditor);
}
public setCodeEditor(codeEditor: ICodeEditor): void {
public setCodeEditor(codeEditor: ICodeEditor | null): void {
if (this.hasCodeEditor(codeEditor)) {
// Nothing to do...
return;
@@ -318,10 +324,10 @@ export class MainThreadTextEditor {
}
private _setIndentConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
const creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language, this._model.uri, this._model.isForSimpleWidget);
if (newConfiguration.tabSize === 'auto' || newConfiguration.insertSpaces === 'auto') {
// one of the options was set to 'auto' => detect indentation
let creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language, this._model.uri, this._model.isForSimpleWidget);
let insertSpaces = creationOpts.insertSpaces;
let tabSize = creationOpts.tabSize;
@@ -337,13 +343,20 @@ export class MainThreadTextEditor {
return;
}
let newOpts: ITextModelUpdateOptions = {};
const newOpts: ITextModelUpdateOptions = {};
if (typeof newConfiguration.insertSpaces !== 'undefined') {
newOpts.insertSpaces = newConfiguration.insertSpaces;
}
if (typeof newConfiguration.tabSize !== 'undefined') {
newOpts.tabSize = newConfiguration.tabSize;
}
if (typeof newConfiguration.indentSize !== 'undefined') {
if (newConfiguration.indentSize === 'tabSize') {
newOpts.indentSize = newOpts.tabSize || creationOpts.tabSize;
} else {
newOpts.indentSize = newConfiguration.indentSize;
}
}
this._model.updateOptions(newOpts);
}
@@ -355,7 +368,7 @@ export class MainThreadTextEditor {
}
if (newConfiguration.cursorStyle) {
let newCursorStyle = cursorStyleToString(newConfiguration.cursorStyle);
const newCursorStyle = cursorStyleToString(newConfiguration.cursorStyle);
this._codeEditor.updateOptions({
cursorStyle: newCursorStyle
});
@@ -390,7 +403,7 @@ export class MainThreadTextEditor {
if (!this._codeEditor) {
return;
}
let ranges: Range[] = [];
const ranges: Range[] = [];
for (let i = 0, len = Math.floor(_ranges.length / 4); i < len; i++) {
ranges[i] = new Range(_ranges[4 * i], _ranges[4 * i + 1], _ranges[4 * i + 2], _ranges[4 * i + 3]);
}
@@ -452,7 +465,7 @@ export class MainThreadTextEditor {
this._model.pushEOL(EndOfLineSequence.LF);
}
let transformedEdits = edits.map((edit): IIdentifiedSingleEditOperation => {
const transformedEdits = edits.map((edit): IIdentifiedSingleEditOperation => {
return {
range: Range.lift(edit.range),
text: edit.text,

View File

@@ -23,20 +23,20 @@ import { MainThreadTextEditor } from 'vs/workbench/api/electron-browser/mainThre
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/shared/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IURLService } from 'vs/platform/url/common/url';
import product from 'vs/platform/node/product';
import product from 'vs/platform/product/node/product';
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
private static INSTANCE_COUNT: number = 0;
private _instanceId: string;
private _proxy: ExtHostEditorsShape;
private _documentsAndEditors: MainThreadDocumentsAndEditors;
private readonly _instanceId: string;
private readonly _proxy: ExtHostEditorsShape;
private readonly _documentsAndEditors: MainThreadDocumentsAndEditors;
private _toDispose: IDisposable[];
private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
private _editorPositionData: ITextEditorPositionData;
private _editorPositionData: ITextEditorPositionData | null;
private _registeredDecorationTypes: { [decorationType: string]: boolean; };
constructor(
@@ -77,8 +77,8 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
let id = textEditor.getId();
let toDispose: IDisposable[] = [];
const id = textEditor.getId();
const toDispose: IDisposable[] = [];
toDispose.push(textEditor.onPropertiesChanged((data) => {
this._proxy.$acceptEditorPropertiesChanged(id, data);
}));
@@ -94,7 +94,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
private _updateActiveAndVisibleTextEditors(): void {
// editor columns
let editorPositionData = this._getTextEditorPositionData();
const editorPositionData = this._getTextEditorPositionData();
if (!objectEquals(this._editorPositionData, editorPositionData)) {
this._editorPositionData = editorPositionData;
this._proxy.$acceptEditorPositionData(this._editorPositionData);
@@ -102,7 +102,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
private _getTextEditorPositionData(): ITextEditorPositionData {
let result: ITextEditorPositionData = Object.create(null);
const result: ITextEditorPositionData = Object.create(null);
for (let workbenchEditor of this._editorService.visibleControls) {
const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
if (id) {
@@ -114,7 +114,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// --- from extension host process
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string> {
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined> {
const uri = URI.revive(resource);
const editorOptions: ITextEditorOptions = {
@@ -137,28 +137,28 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
$tryShowEditor(id: string, position?: EditorViewColumn): Promise<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let model = mainThreadEditor.getModel();
const model = mainThreadEditor.getModel();
return this._editorService.openEditor({
resource: model.uri,
options: { preserveFocus: false }
}, viewColumnToEditorGroup(this._editorGroupService, position)).then(() => { return; });
}
return undefined;
return Promise.resolve();
}
$tryHideEditor(id: string): Promise<void> {
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let editors = this._editorService.visibleControls;
const editors = this._editorService.visibleControls;
for (let editor of editors) {
if (mainThreadEditor.matches(editor)) {
return editor.group.closeEditor(editor.input).then(() => { return; });
}
}
}
return undefined;
return Promise.resolve();
}
$trySetSelections(id: string, selections: ISelection[]): Promise<void> {
@@ -192,7 +192,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return Promise.reject(disposed(`TextEditor(${id})`));
}
this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
return undefined;
return Promise.resolve();
}
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise<void> {
@@ -242,12 +242,16 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
}
const codeEditor = editor.getCodeEditor();
if (!codeEditor) {
return Promise.reject(new Error('No such CodeEditor'));
}
const codeEditorId = codeEditor.getId();
const diffEditors = this._codeEditorService.listDiffEditors();
const [diffEditor] = diffEditors.filter(d => d.getOriginalEditor().getId() === codeEditorId || d.getModifiedEditor().getId() === codeEditorId);
if (diffEditor) {
return Promise.resolve(diffEditor.getLineChanges());
return Promise.resolve(diffEditor.getLineChanges() || []);
}
const dirtyDiffContribution = codeEditor.getContribution('editor.contrib.dirtydiff');

View File

@@ -7,29 +7,45 @@ import { SerializedError } from 'vs/base/common/errors';
import Severity from 'vs/base/common/severity';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IExtHostContext, MainContext, MainThreadExtensionServiceShape } from 'vs/workbench/api/node/extHost.protocol';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionService, ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadExtensionService)
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {
private readonly _extensionService: ExtensionService;
private readonly _notificationService: INotificationService;
private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService;
private readonly _windowService: IWindowService;
constructor(
extHostContext: IExtHostContext,
@IExtensionService extensionService: IExtensionService
@IExtensionService extensionService: IExtensionService,
@INotificationService notificationService: INotificationService,
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
@IWindowService windowService: IWindowService
) {
if (extensionService instanceof ExtensionService) {
this._extensionService = extensionService;
}
this._notificationService = notificationService;
this._extensionsWorkbenchService = extensionsWorkbenchService;
this._windowService = windowService;
}
public dispose(): void {
}
$localShowMessage(severity: Severity, msg: string): void {
this._extensionService._logOrShowMessage(severity, msg);
$activateExtension(extensionId: ExtensionIdentifier, activationEvent: string): Promise<void> {
return this._extensionService._activateById(extensionId, activationEvent);
}
$onWillActivateExtension(extensionId: ExtensionIdentifier): void {
this._extensionService._onWillActivateExtension(extensionId);
@@ -46,9 +62,66 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
console.error(`[${extensionId}]${error.message}`);
console.error(error.stack);
}
$onExtensionActivationFailed(extensionId: ExtensionIdentifier): void {
async $onExtensionActivationError(extensionId: ExtensionIdentifier, activationError: ExtensionActivationError): Promise<void> {
if (typeof activationError === 'string') {
this._extensionService._logOrShowMessage(Severity.Error, activationError);
} else {
this._handleMissingDependency(extensionId, activationError.dependency);
}
}
$addMessage(extensionId: ExtensionIdentifier, severity: Severity, message: string): void {
this._extensionService._addMessage(extensionId, severity, message);
private async _handleMissingDependency(extensionId: ExtensionIdentifier, missingDependency: string): Promise<void> {
const extension = await this._extensionService.getExtension(extensionId.value);
if (extension) {
const local = await this._extensionsWorkbenchService.queryLocal();
const installedDependency = local.filter(i => areSameExtensions(i.identifier, { id: missingDependency }))[0];
if (installedDependency) {
await this._handleMissingInstalledDependency(extension, installedDependency);
} else {
await this._handleMissingNotInstalledDependency(extension, missingDependency);
}
}
}
private async _handleMissingInstalledDependency(extension: IExtensionDescription, missingInstalledDependency: IExtension): Promise<void> {
const extName = extension.displayName || extension.name;
if (missingInstalledDependency.enablementState === EnablementState.Enabled || missingInstalledDependency.enablementState === EnablementState.WorkspaceEnabled) {
this._notificationService.notify({
severity: Severity.Error,
message: localize('reload window', "Cannot activate extension '{0}' because it depends on extension '{1}', which is not loaded. Would you like to reload the window to load the extension?", extName, missingInstalledDependency.displayName),
actions: {
primary: [new Action('reload', localize('reload', "Reload Window"), '', true, () => this._windowService.reloadWindow())]
}
});
} else {
this._notificationService.notify({
severity: Severity.Error,
message: localize('disabledDep', "Cannot activate extension '{0}' because it depends on extension '{1}', which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.displayName),
actions: {
primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true,
() => this._extensionsWorkbenchService.setEnablement([missingInstalledDependency], missingInstalledDependency.enablementState === EnablementState.Disabled ? EnablementState.Enabled : EnablementState.WorkspaceEnabled)
.then(() => this._windowService.reloadWindow(), e => this._notificationService.error(e)))]
}
});
}
}
private async _handleMissingNotInstalledDependency(extension: IExtensionDescription, missingDependency: string): Promise<void> {
const extName = extension.displayName || extension.name;
const dependencyExtension = (await this._extensionsWorkbenchService.queryGallery({ names: [missingDependency] })).firstPage[0];
if (dependencyExtension) {
this._notificationService.notify({
severity: Severity.Error,
message: localize('uninstalledDep', "Cannot activate extension '{0}' because it depends on extension '{1}', which is not installed. Would you like to install the extension and reload the window?", extName, dependencyExtension.displayName),
actions: {
primary: [new Action('install', localize('install missing dep', "Install and Reload"), '', true,
() => this._extensionsWorkbenchService.install(dependencyExtension)
.then(() => this._windowService.reloadWindow(), e => this._notificationService.error(e)))]
}
});
} else {
this._notificationService.error(localize('unknownDep', "Cannot activate extension '{0}' because it depends on an unknown extension '{1}'.", extName, missingDependency));
}
}
}

View File

@@ -16,6 +16,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
private readonly _proxy: ExtHostFileSystemShape;
private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
private readonly _resourceLabelFormatters = new Map<number, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@@ -39,12 +40,24 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
this._fileProvider.delete(handle);
}
$setUriFormatter(formatter: ResourceLabelFormatter): void {
this._labelService.registerFormatter(formatter);
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void {
// Dynamicily registered formatters should have priority over those contributed via package.json
formatter.priority = true;
const disposable = this._labelService.registerFormatter(formatter);
this._resourceLabelFormatters.set(handle, disposable);
}
$unregisterResourceLabelFormatter(handle: number): void {
dispose(this._resourceLabelFormatters.get(handle));
this._resourceLabelFormatters.delete(handle);
}
$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
this._fileProvider.get(handle).$onFileSystemChange(changes);
const fileProvider = this._fileProvider.get(handle);
if (!fileProvider) {
throw new Error('Unknown file provider');
}
fileProvider.$onFileSystemChange(changes);
}
}

View File

@@ -52,12 +52,12 @@ export class MainThreadFileSystemEventService {
// file operation events - (changes the editor makes)
fileService.onAfterOperation(e => {
if (e.operation === FileOperation.MOVE) {
proxy.$onFileRename(e.resource, e.target.resource);
proxy.$onFileRename(e.resource, e.target!.resource);
}
}, undefined, this._listener);
textfileService.onWillMove(e => {
let promise = proxy.$onWillRename(e.oldResource, e.newResource);
const promise = proxy.$onWillRename(e.oldResource, e.newResource);
e.waitUntil(promise);
}, undefined, this._listener);
}

View File

@@ -9,8 +9,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { isThenable } from 'vs/base/common/async';
import { isNullOrUndefined } from 'util';
import { GCSignal } from 'gc-signals';
export const IHeapService = createDecorator<IHeapService>('heapService');
@@ -20,10 +19,9 @@ export interface IHeapService {
readonly onGarbageCollection: Event<number[]>;
/**
* Track gc-collection for all new objects that
* have the $ident-value set.
* Track gc-collection for the given object
*/
trackRecursive<T>(obj: T | Promise<T>): Promise<T>;
trackObject(obj: ObjectIdentifier | undefined): void;
}
export class HeapService implements IHeapService {
@@ -35,7 +33,10 @@ export class HeapService implements IHeapService {
private _activeSignals = new WeakMap<any, object>();
private _activeIds = new Set<number>();
private _consumeHandle: any;
private _ctor: { new(id: number): GCSignal };
private _ctorInit: Promise<void>;
constructor() {
//
@@ -45,80 +46,57 @@ export class HeapService implements IHeapService {
clearInterval(this._consumeHandle);
}
trackRecursive<T>(obj: T | Promise<T>): Promise<T> {
if (isThenable(obj)) {
return obj.then(result => this.trackRecursive(result));
trackObject(obj: ObjectIdentifier | undefined | null): void {
if (!obj) {
return;
}
const ident = obj.$ident;
if (typeof ident !== 'number') {
return;
}
if (this._activeIds.has(ident)) {
return;
}
if (this._ctor) {
// track and leave
this._activeIds.add(ident);
this._activeSignals.set(obj, new this._ctor(ident));
} else {
return this._doTrackRecursive(obj);
}
}
// make sure to load gc-signals, then track and leave
if (!this._ctorInit) {
this._ctorInit = import('gc-signals').then(({ GCSignal, consumeSignals }) => {
this._ctor = GCSignal;
this._consumeHandle = setInterval(() => {
const ids = consumeSignals();
private _doTrackRecursive(obj: any): Promise<any> {
if (isNullOrUndefined(obj)) {
return Promise.resolve(obj);
}
return import('gc-signals').then(({ GCSignal, consumeSignals }) => {
if (this._consumeHandle === undefined) {
// ensure that there is one consumer of signals
this._consumeHandle = setInterval(() => {
const ids = consumeSignals();
if (ids.length > 0) {
// local book-keeping
for (const id of ids) {
this._activeIds.delete(id);
if (ids.length > 0) {
// local book-keeping
for (const id of ids) {
this._activeIds.delete(id);
}
// fire event
this._onGarbageCollection.fire(ids);
}
// fire event
this._onGarbageCollection.fire(ids);
}
}, 15 * 1000);
}, 15 * 1000);
});
}
const stack = [obj];
while (stack.length > 0) {
// remove first element
let obj = stack.shift();
if (!obj || typeof obj !== 'object') {
continue;
}
for (let key in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
continue;
}
const value = obj[key];
// recurse -> object/array
if (typeof value === 'object') {
stack.push(value);
} else if (key === ObjectIdentifier.name) {
// track new $ident-objects
if (typeof value === 'number' && !this._activeIds.has(value)) {
this._activeIds.add(value);
this._activeSignals.set(obj, new GCSignal(value));
}
}
}
}
return obj;
});
this._ctorInit.then(() => {
this._activeIds.add(ident);
this._activeSignals.set(obj, new this._ctor(ident));
});
}
}
}
@extHostCustomer
export class MainThreadHeapService {
private _toDispose: IDisposable;
private readonly _toDispose: IDisposable;
constructor(
extHostContext: IExtHostContext,

View File

@@ -7,11 +7,11 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/parts/search/common/search';
import * as search from 'vs/workbench/contrib/search/common/search';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata } from '../node/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto, LinkDto } from '../node/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService';
@@ -20,14 +20,16 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
private _proxy: ExtHostLanguageFeaturesShape;
private _heapService: IHeapService;
private _modeService: IModeService;
private _registrations: { [handle: number]: IDisposable; } = Object.create(null);
private readonly _proxy: ExtHostLanguageFeaturesShape;
private readonly _heapService: IHeapService;
private readonly _modeService: IModeService;
private readonly _registrations: { [handle: number]: IDisposable; } = Object.create(null);
constructor(
extHostContext: IExtHostContext,
@@ -46,7 +48,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
$unregister(handle: number): void {
let registration = this._registrations[handle];
const registration = this._registrations[handle];
if (registration) {
registration.dispose();
delete this._registrations[handle];
@@ -85,9 +87,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto): search.IWorkspaceSymbol;
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto[]): search.IWorkspaceSymbol[];
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[]): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] {
private static _reviveWorkspaceSymbolDto(data: undefined): undefined;
private static _reviveWorkspaceSymbolDto(data: WorkspaceSymbolDto | WorkspaceSymbolDto[] | undefined): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] | undefined {
if (!data) {
return <search.IWorkspaceSymbol>data;
return <undefined>data;
} else if (Array.isArray(data)) {
data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto);
return <search.IWorkspaceSymbol[]>data;
@@ -97,13 +100,20 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
private static _reviveCodeActionDto(data: CodeActionDto[]): modes.CodeAction[] {
private static _reviveCodeActionDto(data: CodeActionDto[] | undefined): modes.CodeAction[] {
if (data) {
data.forEach(code => reviveWorkspaceEditDto(code.edit));
}
return <modes.CodeAction[]>data;
}
private static _reviveLinkDTO(data: LinkDto): modes.ILink {
if (data.url && typeof data.url !== 'string') {
data.url = URI.revive(data.url);
}
return <modes.ILink>data;
}
//#endregion
// --- outline
@@ -111,7 +121,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentSymbolProvider>{
displayName,
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<modes.DocumentSymbol[]> => {
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined> => {
return this._proxy.$provideDocumentSymbols(handle, model.uri, token);
}
});
@@ -119,14 +129,28 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- code lens
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void {
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void {
const provider = <modes.CodeLensProvider>{
provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Promise<modes.ICodeLensSymbol[]> => {
return this._heapService.trackRecursive(this._proxy.$provideCodeLenses(handle, model.uri, token));
return this._proxy.$provideCodeLenses(handle, model.uri, token).then(dto => {
if (dto) {
dto.forEach(obj => {
this._heapService.trackObject(obj);
this._heapService.trackObject(obj.command);
});
}
return dto;
});
},
resolveCodeLens: (model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Promise<modes.ICodeLensSymbol> => {
return this._heapService.trackRecursive(this._proxy.$resolveCodeLens(handle, model.uri, codeLens, token));
resolveCodeLens: (model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): Promise<modes.ICodeLensSymbol | undefined> => {
return this._proxy.$resolveCodeLens(handle, model.uri, codeLens, token).then(obj => {
if (obj) {
this._heapService.trackObject(obj);
this._heapService.trackObject(obj.command);
}
return obj;
});
}
};
@@ -146,6 +170,35 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
// -- code inset
$registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void {
const provider = <codeInset.CodeInsetProvider>{
provideCodeInsets: (model: ITextModel, token: CancellationToken): CodeInsetDto[] | Thenable<CodeInsetDto[]> => {
return this._proxy.$provideCodeInsets(handle, model.uri, token).then(dto => {
if (dto) { dto.forEach(obj => this._heapService.trackObject(obj)); }
return dto;
});
},
resolveCodeInset: (model: ITextModel, codeInset: CodeInsetDto, token: CancellationToken): CodeInsetDto | Thenable<CodeInsetDto> => {
return this._proxy.$resolveCodeInset(handle, model.uri, codeInset, token).then(obj => {
this._heapService.trackObject(obj);
return obj;
});
}
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<codeInset.CodeInsetProvider>();
this._registrations[eventHandle] = emitter;
provider.onDidChange = emitter.event;
}
const langSelector = typeConverters.LanguageSelector.from(selector);
this._registrations[handle] = codeInset.CodeInsetProviderRegistry.register(langSelector, provider);
}
// --- declaration
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
@@ -184,7 +237,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.HoverProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.HoverProvider>{
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.Hover> => {
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.Hover | undefined> => {
return this._proxy.$provideHover(handle, model.uri, position, token);
}
});
@@ -194,7 +247,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentHighlightProvider>{
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.DocumentHighlight[]> => {
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined> => {
return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);
}
});
@@ -215,7 +268,12 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeAction[]> => {
return this._heapService.trackRecursive(this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token)).then(MainThreadLanguageFeatures._reviveCodeActionDto);
return this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token).then(dto => {
if (dto) {
dto.forEach(obj => { this._heapService.trackObject(obj.command); });
}
return MainThreadLanguageFeatures._reviveCodeActionDto(dto);
});
},
providedCodeActionKinds
});
@@ -223,30 +281,29 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- formatting
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentFormattingEditProvider>{
displayName,
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[]> => {
extensionId,
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);
}
});
}
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], displayName: string): void {
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.DocumentRangeFormattingEditProvider>{
displayName,
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[]> => {
extensionId,
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);
}
});
}
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[]): void {
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.OnTypeFormattingEditProvider>{
extensionId,
autoFormatTriggerCharacters,
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[]> => {
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined> => {
return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token);
}
});
@@ -255,7 +312,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- navigate type
$registerNavigateTypeSupport(handle: number): void {
let lastResultId: number;
let lastResultId: number | undefined;
this._registrations[handle] = search.WorkspaceSymbolProviderRegistry.register(<search.IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string, token: CancellationToken): Promise<search.IWorkspaceSymbol[]> => {
return this._proxy.$provideWorkspaceSymbols(handle, search, token).then(result => {
@@ -266,8 +323,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);
});
},
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol, token: CancellationToken): Promise<search.IWorkspaceSymbol> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item, token).then(i => MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i));
resolveWorkspaceSymbol: (item: search.IWorkspaceSymbol, token: CancellationToken): Promise<search.IWorkspaceSymbol | undefined> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item, token).then(i => {
if (i) {
return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(i);
}
return undefined;
});
}
});
}
@@ -281,7 +343,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(reviveWorkspaceEditDto);
},
resolveRenameLocation: supportResolveLocation
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.RenameLocation> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.RenameLocation | undefined> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)
: undefined
});
}
@@ -291,7 +353,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void {
this._registrations[handle] = modes.CompletionProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.CompletionItemProvider>{
triggerCharacters,
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList> => {
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
if (!result) {
return result;
@@ -299,7 +361,11 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return {
suggestions: result.suggestions,
incomplete: result.incomplete,
dispose: () => this._proxy.$releaseCompletionItems(handle, result._id)
dispose: () => {
if (typeof result._id === 'number') {
this._proxy.$releaseCompletionItems(handle, result._id);
}
}
};
});
},
@@ -317,7 +383,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
signatureHelpTriggerCharacters: metadata.triggerCharacters,
signatureHelpRetriggerCharacters: metadata.retriggerCharacters,
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken, context: modes.SignatureHelpContext): Promise<modes.SignatureHelp> => {
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken, context: modes.SignatureHelpContext): Promise<modes.SignatureHelp | undefined> => {
return this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);
}
});
@@ -328,10 +394,24 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.LinkProviderRegistry.register(typeConverters.LanguageSelector.from(selector), <modes.LinkProvider>{
provideLinks: (model, token) => {
return this._heapService.trackRecursive(this._proxy.$provideDocumentLinks(handle, model.uri, token));
return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {
if (dto) {
dto.forEach(obj => {
MainThreadLanguageFeatures._reviveLinkDTO(obj);
this._heapService.trackObject(obj);
});
}
return dto;
});
},
resolveLink: (link, token) => {
return this._proxy.$resolveDocumentLink(handle, link, token);
return this._proxy.$resolveDocumentLink(handle, link, token).then(obj => {
if (obj) {
MainThreadLanguageFeatures._reviveLinkDTO(obj);
this._heapService.trackObject(obj);
}
return obj;
});
}
});
}
@@ -385,8 +465,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void {
this._registrations[handle] = modes.SelectionRangeRegistry.register(typeConverters.LanguageSelector.from(selector), {
provideSelectionRanges: (model, position, token) => {
return this._proxy.$provideSelectionRanges(handle, model.uri, position, token);
provideSelectionRanges: (model, positions, token) => {
return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);
}
});
}
@@ -394,61 +474,43 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- configuration
private static _reviveRegExp(regExp: ISerializedRegExp): RegExp {
if (typeof regExp === 'undefined') {
return undefined;
}
if (regExp === null) {
return null;
}
return new RegExp(regExp.pattern, regExp.flags);
}
private static _reviveIndentationRule(indentationRule: ISerializedIndentationRule): IndentationRule {
if (typeof indentationRule === 'undefined') {
return undefined;
}
if (indentationRule === null) {
return null;
}
return {
decreaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.decreaseIndentPattern),
increaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.increaseIndentPattern),
indentNextLinePattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.indentNextLinePattern),
unIndentedLinePattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.unIndentedLinePattern),
indentNextLinePattern: indentationRule.indentNextLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.indentNextLinePattern) : undefined,
unIndentedLinePattern: indentationRule.unIndentedLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.unIndentedLinePattern) : undefined,
};
}
private static _reviveOnEnterRule(onEnterRule: ISerializedOnEnterRule): OnEnterRule {
return {
beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText),
afterText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText),
oneLineAboveText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.oneLineAboveText),
afterText: onEnterRule.afterText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText) : undefined,
oneLineAboveText: onEnterRule.oneLineAboveText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.oneLineAboveText) : undefined,
action: onEnterRule.action
};
}
private static _reviveOnEnterRules(onEnterRules: ISerializedOnEnterRule[]): OnEnterRule[] {
if (typeof onEnterRules === 'undefined') {
return undefined;
}
if (onEnterRules === null) {
return null;
}
return onEnterRules.map(MainThreadLanguageFeatures._reviveOnEnterRule);
}
$setLanguageConfiguration(handle: number, languageId: string, _configuration: ISerializedLanguageConfiguration): void {
let configuration: LanguageConfiguration = {
const configuration: LanguageConfiguration = {
comments: _configuration.comments,
brackets: _configuration.brackets,
wordPattern: MainThreadLanguageFeatures._reviveRegExp(_configuration.wordPattern),
indentationRules: MainThreadLanguageFeatures._reviveIndentationRule(_configuration.indentationRules),
onEnterRules: MainThreadLanguageFeatures._reviveOnEnterRules(_configuration.onEnterRules),
wordPattern: _configuration.wordPattern ? MainThreadLanguageFeatures._reviveRegExp(_configuration.wordPattern) : undefined,
indentationRules: _configuration.indentationRules ? MainThreadLanguageFeatures._reviveIndentationRule(_configuration.indentationRules) : undefined,
onEnterRules: _configuration.onEnterRules ? MainThreadLanguageFeatures._reviveOnEnterRules(_configuration.onEnterRules) : undefined,
autoClosingPairs: null,
surroundingPairs: null,
__electricCharacterSupport: null
autoClosingPairs: undefined,
surroundingPairs: undefined,
__electricCharacterSupport: undefined
};
if (_configuration.__characterPairSupport) {
@@ -465,7 +527,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
};
}
let languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (languageIdentifier) {
this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration);
}

View File

@@ -29,7 +29,7 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
$changeLanguage(resource: UriComponents, languageId: string): Promise<void> {
const uri = URI.revive(resource);
let model = this._modelService.getModel(uri);
const model = this._modelService.getModel(uri);
if (!model) {
return Promise.reject(new Error('Invalid uri'));
}

View File

@@ -8,13 +8,12 @@ import Severity from 'vs/base/common/severity';
import { Action, IAction } from 'vs/base/common/actions';
import { MainThreadMessageServiceShape, MainContext, IExtHostContext, MainThreadMessageOptions } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { Event } from 'vs/base/common/event';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { dispose } from 'vs/base/common/lifecycle';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadMessageService)
export class MainThreadMessageService implements MainThreadMessageServiceShape {
@@ -32,7 +31,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
//
}
$showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number> {
$showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
if (options.modal) {
return this._showModalMessage(severity, message, commands);
} else {
@@ -40,17 +39,17 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
}
}
private _showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], extension: IExtensionDescription): Promise<number> {
private _showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], extension: IExtensionDescription | undefined): Promise<number> {
return new Promise<number>(resolve => {
let primaryActions: MessageItemAction[] = [];
const primaryActions: MessageItemAction[] = [];
class MessageItemAction extends Action {
constructor(id: string, label: string, handle: number) {
super(id, label, undefined, true, () => {
resolve(handle);
return undefined;
return Promise.resolve();
});
}
}
@@ -67,7 +66,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
primaryActions.push(new MessageItemAction('_extension_message_handle_' + command.handle, command.title, command.handle));
});
let source: string;
let source: string | undefined;
if (extension) {
source = nls.localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name);
}
@@ -97,7 +96,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
});
}
private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number> {
private _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
let cancelId: number | undefined = undefined;
const buttons = commands.map((command, index) => {

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import { IOutputService, IOutputChannel, OUTPUT_PANEL_ID, Extensions, IOutputChannelRegistry } from 'vs/workbench/parts/output/common/output';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { IOutputService, IOutputChannel, OUTPUT_PANEL_ID, Extensions, IOutputChannelRegistry } from 'vs/workbench/contrib/output/common/output';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { MainThreadOutputServiceShape, MainContext, IExtHostContext, ExtHostOutputServiceShape, ExtHostContext } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@@ -18,27 +18,27 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
private static _idPool = 1;
private _proxy: ExtHostOutputServiceShape;
private readonly _proxy: ExtHostOutputServiceShape;
private readonly _outputService: IOutputService;
private readonly _partService: IPartService;
private readonly _layoutService: IWorkbenchLayoutService;
private readonly _panelService: IPanelService;
constructor(
extHostContext: IExtHostContext,
@IOutputService outputService: IOutputService,
@IPartService partService: IPartService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IPanelService panelService: IPanelService
) {
super();
this._outputService = outputService;
this._partService = partService;
this._layoutService = layoutService;
this._panelService = panelService;
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostOutputService);
const setVisibleChannel = () => {
const panel = this._panelService.getActivePanel();
const visibleChannel: IOutputChannel = panel && panel.getId() === OUTPUT_PANEL_ID ? this._outputService.getActiveChannel() : null;
const visibleChannel: IOutputChannel | null = panel && panel.getId() === OUTPUT_PANEL_ID ? this._outputService.getActiveChannel() : null;
this._proxy.$setVisibleChannel(visibleChannel ? visibleChannel.id : null);
};
this._register(Event.any<any>(this._outputService.onActiveOutputChannel, this._panelService.onDidPanelOpen, this._panelService.onDidPanelClose)(() => setVisibleChannel()));
@@ -47,12 +47,12 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
public $register(label: string, log: boolean, file?: UriComponents): Promise<string> {
const id = 'extension-output-#' + (MainThreadOutputService._idPool++);
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : null, log });
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : undefined, log });
this._register(toDisposable(() => this.$dispose(id)));
return Promise.resolve(id);
}
public $append(channelId: string, value: string): Promise<void> {
public $append(channelId: string, value: string): Promise<void> | undefined {
const channel = this._getChannel(channelId);
if (channel) {
channel.append(value);
@@ -60,7 +60,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
return undefined;
}
public $update(channelId: string): Promise<void> {
public $update(channelId: string): Promise<void> | undefined {
const channel = this._getChannel(channelId);
if (channel) {
channel.update();
@@ -68,7 +68,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
return undefined;
}
public $clear(channelId: string, till: number): Promise<void> {
public $clear(channelId: string, till: number): Promise<void> | undefined {
const channel = this._getChannel(channelId);
if (channel) {
channel.clear(till);
@@ -76,7 +76,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
return undefined;
}
public $reveal(channelId: string, preserveFocus: boolean): Promise<void> {
public $reveal(channelId: string, preserveFocus: boolean): Promise<void> | undefined {
const channel = this._getChannel(channelId);
if (channel) {
this._outputService.showChannel(channel.id, preserveFocus);
@@ -84,16 +84,19 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
return undefined;
}
public $close(channelId: string): Promise<void> {
public $close(channelId: string): Promise<void> | undefined {
const panel = this._panelService.getActivePanel();
if (panel && panel.getId() === OUTPUT_PANEL_ID && channelId === this._outputService.getActiveChannel().id) {
this._partService.setPanelHidden(true);
if (panel && panel.getId() === OUTPUT_PANEL_ID) {
const activeChannel = this._outputService.getActiveChannel();
if (activeChannel && channelId === activeChannel.id) {
this._layoutService.setPanelHidden(true);
}
}
return undefined;
}
public $dispose(channelId: string): Promise<void> {
public $dispose(channelId: string): Promise<void> | undefined {
const channel = this._getChannel(channelId);
if (channel) {
channel.dispose();
@@ -101,7 +104,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
return undefined;
}
private _getChannel(channelId: string): IOutputChannel {
private _getChannel(channelId: string): IOutputChannel | null {
return this._outputService.getChannel(channelId);
}
}

View File

@@ -10,9 +10,9 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
@extHostNamedCustomer(MainContext.MainThreadProgress)
export class MainThreadProgress implements MainThreadProgressShape {
private _progressService: IProgressService2;
private readonly _progressService: IProgressService2;
private _progress = new Map<number, { resolve: () => void, progress: IProgress<IProgressStep> }>();
private _proxy: ExtHostProgressShape;
private readonly _proxy: ExtHostProgressShape;
constructor(
extHostContext: IExtHostContext,
@@ -34,14 +34,16 @@ export class MainThreadProgress implements MainThreadProgressShape {
}
$progressReport(handle: number, message: IProgressStep): void {
if (this._progress.has(handle)) {
this._progress.get(handle).progress.report(message);
const entry = this._progress.get(handle);
if (entry) {
entry.progress.report(message);
}
}
$progressEnd(handle: number): void {
if (this._progress.has(handle)) {
this._progress.get(handle).resolve();
const entry = this._progress.get(handle);
if (entry) {
entry.resolve();
this._progress.delete(handle);
}
}

View File

@@ -18,9 +18,9 @@ interface QuickInputSession {
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
private _proxy: ExtHostQuickOpenShape;
private _quickInputService: IQuickInputService;
private _items: Record<number, {
private readonly _proxy: ExtHostQuickOpenShape;
private readonly _quickInputService: IQuickInputService;
private readonly _items: Record<number, {
resolve(items: TransferQuickPickItems[]): void;
reject(error: Error): void;
}> = {};
@@ -36,7 +36,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
public dispose(): void {
}
$show(instance: number, options: IPickOptions<TransferQuickPickItems>, token: CancellationToken): Promise<number | number[]> {
$show(instance: number, options: IPickOptions<TransferQuickPickItems>, token: CancellationToken): Promise<number | number[] | undefined> {
const contents = new Promise<TransferQuickPickItems[]>((resolve, reject) => {
this._items[instance] = { resolve, reject };
});
@@ -72,7 +72,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
this._items[instance].resolve(items);
delete this._items[instance];
}
return undefined;
return Promise.resolve();
}
$setError(instance: number, error: Error): Promise<void> {
@@ -80,12 +80,12 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
this._items[instance].reject(error);
delete this._items[instance];
}
return undefined;
return Promise.resolve();
}
// ---- input
$input(options: InputBoxOptions, validateInput: boolean, token: CancellationToken): Promise<string> {
$input(options: InputBoxOptions | undefined, validateInput: boolean, token: CancellationToken): Promise<string> {
const inputOptions: IInputOptions = Object.create(null);
if (options) {
@@ -181,13 +181,13 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
.filter(handle => handlesToItems.has(handle))
.map(handle => handlesToItems.get(handle));
} else if (param === 'buttons') {
input[param] = params.buttons.map(button => {
input[param] = params.buttons!.map(button => {
if (button.handle === -1) {
return this._quickInputService.backButton;
}
const { iconPath, tooltip, handle } = button;
return {
iconPath: {
iconPath: iconPath && {
dark: URI.revive(iconPath.dark),
light: iconPath.light && URI.revive(iconPath.light)
},

View File

@@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { assign } from 'vs/base/common/objects';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/services/scm/common/scm';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/contrib/scm/common/scm';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
@@ -21,14 +21,14 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup {
private _onDidSplice = new Emitter<ISplice<ISCMResource>>();
readonly onDidSplice = this._onDidSplice.event;
get hideWhenEmpty(): boolean { return this.features.hideWhenEmpty; }
get hideWhenEmpty(): boolean { return !!this.features.hideWhenEmpty; }
private _onDidChange = new Emitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
constructor(
private sourceControlHandle: number,
private handle: number,
private readonly sourceControlHandle: number,
private readonly handle: number,
public provider: ISCMProvider,
public features: SCMGroupFeatures,
public label: string,
@@ -62,10 +62,10 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup {
class MainThreadSCMResource implements ISCMResource {
constructor(
private proxy: ExtHostSCMShape,
private sourceControlHandle: number,
private groupHandle: number,
private handle: number,
private readonly proxy: ExtHostSCMShape,
private readonly sourceControlHandle: number,
private readonly groupHandle: number,
private readonly handle: number,
public sourceUri: URI,
public resourceGroup: ISCMResourceGroup,
public decorations: ISCMResourceDecorations
@@ -92,7 +92,7 @@ class MainThreadSCMProvider implements ISCMProvider {
get id(): string { return this._id; }
readonly groups = new Sequence<MainThreadSCMResourceGroup>();
private _groupsByHandle: { [handle: number]: MainThreadSCMResourceGroup; } = Object.create(null);
private readonly _groupsByHandle: { [handle: number]: MainThreadSCMResourceGroup; } = Object.create(null);
// get groups(): ISequence<ISCMResourceGroup> {
// return {
@@ -129,11 +129,11 @@ class MainThreadSCMProvider implements ISCMProvider {
get onDidChange(): Event<void> { return this._onDidChange.event; }
constructor(
private proxy: ExtHostSCMShape,
private _handle: number,
private _contextValue: string,
private _label: string,
private _rootUri: URI | undefined,
private readonly proxy: ExtHostSCMShape,
private readonly _handle: number,
private readonly _contextValue: string,
private readonly _label: string,
private readonly _rootUri: URI | undefined,
@ISCMService scmService: ISCMService
) { }
@@ -142,11 +142,11 @@ class MainThreadSCMProvider implements ISCMProvider {
this._onDidChange.fire();
if (typeof features.commitTemplate !== 'undefined') {
this._onDidChangeCommitTemplate.fire(this.commitTemplate);
this._onDidChangeCommitTemplate.fire(this.commitTemplate!);
}
if (typeof features.statusBarCommands !== 'undefined') {
this._onDidChangeStatusBarCommands.fire(this.statusBarCommands);
this._onDidChangeStatusBarCommands.fire(this.statusBarCommands!);
}
}
@@ -202,14 +202,14 @@ class MainThreadSCMProvider implements ISCMProvider {
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
icon: icon && URI.parse(icon),
iconDark: iconDark && URI.parse(iconDark),
icon: icon ? URI.parse(icon) : undefined,
iconDark: iconDark ? URI.parse(iconDark) : undefined,
tooltip,
strikeThrough,
faded,
source,
letter,
color: color && color.id
color: color ? color.id : undefined
};
return new MainThreadSCMResource(
@@ -241,7 +241,7 @@ class MainThreadSCMProvider implements ISCMProvider {
this.groups.splice(this.groups.elements.indexOf(group), 1);
}
async getOriginalResource(uri: URI): Promise<URI> {
async getOriginalResource(uri: URI): Promise<URI | null> {
if (!this.features.hasQuickDiffProvider) {
return null;
}
@@ -265,7 +265,7 @@ class MainThreadSCMProvider implements ISCMProvider {
@extHostNamedCustomer(MainContext.MainThreadSCM)
export class MainThreadSCM implements MainThreadSCMShape {
private _proxy: ExtHostSCMShape;
private readonly _proxy: ExtHostSCMShape;
private _repositories: { [handle: number]: ISCMRepository; } = Object.create(null);
private _inputDisposables: { [handle: number]: IDisposable; } = Object.create(null);
private _disposables: IDisposable[] = [];

View File

@@ -7,7 +7,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IdleValue, sequence } from 'vs/base/common/async';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import * as strings from 'vs/base/common/strings';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
@@ -16,14 +16,14 @@ import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IIdentifiedSingleEditOperation, ISingleEditOperation, ITextModel } from 'vs/editor/common/model';
import { CodeAction } from 'vs/editor/common/modes';
import { IIdentifiedSingleEditOperation, ITextModel } from 'vs/editor/common/model';
import { CodeAction, TextEdit } from 'vs/editor/common/modes';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { getDocumentFormattingEdits, NoProviderError } from 'vs/editor/contrib/format/format';
import { getDocumentFormattingEdits, FormatMode } from 'vs/editor/contrib/format/format';
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
import { localize } from 'vs/nls';
@@ -34,8 +34,10 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
// {{SQL CARBON EDIT}}
import { ISaveParticipant, SaveReason, IResolvedTextFileEditorModel, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../node/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
// {{SQL CARBON EDIT}}
import { INotebookService } from 'sql/workbench/services/notebook/common/notebookService';
@@ -78,7 +80,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
// Nothing
}
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO);
}
@@ -88,7 +90,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
let prevSelection: Selection[] = [];
let cursors: Position[] = [];
let editor = findEditor(model, this.codeEditorService);
const editor = findEditor(model, this.codeEditorService);
if (editor) {
// Find `prevSelection` in any case do ensure a good undo stack when pushing the edit
// Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump
@@ -113,12 +115,12 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
}
}
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): ICodeEditor {
let candidate: ICodeEditor | null = null;
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): IActiveCodeEditor | null {
let candidate: IActiveCodeEditor | null = null;
if (model.isAttachedToEditor()) {
for (const editor of codeEditorService.listCodeEditors()) {
if (editor.getModel() === model) {
if (editor.hasModel() && editor.getModel() === model) {
if (editor.hasTextFocus()) {
return editor; // favour focused editor if there are multiple
}
@@ -140,7 +142,7 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant {
// Nothing
}
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
this.doInsertFinalNewLine(model.textEditorModel);
}
@@ -178,7 +180,7 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant
// Nothing
}
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) {
this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO);
}
@@ -243,12 +245,13 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
constructor(
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
@IConfigurationService private readonly _configurationService: IConfigurationService
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
) {
// Nothing
}
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
const model = editorModel.textEditorModel;
if (env.reason === SaveReason.AUTO
@@ -257,26 +260,19 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
}
const versionNow = model.getVersionId();
const { tabSize, insertSpaces } = model.getOptions();
const timeout = this._configurationService.getValue<number>('editor.formatOnSaveTimeout', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() });
return new Promise<ISingleEditOperation[]>((resolve, reject) => {
let source = new CancellationTokenSource();
let request = getDocumentFormattingEdits(model, { tabSize, insertSpaces }, source.token);
return new Promise<TextEdit[] | null | undefined>((resolve, reject) => {
const source = new CancellationTokenSource();
const request = getDocumentFormattingEdits(this._telemetryService, this._editorWorkerService, model, model.getFormattingOptions(), FormatMode.Auto, source.token);
setTimeout(() => {
reject(localize('timeout.formatOnSave', "Aborted format on save after {0}ms", timeout));
source.cancel();
}, timeout);
request.then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits)).then(resolve, err => {
if (!NoProviderError.is(err)) {
reject(err);
} else {
resolve();
}
});
request.then(resolve, reject);
}).then(edits => {
if (isNonEmptyArray(edits) && versionNow === model.getVersionId()) {
@@ -290,11 +286,11 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
});
}
private _editsWithEditor(editor: ICodeEditor, edits: ISingleEditOperation[]): void {
private _editsWithEditor(editor: ICodeEditor, edits: TextEdit[]): void {
FormattingEdit.execute(editor, edits);
}
private _editWithModel(model: ITextModel, edits: ISingleEditOperation[]): void {
private _editWithModel(model: ITextModel, edits: TextEdit[]): void {
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
@@ -305,11 +301,11 @@ class FormatOnSaveParticipant implements ISaveParticipantParticipant {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return undefined;
return null;
});
}
private static _asIdentEdit({ text, range }: ISingleEditOperation): IIdentifiedSingleEditOperation {
private static _asIdentEdit({ text, range }: TextEdit): IIdentifiedSingleEditOperation {
return {
text,
range: Range.lift(range),
@@ -326,7 +322,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
@IConfigurationService private readonly _configurationService: IConfigurationService
) { }
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
if (env.reason === SaveReason.AUTO) {
return undefined;
}
@@ -377,14 +373,14 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
for (const codeActionKind of codeActionsOnSave) {
const actionsToRun = await this.getActionsToRun(model, codeActionKind, token);
try {
await this.applyCodeActions(actionsToRun);
await this.applyCodeActions(actionsToRun.actions);
} catch {
// Failure to apply a code action should not block other on save actions
}
}
}
private async applyCodeActions(actionsToRun: CodeAction[]) {
private async applyCodeActions(actionsToRun: ReadonlyArray<CodeAction>) {
for (const action of actionsToRun) {
await applyCodeAction(action, this._bulkEditService, this._commandService);
}
@@ -400,13 +396,13 @@ class CodeActionOnSaveParticipant implements ISaveParticipant {
class ExtHostSaveParticipant implements ISaveParticipantParticipant {
private _proxy: ExtHostDocumentSaveParticipantShape;
private readonly _proxy: ExtHostDocumentSaveParticipantShape;
constructor(extHostContext: IExtHostContext) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
}
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
if (!shouldSynchronizeModel(editorModel.textEditorModel)) {
// the model never made it to the extension
@@ -455,11 +451,11 @@ export class SaveParticipant implements ISaveParticipant {
}
dispose(): void {
TextFileEditorModel.setSaveParticipant(undefined);
TextFileEditorModel.setSaveParticipant(null);
this._saveParticipants.dispose();
}
async participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
return this._progressService.withProgress({ location: ProgressLocation.Window }, progress => {
progress.report({ message: localize('saveParticipants', "Running Save Participants...") });
const promiseFactory = this._saveParticipants.getValue().map(p => () => {

View File

@@ -7,7 +7,7 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, QueryType, SearchProviderType, ITextQuery, IFileQuery } from 'vs/platform/search/common/search';
import { IFileMatch, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, QueryType, SearchProviderType, ITextQuery, IFileQuery } from 'vs/workbench/services/search/common/search';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../node/extHost.protocol';
@@ -40,21 +40,27 @@ export class MainThreadSearch implements MainThreadSearchShape {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, SearchProviderType.file, scheme, handle, this._proxy));
}
$registerFileIndexProvider(handle: number, scheme: string): void {
this._searchProvider.set(handle, new RemoteSearchProvider(this._searchService, SearchProviderType.fileIndex, scheme, handle, this._proxy));
}
$unregisterProvider(handle: number): void {
dispose(this._searchProvider.get(handle));
this._searchProvider.delete(handle);
}
$handleFileMatch(handle: number, session, data: UriComponents[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
const provider = this._searchProvider.get(handle);
if (!provider) {
throw new Error('Got result for unknown provider');
}
provider.handleFindMatch(session, data);
}
$handleTextMatch(handle: number, session, data: IRawFileMatch2[]): void {
this._searchProvider.get(handle).handleFindMatch(session, data);
const provider = this._searchProvider.get(handle);
if (!provider) {
throw new Error('Got result for unknown provider');
}
provider.handleFindMatch(session, data);
}
$handleTelemetry(eventName: string, data: any): void {
@@ -77,7 +83,8 @@ class SearchOperation {
addMatch(match: IFileMatch): void {
if (this.matches.has(match.resource.toString())) {
// Merge with previous IFileMatches
this.matches.get(match.resource.toString()).results.push(...match.results);
// TODO@rob clean up text/file result types
this.matches.get(match.resource.toString())!.results!.push(...match.results!);
} else {
this.matches.set(match.resource.toString(), match);
}
@@ -107,15 +114,15 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
dispose(this._registrations);
}
fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
return this.doSearch(query, null, token);
fileSearch(query: IFileQuery, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete | undefined> {
return this.doSearch(query, undefined, token);
}
textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete | undefined> {
return this.doSearch(query, onProgress, token);
}
doSearch(query: ITextQuery | IFileQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete> {
doSearch(query: ITextQuery | IFileQuery, onProgress?: (p: ISearchProgressItem) => void, token: CancellationToken = CancellationToken.None): Promise<ISearchComplete | undefined> {
if (isFalsyOrEmpty(query.folderQueries)) {
return Promise.resolve(undefined);
}
@@ -141,12 +148,13 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
}
handleFindMatch(session: number, dataOrUri: Array<UriComponents | IRawFileMatch2>): void {
if (!this._searches.has(session)) {
const searchOp = this._searches.get(session);
if (!searchOp) {
// ignore...
return;
}
const searchOp = this._searches.get(session);
dataOrUri.forEach(result => {
if ((<IRawFileMatch2>result).results) {
searchOp.addMatch({

View File

@@ -34,12 +34,12 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.$dispose(id);
// Add new
let entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
const entry = this._statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
this._entries[id] = entry;
}
$dispose(id: number) {
let disposeable = this._entries[id];
const disposeable = this._entries[id];
if (disposeable) {
disposeable.dispose();
}

View File

@@ -11,10 +11,10 @@ import { IDisposable } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadStorage)
export class MainThreadStorage implements MainThreadStorageShape {
private _storageService: IStorageService;
private _proxy: ExtHostStorageShape;
private _storageListener: IDisposable;
private _sharedStorageKeysToWatch: Map<string, boolean> = new Map<string, boolean>();
private readonly _storageService: IStorageService;
private readonly _proxy: ExtHostStorageShape;
private readonly _storageListener: IDisposable;
private readonly _sharedStorageKeysToWatch: Map<string, boolean> = new Map<string, boolean>();
constructor(
extHostContext: IExtHostContext,
@@ -24,7 +24,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostStorage);
this._storageListener = this._storageService.onDidChangeStorage(e => {
let shared = e.scope === StorageScope.GLOBAL;
const shared = e.scope === StorageScope.GLOBAL;
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
try {
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
@@ -39,7 +39,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
this._storageListener.dispose();
}
$getValue<T>(shared: boolean, key: string): Promise<T> {
$getValue<T>(shared: boolean, key: string): Promise<T | undefined> {
if (shared) {
this._sharedStorageKeysToWatch.set(key, true);
}
@@ -50,8 +50,8 @@ export class MainThreadStorage implements MainThreadStorageShape {
}
}
private _getValue<T>(shared: boolean, key: string): T {
let jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
private _getValue<T>(shared: boolean, key: string): T | undefined {
const jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
if (!jsonValue) {
return undefined;
}
@@ -66,6 +66,6 @@ export class MainThreadStorage implements MainThreadStorageShape {
} catch (err) {
return Promise.reject(err);
}
return undefined;
return Promise.resolve(undefined);
}
}

View File

@@ -18,19 +18,19 @@ import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspac
import {
ContributedTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet
} from 'vs/workbench/parts/tasks/common/tasks';
} from 'vs/workbench/contrib/tasks/common/tasks';
import { ResolveSet, ResolvedVariables } from 'vs/workbench/parts/tasks/common/taskSystem';
import { ITaskService, TaskFilter, ITaskProvider } from 'vs/workbench/parts/tasks/common/taskService';
import { ResolveSet, ResolvedVariables } from 'vs/workbench/contrib/tasks/common/taskSystem';
import { ITaskService, TaskFilter, ITaskProvider } from 'vs/workbench/contrib/tasks/common/taskService';
import { TaskDefinition } from 'vs/workbench/parts/tasks/node/tasks';
import { TaskDefinition } from 'vs/workbench/contrib/tasks/node/tasks';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
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, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO,
ProcessExecutionDTO, ShellExecutionDTO, ShellExecutionOptionsDTO, CustomExecutionDTO, TaskDTO, TaskSourceDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO,
RunOptionsDTO
} from 'vs/workbench/api/shared/tasks';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
@@ -42,12 +42,6 @@ namespace TaskExecutionDTO {
task: TaskDTO.from(value.task)
};
}
export function to(value: TaskExecutionDTO, workspace: IWorkspaceContextService, executeOnly: boolean): TaskExecution {
return {
id: value.id,
task: TaskDTO.to(value.task, workspace, executeOnly)
};
}
}
namespace TaskProcessStartedDTO {
@@ -70,11 +64,11 @@ namespace TaskProcessEndedDTO {
namespace TaskDefinitionDTO {
export function from(value: KeyedTaskIdentifier): TaskDefinitionDTO {
let result = Objects.assign(Object.create(null), value);
const result = Objects.assign(Object.create(null), value);
delete result._key;
return result;
}
export function to(value: TaskDefinitionDTO, executeOnly: boolean): KeyedTaskIdentifier {
export function to(value: TaskDefinitionDTO, executeOnly: boolean): KeyedTaskIdentifier | undefined {
let result = TaskDefinition.createTaskIdentifier(value, console);
if (result === undefined && executeOnly) {
result = {
@@ -87,13 +81,13 @@ namespace TaskDefinitionDTO {
}
namespace TaskPresentationOptionsDTO {
export function from(value: PresentationOptions): TaskPresentationOptionsDTO {
export function from(value: PresentationOptions | undefined): TaskPresentationOptionsDTO | undefined {
if (value === undefined || value === null) {
return undefined;
}
return Objects.assign(Object.create(null), value);
}
export function to(value: TaskPresentationOptionsDTO): PresentationOptions {
export function to(value: TaskPresentationOptionsDTO | undefined): PresentationOptions {
if (value === undefined || value === null) {
return PresentationOptions.defaults;
}
@@ -102,13 +96,13 @@ namespace TaskPresentationOptionsDTO {
}
namespace RunOptionsDTO {
export function from(value: RunOptions): RunOptionsDTO {
export function from(value: RunOptions): RunOptionsDTO | undefined {
if (value === undefined || value === null) {
return undefined;
}
return Objects.assign(Object.create(null), value);
}
export function to(value: RunOptionsDTO): RunOptions {
export function to(value: RunOptionsDTO | undefined): RunOptions {
if (value === undefined || value === null) {
return RunOptions.defaults;
}
@@ -117,7 +111,7 @@ namespace RunOptionsDTO {
}
namespace ProcessExecutionOptionsDTO {
export function from(value: CommandOptions): ProcessExecutionOptionsDTO {
export function from(value: CommandOptions): ProcessExecutionOptionsDTO | undefined {
if (value === undefined || value === null) {
return undefined;
}
@@ -126,7 +120,7 @@ namespace ProcessExecutionOptionsDTO {
env: value.env
};
}
export function to(value: ProcessExecutionOptionsDTO): CommandOptions {
export function to(value: ProcessExecutionOptionsDTO | undefined): CommandOptions {
if (value === undefined || value === null) {
return CommandOptions.defaults;
}
@@ -138,14 +132,14 @@ namespace ProcessExecutionOptionsDTO {
}
namespace ProcessExecutionDTO {
export function is(value: ShellExecutionDTO | ProcessExecutionDTO): value is ProcessExecutionDTO {
let candidate = value as ProcessExecutionDTO;
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ProcessExecutionDTO {
const candidate = value as ProcessExecutionDTO;
return candidate && !!candidate.process;
}
export function from(value: CommandConfiguration): ProcessExecutionDTO {
let process: string = Types.isString(value.name) ? value.name : value.name.value;
let args: string[] = value.args ? value.args.map(value => Types.isString(value) ? value : value.value) : [];
let result: ProcessExecutionDTO = {
const process: string = Types.isString(value.name) ? value.name : value.name!.value;
const args: string[] = value.args ? value.args.map(value => Types.isString(value) ? value : value.value) : [];
const result: ProcessExecutionDTO = {
process: process,
args: args
};
@@ -155,7 +149,7 @@ namespace ProcessExecutionDTO {
return result;
}
export function to(value: ProcessExecutionDTO): CommandConfiguration {
let result: CommandConfiguration = {
const result: CommandConfiguration = {
runtime: RuntimeType.Process,
name: value.process,
args: value.args,
@@ -167,11 +161,11 @@ namespace ProcessExecutionDTO {
}
namespace ShellExecutionOptionsDTO {
export function from(value: CommandOptions): ShellExecutionOptionsDTO {
export function from(value: CommandOptions): ShellExecutionOptionsDTO | undefined {
if (value === undefined || value === null) {
return undefined;
}
let result: ShellExecutionOptionsDTO = {
const result: ShellExecutionOptionsDTO = {
cwd: value.cwd || CommandOptions.defaults.cwd,
env: value.env
};
@@ -182,11 +176,11 @@ namespace ShellExecutionOptionsDTO {
}
return result;
}
export function to(value: ShellExecutionOptionsDTO): CommandOptions {
export function to(value: ShellExecutionOptionsDTO): CommandOptions | undefined {
if (value === undefined || value === null) {
return undefined;
}
let result: CommandOptions = {
const result: CommandOptions = {
cwd: value.cwd,
env: value.env
};
@@ -206,12 +200,12 @@ namespace ShellExecutionOptionsDTO {
}
namespace ShellExecutionDTO {
export function is(value: ShellExecutionDTO | ProcessExecutionDTO): value is ShellExecutionDTO {
let candidate = value as ShellExecutionDTO;
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is ShellExecutionDTO {
const candidate = value as ShellExecutionDTO;
return candidate && (!!candidate.commandLine || !!candidate.command);
}
export function from(value: CommandConfiguration): ShellExecutionDTO {
let result: ShellExecutionDTO = {};
const result: ShellExecutionDTO = {};
if (value.name && Types.isString(value.name) && (value.args === undefined || value.args === null || value.args.length === 0)) {
result.commandLine = value.name;
} else {
@@ -224,7 +218,7 @@ namespace ShellExecutionDTO {
return result;
}
export function to(value: ShellExecutionDTO): CommandConfiguration {
let result: CommandConfiguration = {
const result: CommandConfiguration = {
runtime: RuntimeType.Shell,
name: value.commandLine ? value.commandLine : value.command,
args: value.args,
@@ -237,9 +231,29 @@ namespace ShellExecutionDTO {
}
}
namespace CustomExecutionDTO {
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO): value is CustomExecutionDTO {
const candidate = value as CustomExecutionDTO;
return candidate && candidate.customExecution === 'customExecution';
}
export function from(value: CommandConfiguration): CustomExecutionDTO {
return {
customExecution: 'customExecution'
};
}
export function to(value: CustomExecutionDTO): CommandConfiguration {
return {
runtime: RuntimeType.CustomExecution,
presentation: undefined
};
}
}
namespace TaskSourceDTO {
export function from(value: TaskSource): TaskSourceDTO {
let result: TaskSourceDTO = {
const result: TaskSourceDTO = {
label: value.label
};
if (value.kind === TaskSourceKind.Extension) {
@@ -257,7 +271,7 @@ namespace TaskSourceDTO {
}
export function to(value: TaskSourceDTO, workspace: IWorkspaceContextService): ExtensionTaskSource {
let scope: TaskScope;
let workspaceFolder: IWorkspaceFolder;
let workspaceFolder: IWorkspaceFolder | undefined;
if ((value.scope === undefined) || ((typeof value.scope === 'number') && (value.scope !== TaskScope.Global))) {
if (workspace.getWorkspace().folders.length === 0) {
scope = TaskScope.Global;
@@ -270,9 +284,9 @@ namespace TaskSourceDTO {
scope = value.scope;
} else {
scope = TaskScope.Folder;
workspaceFolder = workspace.getWorkspaceFolder(URI.revive(value.scope));
workspaceFolder = Types.withNullAsUndefined(workspace.getWorkspaceFolder(URI.revive(value.scope)));
}
let result: ExtensionTaskSource = {
const result: ExtensionTaskSource = {
kind: TaskSourceKind.Extension,
label: value.label,
extension: value.extensionId,
@@ -285,17 +299,17 @@ namespace TaskSourceDTO {
namespace TaskHandleDTO {
export function is(value: any): value is TaskHandleDTO {
let candidate: TaskHandleDTO = value;
const candidate: TaskHandleDTO = value;
return candidate && Types.isString(candidate.id) && !!candidate.workspaceFolder;
}
}
namespace TaskDTO {
export function from(task: Task): TaskDTO {
export function from(task: Task): TaskDTO | undefined {
if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task))) {
return undefined;
}
let result: TaskDTO = {
const result: TaskDTO = {
_id: task._id,
name: task.configurationProperties.name,
definition: TaskDefinitionDTO.from(task.getDefinition()),
@@ -327,26 +341,32 @@ namespace TaskDTO {
return result;
}
export function to(task: TaskDTO, workspace: IWorkspaceContextService, executeOnly: boolean): ContributedTask {
if (typeof task.name !== 'string') {
export function to(task: TaskDTO | undefined, workspace: IWorkspaceContextService, executeOnly: boolean): ContributedTask | undefined {
if (!task || (typeof task.name !== 'string')) {
return undefined;
}
let command: CommandConfiguration;
if (ShellExecutionDTO.is(task.execution)) {
command = ShellExecutionDTO.to(task.execution);
} else if (ProcessExecutionDTO.is(task.execution)) {
command = ProcessExecutionDTO.to(task.execution);
let command: CommandConfiguration | undefined;
if (task.execution) {
if (ShellExecutionDTO.is(task.execution)) {
command = ShellExecutionDTO.to(task.execution);
} else if (ProcessExecutionDTO.is(task.execution)) {
command = ProcessExecutionDTO.to(task.execution);
} else if (CustomExecutionDTO.is(task.execution)) {
command = CustomExecutionDTO.to(task.execution);
}
}
if (!command) {
return undefined;
}
command.presentation = TaskPresentationOptionsDTO.to(task.presentationOptions);
let source = TaskSourceDTO.to(task.source, workspace);
const source = TaskSourceDTO.to(task.source, workspace);
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let definition = TaskDefinitionDTO.to(task.definition, executeOnly);
let id = `${task.source.extensionId}.${definition._key}`;
let result: ContributedTask = new ContributedTask(
const label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
const definition = TaskDefinitionDTO.to(task.definition, executeOnly)!;
const id = `${task.source.extensionId}.${definition._key}`;
const result: ContributedTask = new ContributedTask(
id, // uuidMap.getUUID(identifier)
source,
label,
@@ -371,7 +391,7 @@ namespace TaskFilterDTO {
export function from(value: TaskFilter): TaskFilterDTO {
return value;
}
export function to(value: TaskFilterDTO): TaskFilter {
export function to(value: TaskFilterDTO | undefined): TaskFilter | undefined {
return value;
}
}
@@ -379,9 +399,9 @@ namespace TaskFilterDTO {
@extHostNamedCustomer(MainContext.MainThreadTask)
export class MainThreadTask implements MainThreadTaskShape {
private _extHostContext: IExtHostContext;
private _proxy: ExtHostTaskShape;
private _providers: Map<number, { disposable: IDisposable, provider: ITaskProvider }>;
private readonly _extHostContext: IExtHostContext;
private readonly _proxy: ExtHostTaskShape;
private readonly _providers: Map<number, { disposable: IDisposable, provider: ITaskProvider }>;
constructor(
extHostContext: IExtHostContext,
@@ -392,13 +412,13 @@ export class MainThreadTask implements MainThreadTaskShape {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTask);
this._providers = new Map();
this._taskService.onDidStateChange((event: TaskEvent) => {
let task = event.__task;
const task = event.__task!;
if (event.kind === TaskEventKind.Start) {
this._proxy.$onDidStartTask(TaskExecutionDTO.from(task.getTaskExecution()));
this._proxy.$onDidStartTask(TaskExecutionDTO.from(task.getTaskExecution()), event.terminalId!);
} else if (event.kind === TaskEventKind.ProcessStarted) {
this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(task.getTaskExecution(), event.processId));
this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(task.getTaskExecution(), event.processId!));
} else if (event.kind === TaskEventKind.ProcessEnded) {
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode));
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode!));
} else if (event.kind === TaskEventKind.End) {
this._proxy.$OnDidEndTask(TaskExecutionDTO.from(task.getTaskExecution()));
}
@@ -412,13 +432,24 @@ export class MainThreadTask implements MainThreadTaskShape {
this._providers.clear();
}
$createTaskId(taskDTO: TaskDTO): Promise<string> {
return new Promise((resolve, reject) => {
let task = TaskDTO.to(taskDTO, this._workspaceContextServer, true);
if (task) {
resolve(task._id);
} else {
reject(new Error('Task could not be created from DTO'));
}
});
}
public $registerTaskProvider(handle: number): Promise<void> {
let provider: ITaskProvider = {
const provider: ITaskProvider = {
provideTasks: (validTypes: IStringDictionary<boolean>) => {
return Promise.resolve(this._proxy.$provideTasks(handle, validTypes)).then((value) => {
let tasks: Task[] = [];
const tasks: Task[] = [];
for (let dto of value.tasks) {
let task = TaskDTO.to(dto, this._workspaceContextServer, true);
const task = TaskDTO.to(dto, this._workspaceContextServer, true);
if (task) {
tasks.push(task);
} else {
@@ -432,21 +463,25 @@ export class MainThreadTask implements MainThreadTaskShape {
});
}
};
let disposable = this._taskService.registerTaskProvider(provider);
const disposable = this._taskService.registerTaskProvider(provider);
this._providers.set(handle, { disposable, provider });
return Promise.resolve(undefined);
}
public $unregisterTaskProvider(handle: number): Promise<void> {
this._providers.delete(handle);
const provider = this._providers.get(handle);
if (provider) {
provider.disposable.dispose();
this._providers.delete(handle);
}
return Promise.resolve(undefined);
}
public $fetchTasks(filter?: TaskFilterDTO): Promise<TaskDTO[]> {
return this._taskService.tasks(TaskFilterDTO.to(filter)).then((tasks) => {
let result: TaskDTO[] = [];
const result: TaskDTO[] = [];
for (let task of tasks) {
let item = TaskDTO.from(task);
const item = TaskDTO.from(task);
if (item) {
result.push(item);
}
@@ -458,25 +493,29 @@ export class MainThreadTask implements MainThreadTaskShape {
public $executeTask(value: TaskHandleDTO | TaskDTO): Promise<TaskExecutionDTO> {
return new Promise<TaskExecutionDTO>((resolve, reject) => {
if (TaskHandleDTO.is(value)) {
let workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
this._taskService.getTask(workspaceFolder, value.id, true).then((task: Task) => {
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
const workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(value.workspaceFolder));
if (workspaceFolder) {
this._taskService.getTask(workspaceFolder, value.id, true).then((task: Task) => {
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
const result: TaskExecutionDTO = {
id: value.id,
task: TaskDTO.from(task)
};
resolve(result);
}, (_error) => {
reject(new Error('Task not found'));
});
let result: TaskExecutionDTO = {
id: value.id,
task: TaskDTO.from(task)
};
resolve(result);
}, (_error) => {
reject(new Error('Task not found'));
});
} else {
reject(new Error('No workspace folder'));
}
} else {
let task = TaskDTO.to(value, this._workspaceContextServer, true);
const task = TaskDTO.to(value, this._workspaceContextServer, true)!;
this._taskService.run(task).then(undefined, reason => {
// eat the error, it has already been surfaced to the user and we don't care about it here
});
let result: TaskExecutionDTO = {
const result: TaskExecutionDTO = {
id: task._id,
task: TaskDTO.from(task)
};
@@ -485,6 +524,24 @@ export class MainThreadTask implements MainThreadTaskShape {
});
}
public $customExecutionComplete(id: string, result?: number): Promise<void> {
return new Promise<void>((resolve, reject) => {
this._taskService.getActiveTasks().then((tasks) => {
for (let task of tasks) {
if (id === task._id) {
this._taskService.extensionCallbackTaskComplete(task, result).then((value) => {
resolve(undefined);
}, (error) => {
reject(error);
});
return;
}
}
reject(new Error('Task to mark as complete not found'));
});
});
}
public $terminateTask(id: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
this._taskService.getActiveTasks().then((tasks) => {
@@ -525,17 +582,17 @@ export class MainThreadTask implements MainThreadTaskShape {
},
context: this._extHostContext,
resolveVariables: (workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise<ResolvedVariables> => {
let vars: string[] = [];
const vars: string[] = [];
toResolve.variables.forEach(item => vars.push(item));
return Promise.resolve(this._proxy.$resolveVariables(workspaceFolder.uri, { process: toResolve.process, variables: vars })).then(values => {
const partiallyResolvedVars = new Array<string>();
forEach(values.variables, (entry) => {
partiallyResolvedVars.push(entry.value);
});
return new Promise((resolve, reject) => {
return new Promise<ResolvedVariables>((resolve, reject) => {
this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks').then(resolvedVars => {
let result = {
process: undefined as string,
const result: ResolvedVariables = {
process: undefined,
variables: new Map<string, string>()
};
for (let i = 0; i < partiallyResolvedVars.length; i++) {

View File

@@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { UriComponents, URI } from 'vs/base/common/uri';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -28,13 +29,16 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// Delay this message so the TerminalInstance constructor has a chance to finish and
// return the ID normally to the extension host. The ID that is passed here will be used
// to register non-extension API terminals in the extension host.
setTimeout(() => this._onTerminalOpened(instance), EXT_HOST_CREATION_DELAY);
setTimeout(() => {
this._onTerminalOpened(instance);
this._onInstanceDimensionsChanged(instance);
}, EXT_HOST_CREATION_DELAY);
}));
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : undefined)));
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
// Set initial ext host state
@@ -55,12 +59,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// when the extension host process goes down ?
}
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }> {
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }> {
const shellLaunchConfig: IShellLaunchConfig = {
name,
executable: shellPath,
args: shellArgs,
cwd,
cwd: typeof cwd === 'string' ? cwd : URI.revive(cwd),
waitOnExit,
ignoreConfigurationCwd: true,
env,
@@ -87,7 +91,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
public $hide(terminalId: number): void {
if (this.terminalService.getActiveInstance().id === terminalId) {
const instance = this.terminalService.getActiveInstance();
if (instance && instance.id === terminalId) {
this.terminalService.hidePanel();
}
}
@@ -161,7 +166,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
terminalInstance.addDisposable(this._terminalOnDidWriteDataListeners[terminalId]);
}
private _onActiveTerminalChanged(terminalId: number | undefined): void {
private _onActiveTerminalChanged(terminalId: number | null): void {
this._proxy.$acceptActiveTerminalChanged(terminalId);
}
@@ -192,15 +197,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
if (terminalInstance.processId === undefined) {
return;
}
this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
}
private _onInstanceDimensionsChanged(instance: ITerminalInstance): void {
// Only send the dimensions if the terminal is a renderer only as there is no API to access
// dimensions on a plain Terminal.
if (instance.shellLaunchConfig.isRendererOnly) {
this._proxy.$acceptTerminalRendererDimensions(instance.id, instance.cols, instance.rows);
}
this._proxy.$acceptTerminalDimensions(instance.id, instance.cols, instance.rows);
}
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {

View File

@@ -5,18 +5,19 @@
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, ViewsRegistry, ITreeViewDescriptor, IRevealOptions } from 'vs/workbench/common/views';
import { ITreeViewDataProvider, ITreeItem, IViewsService, ITreeView, IViewsRegistry, ITreeViewDescriptor, IRevealOptions, Extensions } 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';
import { isUndefinedOrNull, isNumber } from 'vs/base/common/types';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { Registry } from 'vs/platform/registry/common/platform';
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
private _proxy: ExtHostTreeViewsShape;
private _dataProviders: Map<string, TreeViewDataProvider> = new Map<string, TreeViewDataProvider>();
private readonly _proxy: ExtHostTreeViewsShape;
private readonly _dataProviders: Map<string, TreeViewDataProvider> = new Map<string, TreeViewDataProvider>();
constructor(
extHostContext: IExtHostContext,
@@ -45,7 +46,10 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
return this.viewsService.openView(treeViewId, options.focus)
.then(() => {
const viewer = this.getTreeView(treeViewId);
return this.reveal(viewer, this._dataProviders.get(treeViewId), item, parentChain, options);
if (viewer) {
return this.reveal(viewer, this._dataProviders.get(treeViewId)!, item, parentChain, options);
}
return undefined;
});
}
@@ -56,7 +60,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
const itemsToRefresh = dataProvider.getItemsToRefresh(itemsToRefreshByHandle);
return viewer.refresh(itemsToRefresh.length ? itemsToRefresh : undefined);
}
return null;
return Promise.resolve();
}
$setMessage(treeViewId: string, message: string | IMarkdownString): void {
@@ -66,7 +70,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
private async reveal(treeView: ITreeView, dataProvider: TreeViewDataProvider, itemIn: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
options = options ? options : { select: false, focus: false };
const select = isUndefinedOrNull(options.select) ? false : options.select;
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
@@ -79,7 +83,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
for (const parent of parentChain) {
await treeView.expand(parent);
}
item = dataProvider.getItem(item.handle);
const item = dataProvider.getItem(itemIn.handle);
if (item) {
await treeView.reveal(item);
if (select) {
@@ -91,13 +95,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
let itemsToExpand = [item];
for (; itemsToExpand.length > 0 && expand > 0; expand--) {
await treeView.expand(itemsToExpand);
itemsToExpand = itemsToExpand.reduce((result, item) => {
item = dataProvider.getItem(item.handle);
itemsToExpand = itemsToExpand.reduce((result, itemValue) => {
const item = dataProvider.getItem(itemValue.handle);
if (item && item.children && item.children.length) {
result.push(...item.children);
}
return result;
}, []);
}, [] as ITreeItem[]);
}
}
}
@@ -109,8 +113,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._register(treeView.onDidChangeVisibility(isVisible => this._proxy.$setVisible(treeViewId, isVisible)));
}
private getTreeView(treeViewId: string): ITreeView {
const viewDescriptor: ITreeViewDescriptor = <ITreeViewDescriptor>ViewsRegistry.getView(treeViewId);
private getTreeView(treeViewId: string): ITreeView | null {
const viewDescriptor: ITreeViewDescriptor = <ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(treeViewId);
return viewDescriptor ? viewDescriptor.treeView : null;
}
@@ -132,13 +136,12 @@ export type TreeItemHandle = string;
// {{SQL CARBON EDIT}}
export class TreeViewDataProvider implements ITreeViewDataProvider {
// {{SQL CARBON EDIT}}
protected itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
private readonly itemsMap: Map<TreeItemHandle, ITreeItem> = new Map<TreeItemHandle, ITreeItem>();
// {{SQL CARBON EDIT}}
constructor(protected treeViewId: string,
protected _proxy: ExtHostTreeViewsShape,
protected notificationService: INotificationService
constructor(protected readonly treeViewId: string,
protected readonly _proxy: ExtHostTreeViewsShape,
private readonly notificationService: INotificationService
) {
}
@@ -178,7 +181,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
return itemsToRefresh;
}
getItem(treeItemHandle: string): ITreeItem {
getItem(treeItemHandle: string): ITreeItem | undefined {
return this.itemsMap.get(treeItemHandle);
}
@@ -198,7 +201,7 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
}
private updateTreeItem(current: ITreeItem, treeItem: ITreeItem): void {
treeItem.children = treeItem.children ? treeItem.children : null;
treeItem.children = treeItem.children ? treeItem.children : undefined;
if (current) {
const properties = distinct([...Object.keys(current), ...Object.keys(treeItem)]);
for (const property of properties) {

View File

@@ -2,84 +2,99 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import * as map from 'vs/base/common/map';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { localize } from 'vs/nls';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/node/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewInsetHandle, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/node/extHost.protocol';
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/shared/editor';
import { WebviewEditor } from 'vs/workbench/parts/webview/electron-browser/webviewEditor';
import { WebviewEditorInput } from 'vs/workbench/parts/webview/electron-browser/webviewEditorInput';
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions, WebviewReviver } from 'vs/workbench/parts/webview/electron-browser/webviewEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { CodeInsetController } from 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution';
import { WebviewEditor } from 'vs/workbench/contrib/webview/electron-browser/webviewEditor';
import { WebviewEditorInput } from 'vs/workbench/contrib/webview/electron-browser/webviewEditorInput';
import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/electron-browser/webviewEditorService';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import * as vscode from 'vscode';
import { extHostNamedCustomer } from './extHostCustomers';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
private static readonly viewType = 'mainThreadWebview';
export class MainThreadWebviews extends Disposable implements MainThreadWebviewsShape {
private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto'];
private static revivalPool = 0;
private _toDispose: IDisposable[] = [];
private readonly _proxy: ExtHostWebviewsShape;
private readonly _webviews = new Map<WebviewPanelHandle, WebviewEditorInput>();
private readonly _revivers = new Set<string>();
private readonly _webviewsElements = new Map<WebviewInsetHandle, WebviewElement>();
private readonly _revivers = new Map<string, IDisposable>();
private _activeWebview: WebviewPanelHandle | undefined = undefined;
constructor(
context: IExtHostContext,
@ILifecycleService lifecycleService: ILifecycleService,
@IExtensionService extensionService: IExtensionService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IEditorService private readonly _editorService: IEditorService,
@IWebviewEditorService private readonly _webviewService: IWebviewEditorService,
@IOpenerService private readonly _openerService: IOpenerService,
@IExtensionService private readonly _extensionService: IExtensionService,
@ITelemetryService private readonly _telemetryService: ITelemetryService
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
) {
super();
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose);
_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose);
this._toDispose.push(_webviewService.registerReviver(MainThreadWebviews.viewType, this));
// This reviver's only job is to activate webview extensions
// This should trigger the real reviver to be registered from the extension host side.
this._toDispose.push(_webviewService.registerReviver({
canRevive: (webview) => {
const viewType = webview.state.viewType;
if (viewType) {
extensionService.activateByEvent(`onWebviewPanel:${viewType}`);
}
return false;
},
reviveWebview: () => { throw new Error('not implemented'); }
}));
lifecycleService.onBeforeShutdown(e => {
e.veto(this._onBeforeShutdown());
}, this, this._toDispose);
}
public dispose(): void {
this._toDispose = dispose(this._toDispose);
}
public $createWebviewPanel(
handle: WebviewPanelHandle,
viewType: string,
title: string,
showOptions: { viewColumn: EditorViewColumn | null, preserveFocus: boolean },
showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean },
options: WebviewInputOptions,
extensionId: ExtensionIdentifier,
extensionLocation: UriComponents
): void {
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
if (showOptions) {
mainThreadShowOptions.preserveFocus = showOptions.preserveFocus;
mainThreadShowOptions.preserveFocus = !!showOptions.preserveFocus;
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
}
const webview = this._webviewService.createWebview(MainThreadWebviews.viewType, title, mainThreadShowOptions, reviveWebviewOptions(options), URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
const webview = this._webviewService.createWebview(this.getInternalWebviewId(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), URI.revive(extensionLocation), this.createWebviewEventDelegate(handle));
webview.state = {
viewType: viewType,
state: undefined
@@ -96,6 +111,44 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value });
}
$createWebviewCodeInset(handle: WebviewInsetHandle, symbolId: string, options: vscode.WebviewOptions, extensionLocation: UriComponents): void {
// todo@joh main is for the lack of a code-inset service
// which we maybe wanna have... this is how it now works
// 1) create webview element
// 2) find the code inset controller that request it
// 3) let the controller adopt the widget
// 4) continue to forward messages to the webview
const webview = this._instantiationService.createInstance(
WebviewElement,
this._layoutService.getContainer(Parts.EDITOR_PART),
{
extensionLocation: URI.revive(extensionLocation),
enableFindWidget: false,
},
{
allowScripts: options.enableScripts,
}
);
let found = false;
for (const editor of this._codeEditorService.listCodeEditors()) {
const ctrl = CodeInsetController.get(editor);
if (ctrl && ctrl.acceptWebview(symbolId, webview)) {
found = true;
break;
}
}
if (!found) {
webview.dispose();
return;
}
// this will leak... the adopted webview will be disposed by the
// code inset controller. we might need a dispose-event here so that
// we can clean up things.
this._webviewsElements.set(handle, webview);
}
public $disposeWebview(handle: WebviewPanelHandle): void {
const webview = this.getWebview(handle);
webview.dispose();
@@ -111,14 +164,22 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
webview.iconPath = reviveWebviewIcon(value);
}
public $setHtml(handle: WebviewPanelHandle, value: string): void {
const webview = this.getWebview(handle);
webview.html = value;
public $setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void {
if (typeof handle === 'number') {
this.getWebviewElement(handle).contents = value;
} else {
const webview = this.getWebview(handle);
webview.html = value;
}
}
public $setOptions(handle: WebviewPanelHandle, options: vscode.WebviewOptions): void {
const webview = this.getWebview(handle);
webview.setOptions(reviveWebviewOptions(options));
public $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: vscode.WebviewOptions): void {
if (typeof handle === 'number') {
this.getWebviewElement(handle).options = reviveWebviewOptions(options);
} else {
const webview = this.getWebview(handle);
webview.setOptions(reviveWebviewOptions(options));
}
}
public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void {
@@ -128,69 +189,82 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
}
const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn));
this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.activeGroup, showOptions.preserveFocus);
if (targetGroup) {
this._webviewService.revealWebview(webview, targetGroup || this._editorGroupService.getGroup(webview.group || ACTIVE_GROUP), !!showOptions.preserveFocus);
}
}
public $postMessage(handle: WebviewPanelHandle, message: any): Promise<boolean> {
const webview = this.getWebview(handle);
const editors = this._editorService.visibleControls
.filter(e => e instanceof WebviewEditor)
.map(e => e as WebviewEditor)
.filter(e => e.input.matches(webview));
public $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, message: any): Promise<boolean> {
if (typeof handle === 'number') {
this.getWebviewElement(handle).sendMessage(message);
return Promise.resolve(true);
for (const editor of editors) {
editor.sendMessage(message);
} else {
const webview = this.getWebview(handle);
const editors = this._editorService.visibleControls
.filter(e => e instanceof WebviewEditor)
.map(e => e as WebviewEditor)
.filter(e => e.input!.matches(webview));
for (const editor of editors) {
editor.sendMessage(message);
}
return Promise.resolve(editors.length > 0);
}
return Promise.resolve(editors.length > 0);
}
public $registerSerializer(viewType: string): void {
this._revivers.add(viewType);
}
if (this._revivers.has(viewType)) {
throw new Error(`Reviver for ${viewType} already registered`);
}
public $unregisterSerializer(viewType: string): void {
this._revivers.delete(viewType);
}
this._revivers.set(viewType, this._webviewService.registerReviver({
canRevive: (webview) => {
return webview.state && webview.state.viewType === viewType;
},
reviveWebview: async (webview): Promise<void> => {
const viewType = webview.state.viewType;
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
this._webviews.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
let state = undefined;
if (webview.state.state) {
try {
state = JSON.parse(webview.state.state);
} catch {
// noop
}
}
public reviveWebview(webview: WebviewEditorInput): Promise<void> {
const viewType = webview.state.viewType;
return Promise.resolve(this._extensionService.activateByEvent(`onWebviewPanel:${viewType}`).then(() => {
const handle = 'revival-' + MainThreadWebviews.revivalPool++;
this._webviews.set(handle, webview);
webview._events = this.createWebviewEventDelegate(handle);
let state = undefined;
if (webview.state.state) {
try {
state = JSON.parse(webview.state.state);
} catch {
// noop
await this._proxy.$deserializeWebviewPanel(handle, viewType, webview.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webview.group || ACTIVE_GROUP), webview.options);
} catch (error) {
onUnexpectedError(error);
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
}
}
return this._proxy.$deserializeWebviewPanel(handle, webview.state.viewType, webview.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webview.group), webview.options)
.then(undefined, error => {
onUnexpectedError(error);
webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
});
}));
}
public canRevive(webview: WebviewEditorInput): boolean {
if (webview.isDisposed() || !webview.state) {
return false;
public $unregisterSerializer(viewType: string): void {
const reviver = this._revivers.get(viewType);
if (!reviver) {
throw new Error(`No reviver for ${viewType} registered`);
}
return this._revivers.has(webview.state.viewType) || !!webview.reviver;
reviver.dispose();
this._revivers.delete(viewType);
}
private getInternalWebviewId(viewType: string): string {
return `mainThreadWebview-${viewType}`;
}
private _onBeforeShutdown(): boolean {
this._webviews.forEach((view) => {
if (this.canRevive(view)) {
view.state.state = view.webviewState;
this._webviews.forEach((webview) => {
if (!webview.isDisposed() && webview.state && this._revivers.has(webview.state.viewType)) {
webview.state.state = webview.webviewState;
}
});
return false; // Don't veto shutdown
@@ -201,12 +275,9 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
onDidClickLink: uri => this.onDidClickLink(handle, uri),
onMessage: message => this._proxy.$onMessage(handle, message),
onDispose: () => {
const cleanUp = () => {
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
this._webviews.delete(handle);
};
this._proxy.$onDidDisposeWebviewPanel(handle).then(
cleanUp,
cleanUp);
});
}
};
}
@@ -216,7 +287,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
let newActiveWebview: { input: WebviewEditorInput, handle: WebviewPanelHandle } | undefined = undefined;
if (activeEditor && activeEditor.input instanceof WebviewEditorInput) {
for (const handle of map.keys(this._webviews)) {
const input = this._webviews.get(handle);
const input = this._webviews.get(handle)!;
if (input.matches(activeEditor.input)) {
newActiveWebview = { input, handle };
break;
@@ -229,7 +300,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
active: true,
visible: true,
position: editorGroupToViewColumn(this._editorGroupService, newActiveWebview.input.group)
position: editorGroupToViewColumn(this._editorGroupService, newActiveWebview.input.group || ACTIVE_GROUP)
});
return;
}
@@ -240,8 +311,8 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
if (oldActiveWebview) {
this._proxy.$onDidChangeWebviewPanelViewState(this._activeWebview, {
active: false,
visible: this._editorService.visibleControls.some(editor => editor.input && editor.input.matches(oldActiveWebview)),
position: editorGroupToViewColumn(this._editorGroupService, oldActiveWebview.group),
visible: this._editorService.visibleControls.some(editor => !!editor.input && editor.input.matches(oldActiveWebview)),
position: editorGroupToViewColumn(this._editorGroupService, oldActiveWebview.group || ACTIVE_GROUP),
});
}
}
@@ -251,7 +322,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._proxy.$onDidChangeWebviewPanelViewState(newActiveWebview.handle, {
active: true,
visible: true,
position: editorGroupToViewColumn(this._editorGroupService, activeEditor.group)
position: editorGroupToViewColumn(this._editorGroupService, activeEditor ? activeEditor.group : ACTIVE_GROUP),
});
this._activeWebview = newActiveWebview.handle;
} else {
@@ -263,9 +334,9 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
this._webviews.forEach((input, handle) => {
for (const workbenchEditor of this._editorService.visibleControls) {
if (workbenchEditor.input && workbenchEditor.input.matches(input)) {
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group);
const editorPosition = editorGroupToViewColumn(this._editorGroupService, workbenchEditor.group!);
input.updateGroup(workbenchEditor.group.id);
input.updateGroup(workbenchEditor.group!.id);
this._proxy.$onDidChangeWebviewPanelViewState(handle, {
active: handle === this._activeWebview,
visible: true,
@@ -297,6 +368,14 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
return webview;
}
private getWebviewElement(handle: number): WebviewElement {
const webview = this._webviewsElements.get(handle);
if (!webview) {
throw new Error('Unknown webview handle:' + handle);
}
return webview;
}
private static getDeserializationFailedContents(viewType: string) {
return `<!DOCTYPE html>
<html>

View File

@@ -3,27 +3,26 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { IFolderQuery, IPatternInfo, ISearchConfiguration, ISearchProgressItem, ISearchService, QueryType, IFileQuery, IFileMatch } from 'vs/platform/search/common/search';
import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { QueryBuilder, ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder';
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData } from '../node/extHost.protocol';
import { TextSearchComplete } from 'vscode';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@@ -31,13 +30,13 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
private readonly _toDispose: IDisposable[] = [];
private readonly _activeCancelTokens: { [id: number]: CancellationTokenSource } = Object.create(null);
private readonly _proxy: ExtHostWorkspaceShape;
private readonly _queryBuilder = this._instantiationService.createInstance(QueryBuilder);
constructor(
extHostContext: IExtHostContext,
@ISearchService private readonly _searchService: ISearchService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ITextFileService private readonly _textFileService: ITextFileService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
@IStatusbarService private readonly _statusbarService: IStatusbarService,
@IWindowService private readonly _windowService: IWindowService,
@@ -45,6 +44,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@ILabelService private readonly _labelService: ILabelService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace)));
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose);
}
@@ -102,61 +102,41 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
}
private _onDidChangeWorkspace(): void {
const workspace = this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace();
this._proxy.$acceptWorkspaceData(workspace ? {
configuration: workspace.configuration,
this._proxy.$acceptWorkspaceData(this.getWorkspaceData(this._contextService.getWorkspace()));
}
private getWorkspaceData(workspace: IWorkspace): IWorkspaceData | null {
if (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
return null;
}
return {
configuration: workspace.configuration || undefined,
folders: workspace.folders,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
} : null);
};
}
// --- search ---
$startFileSearch(includePattern: string, _includeFolder: UriComponents, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[]> {
$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
const includeFolder = URI.revive(_includeFolder);
const workspace = this._contextService.getWorkspace();
if (!workspace.folders.length) {
return undefined;
return Promise.resolve(undefined);
}
let folderQueries: IFolderQuery[];
if (includeFolder) {
folderQueries = [{ folder: includeFolder }]; // if base provided, only search in that folder
} else {
folderQueries = workspace.folders.map(folder => ({ folder: folder.uri })); // absolute pattern: search across all folders
}
if (!folderQueries) {
return undefined; // invalid query parameters
}
const ignoreSymlinks = folderQueries.every(folderQuery => {
const folderConfig = this._configurationService.getValue<ISearchConfiguration>({ resource: folderQuery.folder });
return !folderConfig.search.followSymlinks;
});
// TODO replace wth QueryBuilder
folderQueries.forEach(fq => {
fq.ignoreSymlinks = ignoreSymlinks;
});
const query: IFileQuery = {
folderQueries,
type: QueryType.File,
maxResults,
disregardExcludeSettings: excludePatternOrDisregardExcludes === false,
_reason: 'startFileSearch'
};
if (typeof includePattern === 'string') {
query.includePattern = { [includePattern]: true };
}
if (typeof excludePatternOrDisregardExcludes === 'string') {
query.excludePattern = { [excludePatternOrDisregardExcludes]: true };
}
this._searchService.extendQuery(query);
const query = this._queryBuilder.file(
includeFolder ? [includeFolder] : workspace.folders.map(f => f.uri),
{
maxResults,
disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined,
disregardSearchExcludeSettings: true,
disregardIgnoreFiles: true,
includePattern,
excludePattern: typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined,
_reason: 'startFileSearch'
});
return this._searchService.fileSearch(query, token).then(result => {
return result.results.map(m => m.resource);
@@ -172,8 +152,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
const workspace = this._contextService.getWorkspace();
const folders = workspace.folders.map(folder => folder.uri);
const queryBuilder = this._instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.text(pattern, folders, options);
const query = this._queryBuilder.text(pattern, folders, options);
query._reason = 'startTextSearch';
const onProgress = (p: ISearchProgressItem) => {
@@ -203,6 +182,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
const query = queryBuilder.file(folders, {
_reason: 'checkExists',
includePattern: includes.join(', '),
expandPatterns: true,
exists: true
});
@@ -227,7 +207,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
});
}
$resolveProxy(url: string): Promise<string> {
$resolveProxy(url: string): Promise<string | undefined> {
return this._windowService.resolveProxy(url);
}
}
@@ -241,7 +221,7 @@ CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (ac
const runningExtensions = await extensionService.getExtensions();
// If requested extension to disable is running, then reload window with given workspace
if (disableExtensions && runningExtensions.some(runningExtension => disableExtensions.some(id => ExtensionIdentifier.equals(runningExtension.identifier, id)))) {
return windowService.openWindow([URI.file(workspace.fsPath)], { args: { _: [], 'disable-extension': disableExtensions } });
return windowService.openWindow([{ uri: workspace, typeHint: 'file' }], { args: { _: [], 'disable-extension': disableExtensions } });
}
}