mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 17:23:40 -05:00
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:
@@ -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';
|
||||
|
||||
@@ -20,6 +20,6 @@ export class MainThreadCommands implements MainThreadClipboardShape {
|
||||
|
||||
$writeText(value: string): Promise<void> {
|
||||
clipboard.writeText(value);
|
||||
return undefined;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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 => () => {
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 } });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user