Merge remote-tracking branch 'origin/master' into stickyness_api

This commit is contained in:
Alex Dima
2017-05-30 08:25:30 +02:00
2380 changed files with 66103 additions and 72069 deletions

View File

@@ -18,7 +18,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { ExtHostTreeView } from 'vs/workbench/api/node/extHostTreeView';
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
@@ -111,7 +111,7 @@ export function createApiFactory(
const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set<ExtHostDocumentSaveParticipant>(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace)));
const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set<ExtHostEditors>(new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set<ExtHostCommands>(new ExtHostCommands(threadService, extHostHeapService));
const extHostTreeView = col.define(ExtHostContext.ExtHostTreeView).set<ExtHostTreeView>(new ExtHostTreeView(threadService, extHostCommands));
const extHostTreeViews = col.define(ExtHostContext.ExtHostTreeViews).set<ExtHostTreeViews>(new ExtHostTreeViews(threadService, extHostCommands));
const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set<ExtHostConfiguration>(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initData.configuration));
const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set<ExtHostDiagnostics>(new ExtHostDiagnostics(threadService));
const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set<ExtHostLanguageFeatures>(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
@@ -369,8 +369,8 @@ export function createApiFactory(
sampleFunction: proposedApiFunction(extension, () => {
return extHostMessageService.showMessage(Severity.Info, 'Hello Proposed Api!', {}, []);
}),
createTreeView: proposedApiFunction(extension, (providerId: string, provider: vscode.TreeDataProvider<any>): vscode.TreeView<any> => {
return extHostTreeView.createTreeView(providerId, provider);
registerTreeDataProviderForView: proposedApiFunction(extension, (viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable => {
return extHostTreeViews.registerTreeDataProviderForView(viewId, treeDataProvider);
})
};
@@ -448,9 +448,9 @@ export function createApiFactory(
getConfiguration: (section?: string): vscode.WorkspaceConfiguration => {
return extHostConfiguration.getConfiguration(section);
},
registerTaskProvider: proposedApiFunction(extension, (provider: vscode.TaskProvider) => {
registerTaskProvider: (provider: vscode.TaskProvider) => {
return extHostTask.registerTaskProvider(extension, provider);
})
}
};
class SCM {
@@ -515,7 +515,6 @@ export function createApiFactory(
OverviewRulerLane: EditorCommon.OverviewRulerLane,
ParameterInformation: extHostTypes.ParameterInformation,
Position: extHostTypes.Position,
ProgressLocation: extHostTypes.ProgressLocation,
Range: extHostTypes.Range,
Selection: extHostTypes.Selection,
SignatureHelp: extHostTypes.SignatureHelp,
@@ -534,9 +533,10 @@ export function createApiFactory(
Uri: URI,
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
ProgressLocation: extHostTypes.ProgressLocation,
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
ThemeColor: extHostTypes.ThemeColor,
// functions
FileLocationKind: extHostTypes.FileLocationKind,
ApplyToKind: extHostTypes.ApplyToKind,
RevealKind: extHostTypes.RevealKind,
TaskGroup: extHostTypes.TaskGroup,
ShellTask: extHostTypes.ShellTask,

View File

@@ -1,107 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/platform';
import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, InstanceCollection } from './extHost.protocol';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
// --- addressable
import { MainThreadCommands } from './mainThreadCommands';
import { MainThreadConfiguration } from './mainThreadConfiguration';
import { MainThreadDiagnostics } from './mainThreadDiagnostics';
import { MainThreadDocuments } from './mainThreadDocuments';
import { MainThreadEditors } from './mainThreadEditors';
import { MainThreadErrors } from './mainThreadErrors';
import { MainThreadTreeView } from './mainThreadTreeView';
import { MainThreadLanguageFeatures } from './mainThreadLanguageFeatures';
import { MainThreadLanguages } from './mainThreadLanguages';
import { MainThreadMessageService } from './mainThreadMessageService';
import { MainThreadOutputService } from './mainThreadOutputService';
import { MainThreadProgress } from './mainThreadProgress';
import { MainThreadQuickOpen } from './mainThreadQuickOpen';
import { MainThreadStatusBar } from './mainThreadStatusBar';
import { MainThreadStorage } from './mainThreadStorage';
import { MainThreadTelemetry } from './mainThreadTelemetry';
import { MainThreadTerminalService } from './mainThreadTerminalService';
import { MainThreadWorkspace } from './mainThreadWorkspace';
import { MainProcessExtensionService } from './mainThreadExtensionService';
import { MainThreadFileSystemEventService } from './mainThreadFileSystemEventService';
import { MainThreadTask } from './mainThreadTask';
import { MainThreadSCM } from './mainThreadSCM';
// --- other interested parties
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { JSONValidationExtensionPoint } from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
import { LanguageConfigurationFileHandler } from 'vs/editor/node/languageConfigurationExtensionPoint';
import { SaveParticipant } from './mainThreadSaveParticipant';
// --- registers itself as service
import './mainThreadHeapService';
export class ExtHostContribution implements IWorkbenchContribution {
constructor(
@IThreadService private threadService: IThreadService,
@IInstantiationService private instantiationService: IInstantiationService,
@IExtensionService private extensionService: IExtensionService
) {
this.initExtensionSystem();
}
public getId(): string {
return 'vs.api.extHost';
}
private initExtensionSystem(): void {
const create = <T>(ctor: IConstructorSignature0<T>): T => {
return this.instantiationService.createInstance(ctor);
};
const documentsAndEditors = this.instantiationService.createInstance(MainThreadDocumentsAndEditors);
// Addressable instances
const col = new InstanceCollection();
col.define(MainContext.MainThreadCommands).set(create(MainThreadCommands));
col.define(MainContext.MainThreadConfiguration).set(create(MainThreadConfiguration));
col.define(MainContext.MainThreadDiagnostics).set(create(MainThreadDiagnostics));
col.define(MainContext.MainThreadDocuments).set(this.instantiationService.createInstance(MainThreadDocuments, documentsAndEditors));
col.define(MainContext.MainThreadEditors).set(this.instantiationService.createInstance(MainThreadEditors, documentsAndEditors));
col.define(MainContext.MainThreadErrors).set(create(MainThreadErrors));
col.define(MainContext.MainThreadExplorers).set(create(MainThreadTreeView));
col.define(MainContext.MainThreadLanguageFeatures).set(create(MainThreadLanguageFeatures));
col.define(MainContext.MainThreadLanguages).set(create(MainThreadLanguages));
col.define(MainContext.MainThreadMessageService).set(create(MainThreadMessageService));
col.define(MainContext.MainThreadOutputService).set(create(MainThreadOutputService));
col.define(MainContext.MainThreadProgress).set(create(MainThreadProgress));
col.define(MainContext.MainThreadQuickOpen).set(create(MainThreadQuickOpen));
col.define(MainContext.MainThreadStatusBar).set(create(MainThreadStatusBar));
col.define(MainContext.MainThreadStorage).set(create(MainThreadStorage));
col.define(MainContext.MainThreadTelemetry).set(create(MainThreadTelemetry));
col.define(MainContext.MainThreadTerminalService).set(create(MainThreadTerminalService));
col.define(MainContext.MainThreadWorkspace).set(create(MainThreadWorkspace));
col.define(MainContext.MainThreadSCM).set(create(MainThreadSCM));
col.define(MainContext.MainThreadTask).set(create(MainThreadTask));
if (this.extensionService instanceof MainProcessExtensionService) {
col.define(MainContext.MainProcessExtensionService).set(<MainProcessExtensionService>this.extensionService);
}
col.finish(true, this.threadService);
// Other interested parties
create(JSONValidationExtensionPoint);
this.instantiationService.createInstance(LanguageConfigurationFileHandler);
create(MainThreadFileSystemEventService);
create(SaveParticipant);
}
}
// Register File Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
ExtHostContribution
);

View File

@@ -35,14 +35,15 @@ import { IWorkspaceConfigurationValues } from 'vs/workbench/services/configurati
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { IApplyEditsOptions, IUndoStopOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditor';
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { InternalTreeNodeContent } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import { TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorModel';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
export interface IEnvironment {
enableProposedApiForAll: boolean;
@@ -134,6 +135,44 @@ export abstract class MainThreadDocumentsShape {
$trySaveDocument(uri: URI): TPromise<boolean> { throw ni(); }
}
export interface ISelectionChangeEvent {
selections: Selection[];
source?: string;
}
export interface ITextEditorConfigurationUpdate {
tabSize?: number | 'auto';
insertSpaces?: boolean | 'auto';
cursorStyle?: TextEditorCursorStyle;
lineNumbers?: TextEditorLineNumbersStyle;
}
export interface IResolvedTextEditorConfiguration {
tabSize: number;
insertSpaces: boolean;
cursorStyle: TextEditorCursorStyle;
lineNumbers: TextEditorLineNumbersStyle;
}
export enum TextEditorRevealType {
Default = 0,
InCenter = 1,
InCenterIfOutsideViewport = 2,
AtTop = 3
}
export interface IUndoStopOptions {
undoStopBefore: boolean;
undoStopAfter: boolean;
}
export interface IApplyEditsOptions extends IUndoStopOptions {
setEndOfLine: EndOfLine;
}
export interface ITextDocumentShowOptions {
position?: EditorPosition;
preserveFocus?: boolean;
@@ -155,14 +194,17 @@ export abstract class MainThreadEditorsShape {
$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]> { throw ni(); }
}
export abstract class MainThreadTreeViewShape {
$registerTreeDataProvider(providerId: string): void { throw ni(); }
$refresh(providerId: string, node: InternalTreeNodeContent): void { throw ni(); }
export interface TreeItem extends vscode.TreeItem {
handle: number;
commandId?: string;
icon?: string;
iconDark?: string;
children?: TreeItem[];
}
export abstract class MainThreadTreeShape {
$registerTreeExplorerNodeProvider(providerId: string, node: InternalTreeNodeContent): void { throw ni(); }
$refresh(providerId: string, node: InternalTreeNodeContent): void { throw ni(); }
export abstract class MainThreadTreeViewsShape {
$registerView(treeViewId: string): void { throw ni(); }
$refresh(treeViewId: string, treeItemHandle?: number): void { throw ni(); }
}
export abstract class MainThreadErrorsShape {
@@ -235,7 +277,7 @@ export abstract class MainThreadQuickOpenShape {
}
export abstract class MainThreadStatusBarShape {
$setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string, alignment: MainThreadStatusBarAlignment, priority: number): void { throw ni(); }
$setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string | editorCommon.ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { throw ni(); }
$dispose(id: number) { throw ni(); }
}
@@ -295,6 +337,7 @@ export abstract class MainThreadSCMShape {
$registerGroup(sourceControlHandle: number, handle: number, id: string, label: string): void { throw ni(); }
$updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): void { throw ni(); }
$updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void { throw ni(); }
$updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void { throw ni(); }
$unregisterGroup(sourceControlHandle: number, handle: number): void { throw ni(); }
@@ -328,8 +371,7 @@ export abstract class ExtHostDocumentsShape {
$provideTextDocumentContent(handle: number, uri: URI): TPromise<string> { throw ni(); }
$acceptModelModeChanged(strURL: string, oldModeId: string, newModeId: string): void { throw ni(); }
$acceptModelSaved(strURL: string): void { throw ni(); }
$acceptModelDirty(strURL: string): void { throw ni(); }
$acceptModelReverted(strURL: string): void { throw ni(); }
$acceptDirtyStateChanged(strURL: string, isDirty: boolean): void { throw ni(); }
$acceptModelChanged(strURL: string, e: IModelChangedEvent, isDirty: boolean): void { throw ni(); }
}
@@ -365,20 +407,18 @@ export abstract class ExtHostDocumentsAndEditorsShape {
$acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void { throw ni(); }
}
export type TreeViewCommandArg = {
treeViewId: string,
treeItemHandle: number
};
export abstract class ExtHostTreeViewShape {
$provideRootNode(providerId: string): TPromise<InternalTreeNodeContent> { throw ni(); };
$resolveChildren(providerId: string, node: InternalTreeNodeContent): TPromise<InternalTreeNodeContent[]> { throw ni(); }
$getInternalCommand(providerId: string, node: InternalTreeNodeContent): TPromise<modes.Command> { throw ni(); }
}
export abstract class ExtHostTreeShape {
$resolveChildren(providerId: string, node: InternalTreeNodeContent): TPromise<InternalTreeNodeContent[]> { throw ni(); }
$getInternalCommand(providerId: string, node: InternalTreeNodeContent): TPromise<modes.Command> { throw ni(); }
export abstract class ExtHostTreeViewsShape {
$getElements(treeViewId: string): TPromise<TreeItem[]> { throw ni(); }
$getChildren(treeViewId: string, treeItemHandle: number): TPromise<TreeItem[]> { throw ni(); }
$restore(treeViewId: string, treeItems: TreeItem[]): TPromise<TreeItem[]> { throw ni(); }
}
export abstract class ExtHostExtensionServiceShape {
$localShowMessage(severity: Severity, msg: string): void { throw ni(); }
$activateExtension(extensionDescription: IExtensionDescription): TPromise<void> { throw ni(); }
}
@@ -465,7 +505,7 @@ export const MainContext = {
MainThreadDocuments: createMainId<MainThreadDocumentsShape>('MainThreadDocuments', MainThreadDocumentsShape),
MainThreadEditors: createMainId<MainThreadEditorsShape>('MainThreadEditors', MainThreadEditorsShape),
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors', MainThreadErrorsShape),
MainThreadExplorers: createMainId<MainThreadTreeViewShape>('MainThreadTreeView', MainThreadTreeViewShape),
MainThreadTreeViews: createMainId<MainThreadTreeViewsShape>('MainThreadTreeViews', MainThreadTreeViewsShape),
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures', MainThreadLanguageFeaturesShape),
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages', MainThreadLanguagesShape),
MainThreadMessageService: createMainId<MainThreadMessageServiceShape>('MainThreadMessageService', MainThreadMessageServiceShape),
@@ -490,7 +530,7 @@ export const ExtHostContext = {
ExtHostDocuments: createExtId<ExtHostDocumentsShape>('ExtHostDocuments', ExtHostDocumentsShape),
ExtHostDocumentSaveParticipant: createExtId<ExtHostDocumentSaveParticipantShape>('ExtHostDocumentSaveParticipant', ExtHostDocumentSaveParticipantShape),
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors', ExtHostEditorsShape),
ExtHostTreeView: createExtId<ExtHostTreeViewShape>('ExtHostTreeView', ExtHostTreeViewShape),
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews', ExtHostTreeViewsShape),
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService', ExtHostFileSystemEventServiceShape),
ExtHostHeapService: createExtId<ExtHostHeapServiceShape>('ExtHostHeapMonitor', ExtHostHeapServiceShape),
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures', ExtHostLanguageFeaturesShape),

View File

@@ -12,6 +12,7 @@ import Severity from 'vs/base/common/severity';
import * as vscode from 'vscode';
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape } from './extHost.protocol';
import { DiagnosticSeverity } from './extHostTypes';
import { stableSort } from 'vs/base/common/arrays';
export class DiagnosticCollection implements vscode.DiagnosticCollection {
@@ -74,13 +75,10 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
toSync = [];
let lastUri: vscode.Uri;
// ensure stable-sort: keep the original
// index for otherwise equal items
const sortedTuples = first
.map((tuple, idx) => ({ tuple, idx }))
.sort(DiagnosticCollection._compareIndexedTuplesByUri);
// ensure stable-sort
stableSort(first, DiagnosticCollection._compareIndexedTuplesByUri);
for (const { tuple } of sortedTuples) {
for (const tuple of first) {
const [uri, diagnostics] = tuple;
if (!lastUri || uri.toString() !== lastUri.toString()) {
if (lastUri && this._data.get(lastUri.toString()).length === 0) {
@@ -208,14 +206,10 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
}
}
private static _compareIndexedTuplesByUri(a: { tuple: [vscode.Uri, vscode.Diagnostic[]]; idx: number }, b: { tuple: [vscode.Uri, vscode.Diagnostic[]]; idx: number }): number {
if (a.tuple[0].toString() < b.tuple[0].toString()) {
private static _compareIndexedTuplesByUri(a: [vscode.Uri, vscode.Diagnostic[]], b: [vscode.Uri, vscode.Diagnostic[]]): number {
if (a[0].toString() < b[0].toString()) {
return -1;
} else if (a.tuple[0].toString() > b.tuple[0].toString()) {
return 1;
} else if (a.idx < b.idx) {
return -1;
} else if (a.idx > b.idx) {
} else if (a[0].toString() > b[0].toString()) {
return 1;
} else {
return 0;

View File

@@ -242,9 +242,17 @@ export class ExtHostDocumentData extends MirrorModel {
private _getWordRangeAtPosition(_position: vscode.Position, regexp?: RegExp): vscode.Range {
let position = this._validatePosition(_position);
if (!regexp || regExpLeadsToEndlessLoop(regexp)) {
if (!regexp) {
// use default when custom-regexp isn't provided
regexp = getWordDefinitionFor(this._languageId);
} else if (regExpLeadsToEndlessLoop(regexp)) {
// use default when custom-regexp is bad
console.warn(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`);
regexp = getWordDefinitionFor(this._languageId);
}
let wordAtText = getWordAtText(
position.character + 1,
ensureValidWordDefinition(regexp),

View File

@@ -171,18 +171,17 @@ export class ExtHostDocuments extends ExtHostDocumentsShape {
public $acceptModelSaved(strURL: string): void {
let data = this._documentsAndEditors.getDocument(strURL);
data._acceptIsDirty(false);
this.$acceptDirtyStateChanged(strURL, false);
this._onDidSaveDocument.fire(data.document);
}
public $acceptModelDirty(strURL: string): void {
let document = this._documentsAndEditors.getDocument(strURL);
document._acceptIsDirty(true);
}
public $acceptModelReverted(strURL: string): void {
let document = this._documentsAndEditors.getDocument(strURL);
document._acceptIsDirty(false);
public $acceptDirtyStateChanged(strURL: string, isDirty: boolean): void {
let data = this._documentsAndEditors.getDocument(strURL);
data._acceptIsDirty(isDirty);
this._onDidChangeDocument.fire({
document: data.document,
contentChanges: []
});
}
public $acceptModelChanged(strURL: string, events: IModelChangedEvent, isDirty: boolean): void {

View File

@@ -33,13 +33,13 @@ class FileSystemWatcher implements _FileSystemWatcher {
constructor(dispatcher: Event<FileSystemEvents>, globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) {
this._config = 0;
if (!ignoreCreateEvents) {
if (ignoreCreateEvents) {
this._config += 0b001;
}
if (!ignoreChangeEvents) {
if (ignoreChangeEvents) {
this._config += 0b010;
}
if (!ignoreDeleteEvents) {
if (ignoreDeleteEvents) {
this._config += 0b100;
}

View File

@@ -554,7 +554,7 @@ class SuggestAdapter {
}
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range): modes.ISuggestion {
if (!item.label) {
if (typeof item.label !== 'string' || item.label.length === 0) {
console.warn('INVALID text edit -> must have at least a label');
return undefined;
}

View File

@@ -81,6 +81,11 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
return this._label;
}
set label(label: string) {
this._label = label;
this._proxy.$updateGroupLabel(this._sourceControlHandle, this._handle, label);
}
private _hideWhenEmpty: boolean | undefined = undefined;
get hideWhenEmpty(): boolean | undefined {

View File

@@ -6,7 +6,7 @@
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable } from './extHostTypes';
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
import { StatusBarItem, StatusBarAlignment } from 'vscode';
import { MainContext, MainThreadStatusBarShape } from './extHost.protocol';
@@ -21,7 +21,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
private _text: string;
private _tooltip: string;
private _color: string;
private _color: string | ThemeColor;
private _command: string;
private _timeoutHandle: number;
@@ -57,7 +57,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
return this._tooltip;
}
public get color(): string {
public get color(): string | ThemeColor {
return this._color;
}
@@ -75,7 +75,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
this.update();
}
public set color(color: string) {
public set color(color: string | ThemeColor) {
this._color = color;
this.update();
}

View File

@@ -8,13 +8,11 @@ import { TPromise } from 'vs/base/common/winjs.base';
import * as UUID from 'vs/base/common/uuid';
import { asWinJsPromise } from 'vs/base/common/async';
import * as Problems from 'vs/platform/markers/common/problemMatcher';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as TaskSystem from 'vs/workbench/parts/tasks/common/tasks';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, MainThreadTaskShape, ExtHostTaskShape } from 'vs/workbench/api/node/extHost.protocol';
import { fromDiagnosticSeverity } from 'vs/workbench/api/node/extHostTypeConverters';
import * as types from 'vs/workbench/api/node/extHostTypes';
import * as vscode from 'vscode';
@@ -23,6 +21,7 @@ interface StringMap<V> {
[key: string]: V;
}
/*
namespace ProblemPattern {
export function from(value: vscode.ProblemPattern | vscode.MultiLineProblemPattern): Problems.ProblemPattern | Problems.MultiLineProblemPattern {
if (value === void 0 || value === null) {
@@ -144,7 +143,7 @@ namespace WatchingPattern {
}
}
namespace WathingMatcher {
namespace BackgroundMonitor {
export function from(value: vscode.BackgroundMonitor): Problems.WatchingMatcher {
if (value === void 0 || value === null) {
return undefined;
@@ -159,13 +158,13 @@ namespace WathingMatcher {
}
namespace ProblemMatcher {
export function from(values: vscode.ProblemMatcher[]): Problems.ProblemMatcher[] {
export function from(values: (string | vscode.ProblemMatcher)[]): (string | Problems.ProblemMatcher)[] {
if (values === void 0 || values === null) {
return undefined;
}
let result: Problems.ProblemMatcher[];
let result: (string | Problems.ProblemMatcher)[] = [];
for (let value of values) {
let converted = fromSingle(value);
let converted = typeof value === 'string' ? value : fromSingle(value);
if (converted) {
result.push(converted);
}
@@ -186,33 +185,33 @@ namespace ProblemMatcher {
filePrefix: location.prefix,
pattern: ProblemPattern.from(problemMatcher.pattern),
severity: fromDiagnosticSeverity(problemMatcher.severity),
};
return result;
}
}
*/
namespace RevealKind {
export function from(value: vscode.RevealKind): TaskSystem.ShowOutput {
export function from(value: vscode.RevealKind): TaskSystem.RevealKind {
if (value === void 0 || value === null) {
return TaskSystem.ShowOutput.Always;
return TaskSystem.RevealKind.Always;
}
switch (value) {
case types.RevealKind.Silent:
return TaskSystem.ShowOutput.Silent;
return TaskSystem.RevealKind.Silent;
case types.RevealKind.Never:
return TaskSystem.ShowOutput.Never;
return TaskSystem.RevealKind.Never;
}
return TaskSystem.ShowOutput.Always;
return TaskSystem.RevealKind.Always;
}
}
namespace TerminalBehaviour {
export function from(value: vscode.TerminalBehaviour): { showOutput: TaskSystem.ShowOutput, echo: boolean } {
export function from(value: vscode.TerminalBehaviour): TaskSystem.TerminalBehavior {
if (value === void 0 || value === null) {
return { showOutput: TaskSystem.ShowOutput.Always, echo: false };
return { reveal: TaskSystem.RevealKind.Always, echo: false };
}
return { showOutput: RevealKind.from(value.reveal), echo: !!value.echo };
return { reveal: RevealKind.from(value.reveal), echo: !!value.echo };
}
}
@@ -231,7 +230,10 @@ namespace Strings {
}
namespace CommandOptions {
export function from(value: { cwd?: string; env?: { [key: string]: string; } }): TaskSystem.CommandOptions {
function isShellOptions(value: any): value is vscode.ShellOptions {
return value && typeof value.executable === 'string';
}
export function from(value: vscode.ShellOptions | vscode.ProcessOptions): TaskSystem.CommandOptions {
if (value === void 0 || value === null) {
return undefined;
}
@@ -249,14 +251,17 @@ namespace CommandOptions {
}
});
}
if (isShellOptions(value)) {
result.shell = ShellConfiguration.from(value);
}
return result;
}
}
namespace ShellConfiguration {
export function from(value: { executable?: string, args?: string[] }): boolean | TaskSystem.ShellConfiguration {
if (value === void 0 || value === null || typeof value.executable !== 'string') {
return true;
export function from(value: { executable?: string, args?: string[] }): TaskSystem.ShellConfiguration {
if (value === void 0 || value === null || !value.executable) {
return undefined;
}
let result: TaskSystem.ShellConfiguration = {
@@ -269,7 +274,7 @@ namespace ShellConfiguration {
namespace Tasks {
export function from(tasks: vscode.Task[], uuidMap: UUIDMap): TaskSystem.Task[] {
export function from(tasks: vscode.Task[], extension: IExtensionDescription, uuidMap: UUIDMap): TaskSystem.Task[] {
if (tasks === void 0 || tasks === null) {
return [];
}
@@ -277,7 +282,7 @@ namespace Tasks {
try {
uuidMap.start();
for (let task of tasks) {
let converted = fromSingle(task, uuidMap);
let converted = fromSingle(task, extension, uuidMap);
if (converted) {
result.push(converted);
}
@@ -288,7 +293,7 @@ namespace Tasks {
return result;
}
function fromSingle(task: vscode.Task, uuidMap: UUIDMap): TaskSystem.Task {
function fromSingle(task: vscode.Task, extension: IExtensionDescription, uuidMap: UUIDMap): TaskSystem.Task {
if (typeof task.name !== 'string' || typeof task.identifier !== 'string') {
return undefined;
}
@@ -303,18 +308,20 @@ namespace Tasks {
if (command === void 0) {
return undefined;
}
let behaviour = TerminalBehaviour.from(task.terminal);
command.echo = behaviour.echo;
let result: TaskSystem.Task = {
_id: uuidMap.getUUID(task.identifier),
_source: {
kind: TaskSystem.TaskSourceKind.Extension,
label: typeof task.source === 'string' ? task.source : extension.name,
detail: extension.id
},
name: task.name,
identifier: task.identifier,
identifier: task.identifier ? task.identifier : `${extension.id}.${task.name}`,
group: types.TaskGroup.is(task.group) ? task.group : undefined,
command: command,
showOutput: behaviour.showOutput,
isBackground: !!task.isBackground,
suppressTaskName: true,
problemMatchers: ProblemMatcher.from(task.problemMatchers)
problemMatchers: task.problemMatchers.slice()
};
return result;
}
@@ -326,8 +333,8 @@ namespace Tasks {
let result: TaskSystem.CommandConfiguration = {
name: value.process,
args: Strings.from(value.args),
isShellCommand: false,
echo: false,
type: TaskSystem.CommandType.Process,
terminal: TerminalBehaviour.from(value.terminal)
};
if (value.options) {
result.options = CommandOptions.from(value.options);
@@ -341,8 +348,8 @@ namespace Tasks {
}
let result: TaskSystem.CommandConfiguration = {
name: value.commandLine,
isShellCommand: ShellConfiguration.from(value.options),
echo: false
type: TaskSystem.CommandType.Shell,
terminal: TerminalBehaviour.from(value.terminal)
};
if (value.options) {
result.options = CommandOptions.from(value.options);
@@ -422,7 +429,7 @@ export class ExtHostTask extends ExtHostTaskShape {
}
return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => {
return {
tasks: Tasks.from(value, this.getUUIDMap(handler.extension.id)),
tasks: Tasks.from(value, handler.extension, this.getUUIDMap(handler.extension.id)),
extension: handler.extension
};
});

View File

@@ -12,9 +12,8 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/editorCommon';
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditor';
import * as TypeConverters from './extHostTypeConverters';
import { MainThreadEditorsShape } from './extHost.protocol';
import { MainThreadEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol';
import * as vscode from 'vscode';
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { IRange } from 'vs/editor/common/core/range';

View File

@@ -10,11 +10,11 @@ import { toThenable } from 'vs/base/common/async';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { TextEditorSelectionChangeKind } from './extHostTypes';
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent } from 'vs/workbench/api/node/mainThreadEditor';
import * as TypeConverters from './extHostTypeConverters';
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData } from './extHost.protocol';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './extHost.protocol';
import * as vscode from 'vscode';
export class ExtHostEditors extends ExtHostEditorsShape {
@@ -74,6 +74,7 @@ export class ExtHostEditors extends ExtHostEditorsShape {
};
} else {
options = {
position: EditorPosition.ONE,
preserveFocus: false,
pinned: true
};

View File

@@ -1,162 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { localize } from 'vs/nls';
import { TreeView, TreeDataProvider } from 'vscode';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, ExtHostTreeViewShape, MainThreadTreeViewShape } from './extHost.protocol';
import { InternalTreeNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
import * as modes from 'vs/editor/common/modes';
class InternalTreeNodeImpl implements InternalTreeNode {
readonly id: string;
label: string;
hasChildren: boolean;
clickCommand: string = null;
constructor(readonly providerId: string, node: any, provider: TreeDataProvider<any>) {
this.id = defaultGenerator.nextId();
this.label = provider.getLabel ? provider.getLabel(node) : node.toString();
this.hasChildren = provider.getHasChildren ? provider.getHasChildren(node) : true;
if (provider.getClickCommand) {
const command = provider.getClickCommand(node);
if (command) {
this.clickCommand = command.command;
}
}
}
}
export class ExtHostTreeView extends ExtHostTreeViewShape {
private _proxy: MainThreadTreeViewShape;
private _extNodeProviders: { [providerId: string]: TreeDataProvider<any> };
private _extViews: Map<string, TreeView<any>> = new Map<string, TreeView<any>>();
private _extNodeMaps: { [providerId: string]: { [id: string]: InternalTreeNode } };
private _mainNodesMap: Map<string, Map<any, InternalTreeNode>>;
private _childrenNodesMap: Map<string, Map<any, any[]>>;
constructor(
threadService: IThreadService,
private commands: ExtHostCommands
) {
super();
this._proxy = threadService.get(MainContext.MainThreadExplorers);
this._extNodeProviders = Object.create(null);
this._extNodeMaps = Object.create(null);
this._mainNodesMap = new Map<string, Map<any, InternalTreeNode>>();
this._childrenNodesMap = new Map<string, Map<any, any[]>>();
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.providerId && arg.id) {
const extNodeMap = this._extNodeMaps[arg.providerId];
return extNodeMap[arg.id];
}
return arg;
}
});
}
createTreeView<T>(providerId: string, provider: TreeDataProvider<T>): TreeView<T> {
this._proxy.$registerTreeDataProvider(providerId);
this._extNodeProviders[providerId] = provider;
this._mainNodesMap.set(providerId, new Map<any, InternalTreeNode>());
this._childrenNodesMap.set(providerId, new Map<any, any>());
const treeView: TreeView<T> = {
refresh: (node: T) => {
const mainThreadNode = this._mainNodesMap.get(providerId).get(node);
this._proxy.$refresh(providerId, mainThreadNode);
},
dispose: () => {
delete this._extNodeProviders[providerId];
delete this._extNodeProviders[providerId];
this._mainNodesMap.delete(providerId);
this._childrenNodesMap.delete(providerId);
this._extViews.delete(providerId);
}
};
this._extViews.set(providerId, treeView);
return treeView;
}
$provideRootNode(providerId: string): TPromise<InternalTreeNode> {
const provider = this._extNodeProviders[providerId];
if (!provider) {
const errMessage = localize('treeExplorer.notRegistered', 'No TreeExplorerNodeProvider with id \'{0}\' registered.', providerId);
return TPromise.wrapError<InternalTreeNode>(errMessage);
}
return asWinJsPromise(() => provider.provideRootNode()).then(extRootNode => {
const extNodeMap: { [id: string]: InternalTreeNode } = Object.create(null);
const internalRootNode = new InternalTreeNodeImpl(providerId, extRootNode, provider);
extNodeMap[internalRootNode.id] = extRootNode;
this._extNodeMaps[providerId] = extNodeMap;
this._mainNodesMap.get(providerId).set(extRootNode, internalRootNode);
return internalRootNode;
}, err => {
const errMessage = localize('treeExplorer.failedToProvideRootNode', 'TreeExplorerNodeProvider \'{0}\' failed to provide root node.', providerId);
return TPromise.wrapError<InternalTreeNode>(errMessage);
});
}
$resolveChildren(providerId: string, mainThreadNode: InternalTreeNode): TPromise<InternalTreeNode[]> {
const provider = this._extNodeProviders[providerId];
if (!provider) {
const errMessage = localize('treeExplorer.notRegistered', 'No TreeExplorerNodeProvider with id \'{0}\' registered.', providerId);
return TPromise.wrapError<InternalTreeNode[]>(errMessage);
}
const extNodeMap = this._extNodeMaps[providerId];
const extNode = extNodeMap[mainThreadNode.id];
const currentChildren = this._childrenNodesMap.get(providerId).get(extNode);
if (currentChildren) {
for (const child of currentChildren) {
this._mainNodesMap.get(providerId).delete(child);
}
}
return asWinJsPromise(() => provider.resolveChildren(extNode)).then(children => {
return children.map(extChild => {
const internalChild = new InternalTreeNodeImpl(providerId, extChild, provider);
extNodeMap[internalChild.id] = extChild;
this._mainNodesMap.get(providerId).set(extChild, internalChild);
return internalChild;
});
});
}
// Convert the command on the ExtHost side so we can pass the original externalNode to the registered handler
$getInternalCommand(providerId: string, mainThreadNode: InternalTreeNode): TPromise<modes.Command> {
const commandConverter = this.commands.converter;
if (mainThreadNode.clickCommand) {
const extNode = this._extNodeMaps[providerId][mainThreadNode.id];
const internalCommand = commandConverter.toInternal({
title: '',
command: mainThreadNode.clickCommand,
arguments: [extNode]
});
return TPromise.wrap(internalCommand);
}
return TPromise.as(null);
}
}

View File

@@ -0,0 +1,213 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { localize } from 'vs/nls';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { MainContext, ExtHostTreeViewsShape, MainThreadTreeViewsShape, TreeItem, TreeViewCommandArg } from './extHost.protocol';
import { TreeItemCollapsibleState } from './extHostTypes';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
import * as modes from 'vs/editor/common/modes';
type TreeItemHandle = number;
export class ExtHostTreeViews extends ExtHostTreeViewsShape {
private treeViews: Map<string, ExtHostTreeView<any>> = new Map<string, ExtHostTreeView<any>>();
private _proxy: MainThreadTreeViewsShape;
constructor(
threadService: IThreadService,
private commands: ExtHostCommands
) {
super();
this._proxy = threadService.get(MainContext.MainThreadTreeViews);
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.treeViewId && arg.treeItemHandle) {
return this.convertArgument(arg);
}
return arg;
}
});
}
registerTreeDataProviderForView<T>(id: string, treeDataProvider: vscode.TreeDataProvider<T>): vscode.Disposable {
const treeView = new ExtHostTreeView<T>(id, treeDataProvider, this._proxy);
this.treeViews.set(id, treeView);
return {
dispose: () => {
this.treeViews.delete(id);
treeView.dispose();
}
};
}
$getElements(treeViewId: string): TPromise<TreeItem[]> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
return TPromise.wrapError<TreeItem[]>(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
return treeView.getTreeItems();
}
$getChildren(treeViewId: string, treeItemHandle?: number): TPromise<TreeItem[]> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
return TPromise.wrapError<TreeItem[]>(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId));
}
return treeView.getChildren(treeItemHandle);
}
private convertArgument(arg: TreeViewCommandArg): any {
const treeView = this.treeViews.get(arg.treeViewId);
if (!treeView) {
return TPromise.wrapError<modes.Command>(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', arg.treeViewId));
}
return treeView.getExtensionElement(arg.treeItemHandle);
}
}
class ExtHostTreeView<T> extends Disposable {
private _itemHandlePool = 0;
private extElementsMap: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
private itemHandlesMap: Map<T, TreeItemHandle> = new Map<T, TreeItemHandle>();
private extChildrenElementsMap: Map<T, T[]> = new Map<T, T[]>();
constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape) {
super();
this.proxy.$registerView(viewId);
if (dataProvider.onDidChangeTreeData) {
this._register(dataProvider.onDidChangeTreeData(element => this._refresh(element)));
}
}
getTreeItems(): TPromise<TreeItem[]> {
this.extChildrenElementsMap.clear();
this.extElementsMap.clear();
this.itemHandlesMap.clear();
return asWinJsPromise(() => this.dataProvider.getChildren())
.then(elements => this.processAndMapElements(elements));
}
getChildren(treeItemHandle: TreeItemHandle): TPromise<TreeItem[]> {
let extElement = this.getExtensionElement(treeItemHandle);
if (extElement) {
this.clearChildren(extElement);
} else {
return TPromise.wrapError<TreeItem[]>(localize('treeItem.notFound', 'No tree item with id \'{0}\' found.', treeItemHandle));
}
return asWinJsPromise(() => this.dataProvider.getChildren(extElement))
.then(childrenElements => this.processAndMapElements(childrenElements));
}
getExtensionElement(treeItemHandle: TreeItemHandle): T {
return this.extElementsMap.get(treeItemHandle);
}
private _refresh(element: T): void {
if (element) {
const itemHandle = this.itemHandlesMap.get(element);
if (itemHandle) {
this.proxy.$refresh(this.viewId, itemHandle);
}
} else {
this.proxy.$refresh(this.viewId);
}
}
private processAndMapElements(elements: T[]): TPromise<TreeItem[]> {
const treeItemsPromises: TPromise<TreeItem>[] = [];
for (const element of elements) {
if (this.extChildrenElementsMap.has(element)) {
return TPromise.wrapError<TreeItem[]>(localize('treeView.duplicateElement', 'Element {0} is already registered', element));
}
const treeItem = this.massageTreeItem(this.dataProvider.getTreeItem(element));
this.itemHandlesMap.set(element, treeItem.handle);
this.extElementsMap.set(treeItem.handle, element);
if (treeItem.collapsibleState === TreeItemCollapsibleState.Expanded) {
treeItemsPromises.push(this.getChildren(treeItem.handle).then(children => {
treeItem.children = children;
return treeItem;
}));
} else {
treeItemsPromises.push(TPromise.as(treeItem));
}
}
return TPromise.join(treeItemsPromises);
}
private massageTreeItem(extensionTreeItem: vscode.TreeItem): TreeItem {
const icon = this.getLightIconPath(extensionTreeItem);
return {
handle: ++this._itemHandlePool,
label: extensionTreeItem.label,
commandId: extensionTreeItem.command ? extensionTreeItem.command.command : void 0,
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
collapsibleState: extensionTreeItem.collapsibleState,
};
}
private getLightIconPath(extensionTreeItem: vscode.TreeItem) {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
return this.getIconPath(extensionTreeItem.iconPath);
}
return this.getIconPath(extensionTreeItem.iconPath['light']);
}
return void 0;
}
private getDarkIconPath(extensionTreeItem: vscode.TreeItem) {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}
return void 0;
}
private getIconPath(iconPath: string | URI): string {
if (iconPath instanceof URI) {
return iconPath.toString();
}
return URI.file(iconPath).toString();
}
private clearChildren(extElement: T): void {
const children = this.extChildrenElementsMap.get(extElement);
if (children) {
for (const child of children) {
this.clearElement(child);
}
this.extChildrenElementsMap.delete(extElement);
}
}
private clearElement(extElement: T): void {
this.clearChildren(extElement);
const treeItemhandle = this.itemHandlesMap.get(extElement);
this.itemHandlesMap.delete(extElement);
if (treeItemhandle) {
this.extElementsMap.delete(treeItemhandle);
}
}
dispose() {
this.extElementsMap.clear();
this.itemHandlesMap.clear();
this.extChildrenElementsMap.clear();
}
}

View File

@@ -1018,17 +1018,18 @@ export enum RevealKind {
export class BaseTask {
private _name: string;
private _problemMatchers: vscode.ProblemMatcher[];
private _problemMatchers: string[];
private _identifier: string;
private _isBackground: boolean;
private _source: string;
private _group: string;
private _terminal: vscode.TerminalBehaviour;
constructor(name: string, problemMatchers: vscode.ProblemMatcher[]) {
constructor(name: string, problemMatchers: string[]) {
if (typeof name !== 'string') {
throw illegalArgument('name');
}
this._name = name;
this._identifier = name;
this._problemMatchers = problemMatchers || [];
this._isBackground = false;
this._terminal = Object.create(null);
@@ -1039,11 +1040,11 @@ export class BaseTask {
}
set identifier(value: string) {
if (typeof value !== 'string') {
throw illegalArgument('identifier');
if (value === void 0 || value === null) {
this._identifier = undefined;
}
if (value.indexOf(':') !== -1) {
throw illegalArgument('identifier must not contain \':\'');
if (typeof value !== 'string' || value.length === 0) {
throw illegalArgument('identifier must be a string of length > 0');
}
this._identifier = value;
}
@@ -1063,6 +1064,36 @@ export class BaseTask {
this._isBackground = value;
}
get source(): string {
return this._source;
}
set source(value: string) {
if (value === void 0 || value === null) {
this._source = undefined;
return;
}
if (typeof value !== 'string' || value.length === 0) {
throw illegalArgument('source must be a string of length > 0');
}
this._source = value;
}
get group(): string {
return this._group;
}
set group(value: string) {
if (value === void 0 || value === null) {
this._group = undefined;
return;
}
if (typeof value !== 'string' || value.length === 0) {
throw illegalArgument('group must be a string of length > 0');
}
this._group = value;
}
get terminal(): vscode.TerminalBehaviour {
return this._terminal;
}
@@ -1074,11 +1105,11 @@ export class BaseTask {
this._terminal = value;
}
get problemMatchers(): vscode.ProblemMatcher[] {
get problemMatchers(): string[] {
return this._problemMatchers;
}
set problemMatchers(value: vscode.ProblemMatcher[]) {
set problemMatchers(value: string[]) {
if (!Array.isArray(value)) {
value = [];
}
@@ -1086,12 +1117,20 @@ export class BaseTask {
}
}
/*
namespace ProblemMatcher {
export function is(value: any): value is vscode.ProblemMatcher {
let candidate: vscode.ProblemMatcher = value;
return candidate && !!candidate.pattern;
}
}
*/
namespace ShellOptions {
export function is(value: any): value is vscode.ShellOptions {
return value && ((typeof value.executable === 'string') || (typeof value.cwd === 'string') || !!value.env);
}
}
export namespace TaskGroup {
/**
@@ -1114,7 +1153,7 @@ export namespace TaskGroup {
*/
export const Test: 'test' = 'test';
export function is(value: string): value is vscode.TaskGroup {
export function is(value: string): value is string {
return value === Clean || value === Build || value === RebuildAll || value === Test;
}
}
@@ -1123,43 +1162,37 @@ export class ProcessTask extends BaseTask {
private _process: string;
private _args: string[];
private _group: vscode.TaskGroup;
private _options: vscode.ProcessOptions;
private static parseArguments(restArgs: any[]): { args: string[]; options: vscode.ProcessOptions; problemMatchers: vscode.ProblemMatcher[] } {
let args: string[] = [];
let options: vscode.ProcessOptions = undefined;
let problemMatchers: vscode.ProblemMatcher[] = [];
if (!restArgs || restArgs.length === 0) {
return { args, options, problemMatchers };
}
let current: any = restArgs[0];
if (Array.isArray(current)) {
args = current;
restArgs.shift();
current = restArgs[0];
}
if (ProblemMatcher.is(current)) {
problemMatchers = restArgs;
} else if (current) {
options = current;
restArgs.shift();
if (restArgs.length > 0) {
problemMatchers = restArgs;
}
}
return { args, options, problemMatchers };
}
constructor(name: string, process: string, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, args: string[], ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, args: string[], options: vscode.ProcessOptions, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, process: string, ...rest: any[]) {
constructor(name: string, process: string, args?: string[], problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, process: string, args: string[] | undefined, options: vscode.ProcessOptions, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, process: string, arg3?: string[], arg4?: vscode.ProcessOptions | vscode.ProblemMatchers, arg5?: vscode.ProblemMatchers) {
if (typeof process !== 'string') {
throw illegalArgument('process');
}
let { args, options, problemMatchers } = ProcessTask.parseArguments(rest);
super(name, problemMatchers);
let args: string[];
let options: vscode.ProcessOptions;
let problemMatchers: vscode.ProblemMatchers;
args = arg3 || [];
if (arg4) {
if (Array.isArray(arg4) || typeof arg4 === 'string') {
problemMatchers = arg4;
} else {
options = arg4;
}
}
if (arg5 && !problemMatchers) {
problemMatchers = arg5;
}
let pm: string[];
if (problemMatchers && (typeof problemMatchers === 'string')) {
pm = [problemMatchers];
} else if (Array.isArray(problemMatchers)) {
pm = problemMatchers;
}
pm = pm || [];
super(name, pm);
this._process = process;
this._args = args;
this._options = options || Object.create(null);
@@ -1180,17 +1213,6 @@ export class ProcessTask extends BaseTask {
this._args = value;
}
get group(): vscode.TaskGroup {
return this._group;
}
set group(value: vscode.TaskGroup) {
if (!TaskGroup.is(value)) {
throw illegalArgument('group');
}
this._group = value;
}
get options(): vscode.ProcessOptions {
return this._options;
}
@@ -1203,39 +1225,31 @@ export class ProcessTask extends BaseTask {
}
}
export class ShellTask extends BaseTask {
export class ShellTask extends BaseTask implements vscode.ShellTask {
private _commandLine: string;
private _group: vscode.TaskGroup;
private _options: vscode.ShellOptions;
private static parseArguments(restArgs: any[]): { options: vscode.ShellOptions; problemMatchers: vscode.ProblemMatcher[] } {
let options: vscode.ShellOptions = undefined;
let problemMatchers: vscode.ProblemMatcher[] = [];
if (!restArgs || restArgs.length === 0) {
return { options, problemMatchers };
}
let current: any = restArgs[0];
if (current && !ProblemMatcher.is(current)) {
options = current;
restArgs.shift();
current = restArgs[0];
}
if (ProblemMatcher.is(current)) {
problemMatchers = restArgs;
}
return { options, problemMatchers };
}
constructor(name: string, commandLine: string, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, commandLine: string, options: vscode.ShellOptions, ...problemMatchers: vscode.ProblemMatcher[]);
constructor(name: string, commandLine: string, ...rest: any[]) {
constructor(name: string, commandLine: string, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, commandLine: string, options: vscode.ShellOptions, problemMatchers?: vscode.ProblemMatchers);
constructor(name: string, commandLine: string, optionsOrProblemMatchers?: vscode.ShellOptions | vscode.ProblemMatchers, problemMatchers?: vscode.ProblemMatchers) {
if (typeof commandLine !== 'string') {
throw illegalArgument('commandLine');
}
let { options, problemMatchers } = ShellTask.parseArguments(rest);
super(name, problemMatchers);
let options: vscode.ShellOptions = undefined;
let pm: string[];
if (ShellOptions.is(optionsOrProblemMatchers)) {
options = optionsOrProblemMatchers;
} else {
problemMatchers = optionsOrProblemMatchers;
}
if (problemMatchers && (typeof problemMatchers === 'string')) {
pm = [problemMatchers];
} else if (Array.isArray(problemMatchers)) {
pm = problemMatchers;
}
pm = pm || [];
super(name, pm);
this._commandLine = commandLine;
this._options = options || Object.create(null);
}
@@ -1244,17 +1258,6 @@ export class ShellTask extends BaseTask {
return this._commandLine;
}
get group(): vscode.TaskGroup {
return this._group;
}
set group(value: vscode.TaskGroup) {
if (!TaskGroup.is(value)) {
throw illegalArgument('group');
}
this._group = value;
}
get options(): vscode.ShellOptions {
return this._options;
}
@@ -1271,3 +1274,16 @@ export enum ProgressLocation {
SourceControl = 1,
Window = 10,
}
export enum TreeItemCollapsibleState {
None = 0,
Collapsed = 1,
Expanded = 2
}
export class ThemeColor {
id: string;
constructor(id: string) {
this.id = id;
}
}

View File

@@ -1,94 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { IDisposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape } from './extHost.protocol';
export class MainThreadCommands extends MainThreadCommandsShape {
private _disposables: { [id: string]: IDisposable } = Object.create(null);
private _proxy: ExtHostCommandsShape;
constructor(
@IThreadService private _threadService: IThreadService,
@ICommandService private _commandService: ICommandService
) {
super();
this._proxy = this._threadService.get(ExtHostContext.ExtHostCommands);
}
dispose() {
for (let id in this._disposables) {
this._disposables[id].dispose();
}
}
$registerCommand(id: string): TPromise<any> {
this._disposables[id] = CommandsRegistry.registerCommand(id, (accessor, ...args) => this._proxy.$executeContributedCommand(id, ...args));
return undefined;
}
$unregisterCommand(id: string): TPromise<any> {
if (this._disposables[id]) {
this._disposables[id].dispose();
delete this._disposables[id];
}
return undefined;
}
$executeCommand<T>(id: string, args: any[]): Thenable<T> {
return this._commandService.executeCommand<T>(id, ...args);
}
$getCommands(): Thenable<string[]> {
return TPromise.as(Object.keys(CommandsRegistry.getCommands()));
}
}
// --- command doc
CommandsRegistry.registerCommand('_generateCommandsDocumentation', function (accessor) {
return accessor.get(IThreadService).get(ExtHostContext.ExtHostCommands).$getContributedCommandHandlerDescriptions().then(result => {
// add local commands
const commands = CommandsRegistry.getCommands();
for (let id in commands) {
let { description } = commands[id];
if (description) {
result[id] = description;
}
}
// print all as markdown
const all: string[] = [];
for (let id in result) {
all.push('`' + id + '` - ' + _generateMarkdown(result[id]));
}
console.log(all.join('\n'));
});
});
function _generateMarkdown(description: string | ICommandHandlerDescription): string {
if (typeof description === 'string') {
return description;
} else {
let parts = [description.description];
parts.push('\n\n');
if (description.args) {
for (let arg of description.args) {
parts.push(`* _${arg.name}_ ${arg.description || ''}\n`);
}
}
if (description.returns) {
parts.push(`* _(returns)_ ${description.returns}`);
}
parts.push('\n\n');
return parts.join('');
}
}

View File

@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { MainThreadConfigurationShape, ExtHostContext } from './extHost.protocol';
export class MainThreadConfiguration extends MainThreadConfigurationShape {
private _configurationEditingService: IConfigurationEditingService;
private _toDispose: IDisposable;
constructor(
@IConfigurationEditingService configurationEditingService: IConfigurationEditingService,
@IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService,
@IThreadService threadService: IThreadService
) {
super();
this._configurationEditingService = configurationEditingService;
const proxy = threadService.get(ExtHostContext.ExtHostConfiguration);
this._toDispose = configurationService.onDidUpdateConfiguration(() => {
proxy.$acceptConfigurationChanged(configurationService.values());
});
}
public dispose(): void {
this._toDispose = dispose(this._toDispose);
}
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise<void> {
return this._configurationEditingService.writeConfiguration(target, { key, value });
}
$removeConfigurationOption(target: ConfigurationTarget, key: string): TPromise<void> {
return this._configurationEditingService.writeConfiguration(target, { key, value: undefined });
}
}

View File

@@ -1,33 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainThreadDiagnosticsShape } from './extHost.protocol';
export class MainThreadDiagnostics extends MainThreadDiagnosticsShape {
private _markerService: IMarkerService;
constructor( @IMarkerService markerService: IMarkerService) {
super();
this._markerService = markerService;
}
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any> {
for (let entry of entries) {
let [uri, markers] = entry;
this._markerService.changeOne(owner, uri, markers);
}
return undefined;
}
$clear(owner: string): TPromise<any> {
this._markerService.changeAll(owner, undefined);
return undefined;
}
}

View File

@@ -1,293 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { TPromise } from 'vs/base/common/winjs.base';
import { IFileService } from 'vs/platform/files/common/files';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ExtHostContext, MainThreadDocumentsShape, ExtHostDocumentsShape } from './extHost.protocol';
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { ITextSource } from 'vs/editor/common/model/textSource';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ITextEditorModel } from 'vs/workbench/common/editor';
export class BoundModelReferenceCollection {
private _data = new Array<{ length: number, dispose(): void }>();
private _length = 0;
constructor(
private _maxAge: number = 1000 * 60 * 3,
private _maxLength: number = 1024 * 1024 * 80
) {
//
}
dispose(): void {
this._data = dispose(this._data);
}
add(ref: IReference<ITextEditorModel>): void {
let length = ref.object.textEditorModel.getValueLength();
let handle: number;
let entry: { length: number, dispose(): void };
const dispose = () => {
let idx = this._data.indexOf(entry);
if (idx >= 0) {
this._length -= length;
ref.dispose();
clearTimeout(handle);
this._data.splice(idx, 1);
}
};
handle = setTimeout(dispose, this._maxAge);
entry = { length, dispose };
this._data.push(entry);
this._length += length;
this._cleanup();
}
private _cleanup(): void {
while (this._length > this._maxLength) {
this._data[0].dispose();
}
}
}
export class MainThreadDocuments extends MainThreadDocumentsShape {
private _modelService: IModelService;
private _modeService: IModeService;
private _textModelResolverService: ITextModelResolverService;
private _textFileService: ITextFileService;
private _codeEditorService: ICodeEditorService;
private _fileService: IFileService;
private _untitledEditorService: IUntitledEditorService;
private _editorGroupService: IEditorGroupService;
private _toDispose: IDisposable[];
private _modelToDisposeMap: { [modelUrl: string]: IDisposable; };
private _proxy: ExtHostDocumentsShape;
private _modelIsSynced: { [modelId: string]: boolean; };
private _resourceContentProvider: { [handle: number]: IDisposable };
private _modelReferenceCollection = new BoundModelReferenceCollection();
constructor(
documentsAndEditors: MainThreadDocumentsAndEditors,
@IThreadService threadService: IThreadService,
@IModelService modelService: IModelService,
@IModeService modeService: IModeService,
@ITextFileService textFileService: ITextFileService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IFileService fileService: IFileService,
@ITextModelResolverService textModelResolverService: ITextModelResolverService,
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
@IEditorGroupService editorGroupService: IEditorGroupService
) {
super();
this._modelService = modelService;
this._modeService = modeService;
this._textModelResolverService = textModelResolverService;
this._textFileService = textFileService;
this._codeEditorService = codeEditorService;
this._fileService = fileService;
this._untitledEditorService = untitledEditorService;
this._editorGroupService = editorGroupService;
this._proxy = threadService.get(ExtHostContext.ExtHostDocuments);
this._modelIsSynced = {};
this._toDispose = [];
this._toDispose.push(this._modelReferenceCollection);
this._toDispose.push(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
this._toDispose.push(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
modelService.onModelModeChanged(this._onModelModeChanged, this, this._toDispose);
this._toDispose.push(textFileService.models.onModelSaved(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelSaved(e.resource.toString());
}
}));
this._toDispose.push(textFileService.models.onModelReverted(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelReverted(e.resource.toString());
}
}));
this._toDispose.push(textFileService.models.onModelDirty(e => {
if (this._shouldHandleFileEvent(e)) {
this._proxy.$acceptModelDirty(e.resource.toString());
}
}));
this._modelToDisposeMap = Object.create(null);
this._resourceContentProvider = Object.create(null);
}
public dispose(): void {
Object.keys(this._modelToDisposeMap).forEach((modelUrl) => {
this._modelToDisposeMap[modelUrl].dispose();
});
this._modelToDisposeMap = Object.create(null);
this._toDispose = dispose(this._toDispose);
}
private _shouldHandleFileEvent(e: TextFileModelChangeEvent): boolean {
const model = this._modelService.getModel(e.resource);
return model && !model.isTooLargeForHavingARichMode();
}
private _onModelAdded(model: editorCommon.IModel): void {
// Same filter as in mainThreadEditorsTracker
if (model.isTooLargeForHavingARichMode()) {
// don't synchronize too large models
return null;
}
let modelUrl = model.uri;
this._modelIsSynced[modelUrl.toString()] = true;
this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => {
this._proxy.$acceptModelChanged(modelUrl.toString(), e, this._textFileService.isDirty(modelUrl));
});
}
private _onModelModeChanged(event: { model: editorCommon.IModel; oldModeId: string; }): void {
let { model, oldModeId } = event;
let modelUrl = model.uri;
if (!this._modelIsSynced[modelUrl.toString()]) {
return;
}
this._proxy.$acceptModelModeChanged(model.uri.toString(), oldModeId, model.getLanguageIdentifier().language);
}
private _onModelRemoved(modelUrl: string): void {
if (!this._modelIsSynced[modelUrl]) {
return;
}
delete this._modelIsSynced[modelUrl];
this._modelToDisposeMap[modelUrl].dispose();
delete this._modelToDisposeMap[modelUrl];
}
// --- from extension host process
$trySaveDocument(uri: URI): TPromise<boolean> {
return this._textFileService.save(uri);
}
$tryOpenDocument(uri: URI): TPromise<any> {
if (!uri.scheme || !(uri.fsPath || uri.authority)) {
return TPromise.wrapError(`Invalid uri. Scheme and authority or path must be set.`);
}
let promise: TPromise<boolean>;
switch (uri.scheme) {
case 'untitled':
promise = this._handleUnititledScheme(uri);
break;
case 'file':
default:
promise = this._handleAsResourceInput(uri);
break;
}
return promise.then(success => {
if (!success) {
return TPromise.wrapError('cannot open ' + uri.toString());
}
return undefined;
}, err => {
return TPromise.wrapError('cannot open ' + uri.toString() + '. Detail: ' + toErrorMessage(err));
});
}
$tryCreateDocument(options?: { language?: string, content?: string }): TPromise<URI> {
return this._doCreateUntitled(void 0, options ? options.language : void 0, options ? options.content : void 0);
}
private _handleAsResourceInput(uri: URI): TPromise<boolean> {
return this._textModelResolverService.createModelReference(uri).then(ref => {
this._modelReferenceCollection.add(ref);
const result = !!ref.object;
return result;
});
}
private _handleUnititledScheme(uri: URI): TPromise<boolean> {
let asFileUri = uri.with({ scheme: 'file' });
return this._fileService.resolveFile(asFileUri).then(stats => {
// don't create a new file ontop of an existing file
return TPromise.wrapError<boolean>('file already exists on disk');
}, err => this._doCreateUntitled(asFileUri).then(resource => !!resource));
}
private _doCreateUntitled(uri?: URI, modeId?: string, initialValue?: string): TPromise<URI> {
let input = this._untitledEditorService.createOrGet(uri, modeId, initialValue);
return input.resolve(true).then(model => {
if (!this._modelIsSynced[input.getResource().toString()]) {
throw new Error(`expected URI ${input.getResource().toString()} to have come to LIFE`);
}
return this._proxy.$acceptModelDirty(input.getResource().toString()); // mark as dirty
}).then(() => {
return input.getResource();
});
}
// --- virtual document logic
$registerTextContentProvider(handle: number, scheme: string): void {
this._resourceContentProvider[handle] = this._textModelResolverService.registerTextModelContentProvider(scheme, {
provideTextContent: (uri: URI): TPromise<editorCommon.IModel> => {
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
if (typeof value === 'string') {
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
const mode = this._modeService.getOrCreateModeByFilenameOrFirstLine(uri.fsPath, firstLineText);
return this._modelService.createModel(value, mode, uri);
}
return undefined;
});
}
});
}
$unregisterTextContentProvider(handle: number): void {
const registration = this._resourceContentProvider[handle];
if (registration) {
registration.dispose();
delete this._resourceContentProvider[handle];
}
}
$onVirtualDocumentChange(uri: URI, value: ITextSource): void {
const model = this._modelService.getModel(uri);
if (!model) {
return;
}
const raw: ITextSource = {
lines: value.lines,
length: value.length,
BOM: value.BOM,
EOL: value.EOL,
containsRTL: value.containsRTL,
isBasicASCII: value.isBasicASCII,
};
if (!model.equals(raw)) {
model.setValueFromTextSource(raw);
}
}
}

View File

@@ -1,351 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModel, ICommonCodeEditor, isCommonCodeEditor, isCommonDiffEditor } from 'vs/editor/common/editorCommon';
import { compare } from 'vs/base/common/strings';
import { delta } from 'vs/base/common/arrays';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import Event, { Emitter, any } from 'vs/base/common/event';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IModelAddedData, ITextEditorAddData, IDocumentsAndEditorsDelta } from './extHost.protocol';
import { MainThreadTextEditor } from 'vs/workbench/api/node/mainThreadEditor';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Position as EditorPosition, IEditor } from 'vs/platform/editor/common/editor';
namespace cmp {
export function compareModels(a: IModel, b: IModel): number {
return compare(a.uri.toString(), b.uri.toString());
}
export function compareEditors(a: EditorAndModel, b: EditorAndModel): number {
let ret = compare(a.editor.getId(), b.editor.getId());
if (ret === 0) {
ret = compare(a.document.uri.toString(), b.document.uri.toString());
}
return ret;
}
}
class EditorAndModel {
readonly id: string;
constructor(
readonly editor: ICommonCodeEditor,
readonly document: IModel,
) {
this.id = `${editor.getId()},${document.uri.toString()}`;
}
}
class DocumentAndEditorStateDelta {
readonly isEmpty: boolean;
constructor(
readonly removedDocuments: IModel[],
readonly addedDocuments: IModel[],
readonly removedEditors: EditorAndModel[],
readonly addedEditors: EditorAndModel[],
readonly oldActiveEditor: string,
readonly newActiveEditor: string,
) {
this.isEmpty = this.removedDocuments.length === 0
&& this.addedDocuments.length === 0
&& this.removedEditors.length === 0
&& this.addedEditors.length === 0
&& oldActiveEditor === newActiveEditor;
}
toString(): string {
let ret = 'DocumentAndEditorStateDelta\n';
ret += `\tRemoved Documents: [${this.removedDocuments.map(d => d.uri.toString(true)).join(', ')}]\n`;
ret += `\tAdded Documents: [${this.addedDocuments.map(d => d.uri.toString(true)).join(', ')}]\n`;
ret += `\tRemoved Editors: [${this.removedEditors.map(e => e.id).join(', ')}]\n`;
ret += `\tAdded Editors: [${this.addedEditors.map(e => e.id).join(', ')}]\n`;
ret += `\tNew Active Editor: ${this.newActiveEditor}\n`;
return ret;
}
}
class DocumentAndEditorState {
static compute(before: DocumentAndEditorState, after: DocumentAndEditorState): DocumentAndEditorStateDelta {
if (!before) {
return new DocumentAndEditorStateDelta([], after.documents, [], after.editors, undefined, after.activeEditor);
}
const documentDelta = delta(before.documents, after.documents, cmp.compareModels);
const editorDelta = delta(before.editors, after.editors, cmp.compareEditors);
const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;
return new DocumentAndEditorStateDelta(
documentDelta.removed, documentDelta.added,
editorDelta.removed, editorDelta.added,
oldActiveEditor, newActiveEditor
);
}
constructor(
readonly documents: IModel[],
readonly editors: EditorAndModel[],
readonly activeEditor: string,
) {
this.documents = documents.sort(cmp.compareModels);
this.editors = editors.sort(cmp.compareEditors);
}
}
class MainThreadDocumentAndEditorStateComputer {
private _toDispose: IDisposable[] = [];
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
private _onDidChangeState = new Emitter<DocumentAndEditorStateDelta>();
private _currentState: DocumentAndEditorState;
readonly onDidChangeState: Event<DocumentAndEditorStateDelta> = this._onDidChangeState.event;
constructor(
@IModelService private _modelService: IModelService,
@ICodeEditorService private _codeEditorService: ICodeEditorService,
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService
) {
this._modelService.onModelAdded(this._updateState, this, this._toDispose);
this._modelService.onModelRemoved(this._updateState, this, this._toDispose);
this._codeEditorService.onCodeEditorAdd(this._onDidAddEditor, this, this._toDispose);
this._codeEditorService.onCodeEditorRemove(this._onDidRemoveEditor, this, this._toDispose);
// this._updateState();
}
dispose(): void {
this._toDispose = dispose(this._toDispose);
}
private _onDidAddEditor(e: ICommonCodeEditor): void {
const listener = any<any>(
e.onDidChangeModel,
e.onDidFocusEditor,
e.onDidBlurEditor
)(this._updateState, this);
this._toDisposeOnEditorRemove.set(e.getId(), listener);
this._updateState();
}
private _onDidRemoveEditor(e: ICommonCodeEditor): void {
const sub = this._toDisposeOnEditorRemove.get(e.getId());
if (sub) {
this._toDisposeOnEditorRemove.delete(e.getId());
sub.dispose();
this._updateState();
}
}
private _updateState(): void {
// models: ignore too large models
const models = this._modelService.getModels();
for (let i = 0; i < models.length; i++) {
if (models[i].isTooLargeForHavingARichMode()) {
models.splice(i, 1);
i--;
}
}
// editor: only take those that have a not too large model
const editors: EditorAndModel[] = [];
let activeEditor: string = null;
for (const editor of this._codeEditorService.listCodeEditors()) {
const model = editor.getModel();
if (model && !model.isTooLargeForHavingARichMode()
&& !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
) {
const apiEditor = new EditorAndModel(editor, model);
editors.push(apiEditor);
if (editor.isFocused()) {
activeEditor = apiEditor.id;
}
}
}
// active editor: if none of the previous editors had focus we try
// to match the action workbench editor with one of editor we have
// just computed
if (!activeEditor) {
const workbenchEditor = this._workbenchEditorService.getActiveEditor();
if (workbenchEditor) {
const workbenchEditorControl = workbenchEditor.getControl();
let candidate: ICommonCodeEditor;
if (isCommonCodeEditor(workbenchEditorControl)) {
candidate = workbenchEditorControl;
} else if (isCommonDiffEditor(workbenchEditorControl)) {
candidate = workbenchEditorControl.getModifiedEditor();
}
if (candidate) {
for (const { editor, id } of editors) {
if (candidate === editor) {
activeEditor = id;
break;
}
}
}
}
}
// compute new state and compare against old
const newState = new DocumentAndEditorState(models, editors, activeEditor);
const delta = DocumentAndEditorState.compute(this._currentState, newState);
if (!delta.isEmpty) {
this._currentState = newState;
this._onDidChangeState.fire(delta);
}
}
}
export class MainThreadDocumentsAndEditors {
private _toDispose: IDisposable[];
private _proxy: ExtHostDocumentsAndEditorsShape;
private _stateComputer: MainThreadDocumentAndEditorStateComputer;
private _editors = <{ [id: string]: MainThreadTextEditor }>Object.create(null);
private _onTextEditorAdd = new Emitter<MainThreadTextEditor[]>();
private _onTextEditorRemove = new Emitter<string[]>();
private _onDocumentAdd = new Emitter<IModel[]>();
private _onDocumentRemove = new Emitter<string[]>();
readonly onTextEditorAdd: Event<MainThreadTextEditor[]> = this._onTextEditorAdd.event;
readonly onTextEditorRemove: Event<string[]> = this._onTextEditorRemove.event;
readonly onDocumentAdd: Event<IModel[]> = this._onDocumentAdd.event;
readonly onDocumentRemove: Event<string[]> = this._onDocumentRemove.event;
constructor(
@IModelService private _modelService: IModelService,
@ITextFileService private _textFileService: ITextFileService,
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService,
@IThreadService threadService: IThreadService,
@ICodeEditorService codeEditorService: ICodeEditorService,
) {
this._proxy = threadService.get(ExtHostContext.ExtHostDocumentsAndEditors);
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(_modelService, codeEditorService, _workbenchEditorService);
this._toDispose = [
this._stateComputer,
this._stateComputer.onDidChangeState(this._onDelta, this)
];
}
dispose(): void {
this._toDispose = dispose(this._toDispose);
}
private _onDelta(delta: DocumentAndEditorStateDelta): void {
let removedDocuments: string[];
let removedEditors: string[] = [];
let addedEditors: MainThreadTextEditor[] = [];
// removed models
removedDocuments = delta.removedDocuments.map(m => m.uri.toString());
// added editors
for (const apiEditor of delta.addedEditors) {
const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.document,
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService);
this._editors[apiEditor.id] = mainThreadEditor;
addedEditors.push(mainThreadEditor);
}
// removed editors
for (const { id } of delta.removedEditors) {
const mainThreadEditor = this._editors[id];
if (mainThreadEditor) {
mainThreadEditor.dispose();
delete this._editors[id];
removedEditors.push(id);
}
}
let extHostDelta: IDocumentsAndEditorsDelta = Object.create(null);
let empty = true;
if (delta.newActiveEditor !== undefined) {
empty = false;
extHostDelta.newActiveEditor = delta.newActiveEditor;
}
if (removedDocuments.length > 0) {
empty = false;
extHostDelta.removedDocuments = removedDocuments;
}
if (removedEditors.length > 0) {
empty = false;
extHostDelta.removedEditors = removedEditors;
}
if (delta.addedDocuments.length > 0) {
empty = false;
extHostDelta.addedDocuments = delta.addedDocuments.map(m => this._toModelAddData(m));
}
if (delta.addedEditors.length > 0) {
empty = false;
extHostDelta.addedEditors = addedEditors.map(e => this._toTextEditorAddData(e));
}
if (!empty) {
// first update ext host
this._proxy.$acceptDocumentsAndEditorsDelta(extHostDelta);
// second update dependent state listener
this._onDocumentRemove.fire(removedDocuments);
this._onDocumentAdd.fire(delta.addedDocuments);
this._onTextEditorRemove.fire(removedEditors);
this._onTextEditorAdd.fire(addedEditors);
}
}
private _toModelAddData(model: IModel): IModelAddedData {
return {
url: model.uri,
versionId: model.getVersionId(),
lines: model.getLinesContent(),
EOL: model.getEOL(),
modeId: model.getLanguageIdentifier().language,
isDirty: this._textFileService.isDirty(model.uri)
};
}
private _toTextEditorAddData(textEditor: MainThreadTextEditor): ITextEditorAddData {
return {
id: textEditor.getId(),
document: textEditor.getModel().uri,
options: textEditor.getConfiguration(),
selections: textEditor.getSelections(),
editorPosition: this._findEditorPosition(textEditor)
};
}
private _findEditorPosition(editor: MainThreadTextEditor): EditorPosition {
for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
if (editor.matches(workbenchEditor)) {
return workbenchEditor.position;
}
}
return undefined;
}
findTextEditorIdFor(editor: IEditor): string {
for (let id in this._editors) {
if (this._editors[id].matches(editor)) {
return id;
}
}
return undefined;
}
getEditor(id: string): MainThreadTextEditor {
return this._editors[id];
}
}

View File

@@ -1,418 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import EditorCommon = require('vs/editor/common/editorCommon');
import Event, { Emitter } from 'vs/base/common/event';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
import { TextEditorCursorStyle, cursorStyleToString } from 'vs/editor/common/config/editorOptions';
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
export interface ITextEditorConfigurationUpdate {
tabSize?: number | 'auto';
insertSpaces?: boolean | 'auto';
cursorStyle?: TextEditorCursorStyle;
lineNumbers?: TextEditorLineNumbersStyle;
}
export interface IResolvedTextEditorConfiguration {
tabSize: number;
insertSpaces: boolean;
cursorStyle: TextEditorCursorStyle;
lineNumbers: TextEditorLineNumbersStyle;
}
function configurationsEqual(a: IResolvedTextEditorConfiguration, b: IResolvedTextEditorConfiguration) {
if (a && !b || !a && b) {
return false;
}
if (!a && !b) {
return true;
}
return (
a.tabSize === b.tabSize
&& a.insertSpaces === b.insertSpaces
);
}
export interface ISelectionChangeEvent {
selections: Selection[];
source?: string;
}
export interface IFocusTracker {
onGainedFocus(): void;
onLostFocus(): void;
}
export enum TextEditorRevealType {
Default = 0,
InCenter = 1,
InCenterIfOutsideViewport = 2,
AtTop = 3
}
export interface IUndoStopOptions {
undoStopBefore: boolean;
undoStopAfter: boolean;
}
export interface IApplyEditsOptions extends IUndoStopOptions {
setEndOfLine: EndOfLine;
}
/**
* Text Editor that is permanently bound to the same model.
* It can be bound or not to a CodeEditor.
*/
export class MainThreadTextEditor {
private _id: string;
private _model: EditorCommon.IModel;
private _modelService: IModelService;
private _modelListeners: IDisposable[];
private _codeEditor: EditorCommon.ICommonCodeEditor;
private _focusTracker: IFocusTracker;
private _codeEditorListeners: IDisposable[];
private _lastSelection: Selection[];
private _configuration: IResolvedTextEditorConfiguration;
private _onSelectionChanged: Emitter<ISelectionChangeEvent>;
private _onConfigurationChanged: Emitter<IResolvedTextEditorConfiguration>;
constructor(
id: string,
model: EditorCommon.IModel,
codeEditor: EditorCommon.ICommonCodeEditor,
focusTracker: IFocusTracker,
modelService: IModelService
) {
this._id = id;
this._model = model;
this._codeEditor = null;
this._focusTracker = focusTracker;
this._modelService = modelService;
this._codeEditorListeners = [];
this._onSelectionChanged = new Emitter<ISelectionChangeEvent>();
this._onConfigurationChanged = new Emitter<IResolvedTextEditorConfiguration>();
this._lastSelection = [new Selection(1, 1, 1, 1)];
this._modelListeners = [];
this._modelListeners.push(this._model.onDidChangeOptions((e) => {
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
}));
this.setCodeEditor(codeEditor);
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
}
public dispose(): void {
this._model = null;
this._modelListeners = dispose(this._modelListeners);
this._codeEditor = null;
this._codeEditorListeners = dispose(this._codeEditorListeners);
}
public getId(): string {
return this._id;
}
public getModel(): EditorCommon.IModel {
return this._model;
}
public getCodeEditor(): EditorCommon.ICommonCodeEditor {
return this._codeEditor;
}
public hasCodeEditor(codeEditor: EditorCommon.ICommonCodeEditor): boolean {
return (this._codeEditor === codeEditor);
}
public setCodeEditor(codeEditor: EditorCommon.ICommonCodeEditor): void {
if (this.hasCodeEditor(codeEditor)) {
// Nothing to do...
return;
}
this._codeEditorListeners = dispose(this._codeEditorListeners);
this._codeEditor = codeEditor;
if (this._codeEditor) {
// Catch early the case that this code editor gets a different model set and disassociate from this model
this._codeEditorListeners.push(this._codeEditor.onDidChangeModel(() => {
this.setCodeEditor(null);
}));
let forwardSelection = (event?: ICursorSelectionChangedEvent) => {
this._lastSelection = this._codeEditor.getSelections();
this._onSelectionChanged.fire({
selections: this._lastSelection,
source: event && event.source
});
};
this._codeEditorListeners.push(this._codeEditor.onDidChangeCursorSelection(forwardSelection));
if (!Selection.selectionsArrEqual(this._lastSelection, this._codeEditor.getSelections())) {
forwardSelection();
}
this._codeEditorListeners.push(this._codeEditor.onDidFocusEditor(() => {
this._focusTracker.onGainedFocus();
}));
this._codeEditorListeners.push(this._codeEditor.onDidBlurEditor(() => {
this._focusTracker.onLostFocus();
}));
this._codeEditorListeners.push(this._codeEditor.onDidChangeConfiguration(() => {
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
}));
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
}
}
public isVisible(): boolean {
return !!this._codeEditor;
}
public get onSelectionChanged(): Event<ISelectionChangeEvent> {
return this._onSelectionChanged.event;
}
public get onConfigurationChanged(): Event<IResolvedTextEditorConfiguration> {
return this._onConfigurationChanged.event;
}
public getSelections(): Selection[] {
if (this._codeEditor) {
return this._codeEditor.getSelections();
}
return this._lastSelection;
}
public setSelections(selections: ISelection[]): void {
if (this._codeEditor) {
this._codeEditor.setSelections(selections);
return;
}
this._lastSelection = selections.map(Selection.liftSelection);
}
public getConfiguration(): IResolvedTextEditorConfiguration {
return this._configuration;
}
private _setIndentConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
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);
let insertSpaces = creationOpts.insertSpaces;
let tabSize = creationOpts.tabSize;
if (newConfiguration.insertSpaces !== 'auto' && typeof newConfiguration.insertSpaces !== 'undefined') {
insertSpaces = newConfiguration.insertSpaces;
}
if (newConfiguration.tabSize !== 'auto' && typeof newConfiguration.tabSize !== 'undefined') {
tabSize = newConfiguration.tabSize;
}
this._model.detectIndentation(insertSpaces, tabSize);
return;
}
let newOpts: EditorCommon.ITextModelUpdateOptions = {};
if (typeof newConfiguration.insertSpaces !== 'undefined') {
newOpts.insertSpaces = newConfiguration.insertSpaces;
}
if (typeof newConfiguration.tabSize !== 'undefined') {
newOpts.tabSize = newConfiguration.tabSize;
}
this._model.updateOptions(newOpts);
}
public setConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
this._setIndentConfiguration(newConfiguration);
if (!this._codeEditor) {
return;
}
if (newConfiguration.cursorStyle) {
let newCursorStyle = cursorStyleToString(newConfiguration.cursorStyle);
this._codeEditor.updateOptions({
cursorStyle: newCursorStyle
});
}
if (typeof newConfiguration.lineNumbers !== 'undefined') {
let lineNumbers: 'on' | 'off' | 'relative';
switch (newConfiguration.lineNumbers) {
case TextEditorLineNumbersStyle.On:
lineNumbers = 'on';
break;
case TextEditorLineNumbersStyle.Relative:
lineNumbers = 'relative';
break;
default:
lineNumbers = 'off';
}
this._codeEditor.updateOptions({
lineNumbers: lineNumbers
});
}
}
public setDecorations(key: string, ranges: EditorCommon.IDecorationOptions[]): void {
if (!this._codeEditor) {
return;
}
this._codeEditor.setDecorations(key, ranges);
}
public revealRange(range: IRange, revealType: TextEditorRevealType): void {
if (!this._codeEditor) {
return;
}
switch (revealType) {
case TextEditorRevealType.Default:
this._codeEditor.revealRange(range);
break;
case TextEditorRevealType.InCenter:
this._codeEditor.revealRangeInCenter(range);
break;;
case TextEditorRevealType.InCenterIfOutsideViewport:
this._codeEditor.revealRangeInCenterIfOutsideViewport(range);
break;
case TextEditorRevealType.AtTop:
this._codeEditor.revealRangeAtTop(range);
break;
default:
console.warn(`Unknown revealType: ${revealType}`);
break;
}
}
private _readConfiguration(model: EditorCommon.IModel, codeEditor: EditorCommon.ICommonCodeEditor): IResolvedTextEditorConfiguration {
if (model.isDisposed()) {
// shutdown time
return this._configuration;
}
let cursorStyle = this._configuration ? this._configuration.cursorStyle : TextEditorCursorStyle.Line;
let lineNumbers: TextEditorLineNumbersStyle = this._configuration ? this._configuration.lineNumbers : TextEditorLineNumbersStyle.On;
if (codeEditor) {
let codeEditorOpts = codeEditor.getConfiguration();
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
if (codeEditorOpts.viewInfo.renderRelativeLineNumbers) {
lineNumbers = TextEditorLineNumbersStyle.Relative;
} else if (codeEditorOpts.viewInfo.renderLineNumbers) {
lineNumbers = TextEditorLineNumbersStyle.On;
} else {
lineNumbers = TextEditorLineNumbersStyle.Off;
}
}
let indent = model.getOptions();
return {
insertSpaces: indent.insertSpaces,
tabSize: indent.tabSize,
cursorStyle: cursorStyle,
lineNumbers: lineNumbers
};
}
private _setConfiguration(newConfiguration: IResolvedTextEditorConfiguration): void {
if (configurationsEqual(this._configuration, newConfiguration)) {
return;
}
this._configuration = newConfiguration;
this._onConfigurationChanged.fire(this._configuration);
}
public isFocused(): boolean {
if (this._codeEditor) {
return this._codeEditor.isFocused();
}
return false;
}
public matches(editor: IEditor): boolean {
if (!editor) {
return false;
}
return editor.getControl() === this._codeEditor;
}
public applyEdits(versionIdCheck: number, edits: EditorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): boolean {
if (this._model.getVersionId() !== versionIdCheck) {
// throw new Error('Model has changed in the meantime!');
// model changed in the meantime
return false;
}
if (!this._codeEditor) {
// console.warn('applyEdits on invisible editor');
return false;
}
if (opts.setEndOfLine === EndOfLine.CRLF) {
this._model.setEOL(EditorCommon.EndOfLineSequence.CRLF);
} else if (opts.setEndOfLine === EndOfLine.LF) {
this._model.setEOL(EditorCommon.EndOfLineSequence.LF);
}
let transformedEdits = edits.map((edit): EditorCommon.IIdentifiedSingleEditOperation => {
return {
identifier: null,
range: Range.lift(edit.range),
text: edit.text,
forceMoveMarkers: edit.forceMoveMarkers
};
});
if (opts.undoStopBefore) {
this._codeEditor.pushUndoStop();
}
this._codeEditor.executeEdits('MainThreadTextEditor', transformedEdits);
if (opts.undoStopAfter) {
this._codeEditor.pushUndoStop();
}
return true;
}
insertSnippet(template: string, ranges: IRange[], opts: IUndoStopOptions) {
if (!this._codeEditor) {
return false;
}
const snippetController = SnippetController.get(this._codeEditor);
// cancel previous snippet mode
snippetController.leaveSnippet();
// set selection, focus editor
const selections = ranges.map(r => new Selection(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn));
this._codeEditor.setSelections(selections);
this._codeEditor.focus();
// make modifications
if (opts.undoStopBefore) {
this._codeEditor.pushUndoStop();
}
snippetController.insertSnippet(template, 0, 0);
if (opts.undoStopAfter) {
this._codeEditor.pushUndoStop();
}
return true;
}
}

View File

@@ -1,229 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ISingleEditOperation, IDecorationRenderOptions, IDecorationOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IEditorOptions, Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { TextEditorRevealType, MainThreadTextEditor, IApplyEditsOptions, IUndoStopOptions, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/mainThreadEditor';
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { equals as objectEquals } from 'vs/base/common/objects';
import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData } from './extHost.protocol';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
export class MainThreadEditors extends MainThreadEditorsShape {
private _proxy: ExtHostEditorsShape;
private _documentsAndEditors: MainThreadDocumentsAndEditors;
private _workbenchEditorService: IWorkbenchEditorService;
private _telemetryService: ITelemetryService;
private _toDispose: IDisposable[];
private _textEditorsListenersMap: { [editorId: string]: IDisposable[]; };
private _editorPositionData: ITextEditorPositionData;
constructor(
documentsAndEditors: MainThreadDocumentsAndEditors,
@ICodeEditorService private _codeEditorService: ICodeEditorService,
@IThreadService threadService: IThreadService,
@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
@IEditorGroupService editorGroupService: IEditorGroupService,
@ITelemetryService telemetryService: ITelemetryService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostEditors);
this._documentsAndEditors = documentsAndEditors;
this._workbenchEditorService = workbenchEditorService;
this._telemetryService = telemetryService;
this._toDispose = [];
this._textEditorsListenersMap = Object.create(null);
this._editorPositionData = null;
this._toDispose.push(documentsAndEditors.onTextEditorAdd(editors => editors.forEach(this._onTextEditorAdd, this)));
this._toDispose.push(documentsAndEditors.onTextEditorRemove(editors => editors.forEach(this._onTextEditorRemove, this)));
this._toDispose.push(editorGroupService.onEditorsChanged(() => this._updateActiveAndVisibleTextEditors()));
this._toDispose.push(editorGroupService.onEditorsMoved(() => this._updateActiveAndVisibleTextEditors()));
}
public dispose(): void {
Object.keys(this._textEditorsListenersMap).forEach((editorId) => {
dispose(this._textEditorsListenersMap[editorId]);
});
this._textEditorsListenersMap = Object.create(null);
this._toDispose = dispose(this._toDispose);
}
private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
let id = textEditor.getId();
let toDispose: IDisposable[] = [];
toDispose.push(textEditor.onConfigurationChanged((opts) => {
this._proxy.$acceptOptionsChanged(id, opts);
}));
toDispose.push(textEditor.onSelectionChanged((event) => {
this._proxy.$acceptSelectionsChanged(id, event);
}));
this._textEditorsListenersMap[id] = toDispose;
}
private _onTextEditorRemove(id: string): void {
dispose(this._textEditorsListenersMap[id]);
delete this._textEditorsListenersMap[id];
}
private _updateActiveAndVisibleTextEditors(): void {
// editor columns
let editorPositionData = this._getTextEditorPositionData();
if (!objectEquals(this._editorPositionData, editorPositionData)) {
this._editorPositionData = editorPositionData;
this._proxy.$acceptEditorPositionData(this._editorPositionData);
}
}
private _getTextEditorPositionData(): ITextEditorPositionData {
let result: ITextEditorPositionData = Object.create(null);
for (let workbenchEditor of this._workbenchEditorService.getVisibleEditors()) {
const id = this._documentsAndEditors.findTextEditorIdFor(workbenchEditor);
if (id) {
result[id] = workbenchEditor.position;
}
}
return result;
}
// --- from extension host process
$tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise<string> {
const editorOptions: IEditorOptions = {
preserveFocus: options.preserveFocus,
pinned: options.pinned
};
const input = {
resource,
options: editorOptions
};
return this._workbenchEditorService.openEditor(input, options.position).then(editor => {
if (!editor) {
return undefined;
}
return this._documentsAndEditors.findTextEditorIdFor(editor);
});
}
$tryShowEditor(id: string, position: EditorPosition): TPromise<void> {
// check how often this is used
this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.show' });
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let model = mainThreadEditor.getModel();
return this._workbenchEditorService.openEditor({
resource: model.uri,
options: { preserveFocus: false }
}, position).then(() => { return; });
}
return undefined;
}
$tryHideEditor(id: string): TPromise<void> {
// check how often this is used
this._telemetryService.publicLog('api.deprecated', { function: 'TextEditor.hide' });
let mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
let editors = this._workbenchEditorService.getVisibleEditors();
for (let editor of editors) {
if (mainThreadEditor.matches(editor)) {
return this._workbenchEditorService.closeEditor(editor.position, editor.input).then(() => { return; });
}
}
}
return undefined;
}
$trySetSelections(id: string, selections: ISelection[]): TPromise<any> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError('TextEditor disposed');
}
this._documentsAndEditors.getEditor(id).setSelections(selections);
return TPromise.as(null);
}
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<any> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError('TextEditor disposed');
}
this._documentsAndEditors.getEditor(id).setDecorations(key, ranges);
return TPromise.as(null);
}
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError('TextEditor disposed');
}
this._documentsAndEditors.getEditor(id).revealRange(range, revealType);
return undefined;
}
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<any> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError('TextEditor disposed');
}
this._documentsAndEditors.getEditor(id).setConfiguration(options);
return TPromise.as(null);
}
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError<boolean>('TextEditor disposed');
}
return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
}
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
if (!this._documentsAndEditors.getEditor(id)) {
return TPromise.wrapError<boolean>('TextEditor disposed');
}
return TPromise.as(this._documentsAndEditors.getEditor(id).insertSnippet(template, ranges, opts));
}
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
this._codeEditorService.registerDecorationType(key, options);
}
$removeTextEditorDecorationType(key: string): void {
this._codeEditorService.removeDecorationType(key);
}
$getDiffInformation(id: string): TPromise<ILineChange[]> {
const editor = this._documentsAndEditors.getEditor(id);
if (!editor) {
return TPromise.wrapError<ILineChange[]>('No such TextEditor');
}
const codeEditor = editor.getCodeEditor();
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 TPromise.as([]);
}
return TPromise.as(diffEditor.getLineChanges());
}
}

View File

@@ -1,16 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as errors from 'vs/base/common/errors';
import { MainThreadErrorsShape } from './extHost.protocol';
export class MainThreadErrors extends MainThreadErrorsShape {
public onUnexpectedExtHostError(err: any): void {
errors.onUnexpectedError(err);
}
}

View File

@@ -1,228 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import pkg from 'vs/platform/node/package';
import { localize } from 'vs/nls';
import * as path from 'path';
import URI from 'vs/base/common/uri';
import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService';
import { IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions';
import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints';
import { IMessageService } from 'vs/platform/message/common/message';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, ExtHostExtensionServiceShape } from './extHost.protocol';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions'));
/**
* Represents a failed extension in the ext host.
*/
class MainProcessFailedExtension extends ActivatedExtension {
constructor() {
super(true);
}
}
/**
* Represents an extension that was successfully loaded or an
* empty extension in the ext host.
*/
class MainProcessSuccessExtension extends ActivatedExtension {
constructor() {
super(false);
}
}
function messageWithSource(msg: IMessage): string {
return (msg.source ? '[' + msg.source + ']: ' : '') + msg.message;
}
const hasOwnProperty = Object.hasOwnProperty;
export class MainProcessExtensionService extends AbstractExtensionService<ActivatedExtension> {
private _threadService: IThreadService;
private _messageService: IMessageService;
private _proxy: ExtHostExtensionServiceShape;
private _isDev: boolean;
private _extensionsStatus: { [id: string]: IExtensionsStatus };
/**
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
*/
constructor(
// TODO@Joao: remove!
forcedDisabledExtensions: string[],
@IThreadService threadService: IThreadService,
@IMessageService messageService: IMessageService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IExtensionEnablementService extensionEnablementService: IExtensionEnablementService
) {
super(false);
this._isDev = !environmentService.isBuilt || environmentService.isExtensionDevelopment;
this._messageService = messageService;
this._threadService = threadService;
this._proxy = this._threadService.get(ExtHostContext.ExtHostExtensionService);
this._extensionsStatus = {};
const disabledExtensions = [
...forcedDisabledExtensions,
...extensionEnablementService.getGloballyDisabledExtensions(),
...extensionEnablementService.getWorkspaceDisabledExtensions()
];
this.scanExtensions().done(extensionDescriptions => {
this._onExtensionDescriptions(disabledExtensions.length ? extensionDescriptions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))) : extensionDescriptions);
});
}
private _handleMessage(msg: IMessage) {
this._showMessage(msg.type, messageWithSource(msg));
if (!this._extensionsStatus[msg.source]) {
this._extensionsStatus[msg.source] = { messages: [] };
}
this._extensionsStatus[msg.source].messages.push(msg);
}
public $localShowMessage(severity: Severity, msg: string): void {
let messageShown = false;
if (severity === Severity.Error || severity === Severity.Warning) {
if (this._isDev) {
// Only show nasty intrusive messages if doing extension development.
this._messageService.show(severity, msg);
messageShown = true;
}
}
if (!messageShown) {
switch (severity) {
case Severity.Error:
console.error(msg);
break;
case Severity.Warning:
console.warn(msg);
break;
default:
console.log(msg);
}
}
}
// -- overwriting AbstractExtensionService
public getExtensionsStatus(): { [id: string]: IExtensionsStatus } {
return this._extensionsStatus;
}
protected _showMessage(severity: Severity, msg: string): void {
this._proxy.$localShowMessage(severity, msg);
this.$localShowMessage(severity, msg);
}
protected _createFailedExtension(): ActivatedExtension {
return new MainProcessFailedExtension();
}
protected _actualActivateExtension(extensionDescription: IExtensionDescription): TPromise<ActivatedExtension> {
// redirect extension activation to the extension host
return this._proxy.$activateExtension(extensionDescription).then(_ => {
// the extension host calls $onExtensionActivated, where we write to `_activatedExtensions`
return this._activatedExtensions[extensionDescription.id];
});
}
// -- called by extension host
private _onExtensionDescriptions(extensionDescriptions: IExtensionDescription[]): void {
this._registry.registerExtensions(extensionDescriptions);
let availableExtensions = this._registry.getAllExtensionDescriptions();
let extensionPoints = ExtensionsRegistry.getExtensionPoints();
for (let i = 0, len = extensionPoints.length; i < len; i++) {
this._handleExtensionPoint(extensionPoints[i], availableExtensions);
}
this._triggerOnReady();
}
private _handleExtensionPoint<T>(extensionPoint: ExtensionPoint<T>, availableExtensions: IExtensionDescription[]): void {
let messageHandler = (msg: IMessage) => this._handleMessage(msg);
let users: IExtensionPointUser<T>[] = [], usersLen = 0;
for (let i = 0, len = availableExtensions.length; i < len; i++) {
let desc = availableExtensions[i];
if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) {
users[usersLen++] = {
description: desc,
value: desc.contributes[extensionPoint.name],
collector: new ExtensionMessageCollector(messageHandler, desc.extensionFolderPath)
};
}
}
extensionPoint.acceptUsers(users);
}
public $onExtensionActivated(extensionId: string): void {
this._activatedExtensions[extensionId] = new MainProcessSuccessExtension();
}
public $onExtensionActivationFailed(extensionId: string): void {
this._activatedExtensions[extensionId] = new MainProcessFailedExtension();
}
private scanExtensions(): TPromise<IExtensionDescription[]> {
const collector = new MessagesCollector();
const version = pkg.version;
const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, SystemExtensionsRoot, true);
const userExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, this.environmentService.extensionsPath, false);
const developedExtensions = this.environmentService.disableExtensions || !this.environmentService.isExtensionDevelopment ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, this.environmentService.extensionDevelopmentPath, false);
return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => {
let builtinExtensions = extensionDescriptions[0];
let userExtensions = extensionDescriptions[1];
let developedExtensions = extensionDescriptions[2];
let result: { [extensionId: string]: IExtensionDescription; } = {};
builtinExtensions.forEach((builtinExtension) => {
result[builtinExtension.id] = builtinExtension;
});
userExtensions.forEach((userExtension) => {
if (result.hasOwnProperty(userExtension.id)) {
collector.warn(userExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath));
}
result[userExtension.id] = userExtension;
});
developedExtensions.forEach(developedExtension => {
collector.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath));
if (result.hasOwnProperty(developedExtension.id)) {
collector.warn(developedExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath));
}
result[developedExtension.id] = developedExtension;
});
return Object.keys(result).map(name => result[name]);
}).then(null, err => {
collector.error('', err);
return [];
}).then(extensions => {
collector.getMessages().forEach(entry => this.$localShowMessage(entry.type, this._isDev ? (entry.source ? '[' + entry.source + ']: ' : '') + entry.message : entry.message));
return extensions;
});
}
}

View File

@@ -1,46 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, ExtHostFileSystemEventServiceShape, FileSystemEvents } from './extHost.protocol';
export class MainThreadFileSystemEventService {
constructor(
@IThreadService threadService: IThreadService,
@IFileService fileService: IFileService
) {
const proxy: ExtHostFileSystemEventServiceShape = threadService.get(ExtHostContext.ExtHostFileSystemEventService);
const events: FileSystemEvents = {
created: [],
changed: [],
deleted: []
};
fileService.onFileChanges(event => {
for (let change of event.changes) {
switch (change.type) {
case FileChangeType.ADDED:
events.created.push(change.resource);
break;
case FileChangeType.UPDATED:
events.changed.push(change.resource);
break;
case FileChangeType.DELETED:
events.deleted.push(change.resource);
break;
}
}
proxy.$onFileEvent(events);
events.created.length = 0;
events.changed.length = 0;
events.deleted.length = 0;
});
}
}

View File

@@ -1,112 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, ObjectIdentifier } from './extHost.protocol';
import { consumeSignals, GCSignal } from 'gc-signals';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export const IHeapService = createDecorator<IHeapService>('heapService');
export interface IHeapService {
_serviceBrand: any;
/**
* Track gc-collection for all new objects that
* have the $ident-value set.
*/
trackRecursive<T>(p: TPromise<T>): TPromise<T>;
/**
* Track gc-collection for all new objects that
* have the $ident-value set.
*/
trackRecursive<T>(obj: T): T;
}
export class MainThreadHeapService implements IHeapService {
_serviceBrand: any;
private _activeSignals = new WeakMap<any, GCSignal>();
private _activeIds = new Set<number>();
private _consumeHandle: number;
constructor( @IThreadService threadService: IThreadService) {
const proxy = threadService.get(ExtHostContext.ExtHostHeapService);
this._consumeHandle = setInterval(() => {
const ids = consumeSignals();
if (ids.length > 0) {
// local book-keeping
for (const id of ids) {
this._activeIds.delete(id);
}
// send to ext host
proxy.$onGarbageCollection(ids);
}
}, 15 * 1000);
}
dispose() {
clearInterval(this._consumeHandle);
}
trackRecursive<T>(p: TPromise<T>): TPromise<T>;
trackRecursive<T>(obj: T): T;
trackRecursive<T>(obj: any): any {
if (TPromise.is(obj)) {
return obj.then(result => this.trackRecursive(result));
} else {
return this._doTrackRecursive(obj);
}
}
private _doTrackRecursive(obj: any): any {
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;
}
}
registerSingleton(IHeapService, MainThreadHeapService);

View File

@@ -1,306 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import * as vscode from 'vscode';
import { IReadOnlyModel, ISingleEditOperation } from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import { wireCancellationToken } from 'vs/base/common/async';
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 } from './extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
import { IHeapService } from './mainThreadHeapService';
import { IModeService } from 'vs/editor/common/services/modeService';
export class MainThreadLanguageFeatures extends MainThreadLanguageFeaturesShape {
private _proxy: ExtHostLanguageFeaturesShape;
private _heapService: IHeapService;
private _modeService: IModeService;
private _registrations: { [handle: number]: IDisposable; } = Object.create(null);
constructor(
@IThreadService threadService: IThreadService,
@IHeapService heapService: IHeapService,
@IModeService modeService: IModeService,
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostLanguageFeatures);
this._heapService = heapService;
this._modeService = modeService;
}
$unregister(handle: number): TPromise<any> {
let registration = this._registrations[handle];
if (registration) {
registration.dispose();
delete this._registrations[handle];
}
return undefined;
}
// --- outline
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(selector, <modes.DocumentSymbolProvider>{
provideDocumentSymbols: (model: IReadOnlyModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri));
}
});
return undefined;
}
// --- code lens
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise<any> {
const provider = <modes.CodeLensProvider>{
provideCodeLenses: (model: IReadOnlyModel, token: CancellationToken): modes.ICodeLensSymbol[] | Thenable<modes.ICodeLensSymbol[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeLenses(handle, model.uri)));
},
resolveCodeLens: (model: IReadOnlyModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Thenable<modes.ICodeLensSymbol> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$resolveCodeLens(handle, model.uri, codeLens)));
}
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<modes.CodeLensProvider>();
this._registrations[eventHandle] = emitter;
provider.onDidChange = emitter.event;
}
this._registrations[handle] = modes.CodeLensProviderRegistry.register(selector, provider);
return undefined;
}
$emitCodeLensEvent(eventHandle: number, event?: any): TPromise<any> {
const obj = this._registrations[eventHandle];
if (obj instanceof Emitter) {
obj.fire(event);
}
return undefined;
}
// --- declaration
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.DefinitionProviderRegistry.register(selector, <modes.DefinitionProvider>{
provideDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position));
}
});
return undefined;
}
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.ImplementationProviderRegistry.register(selector, <modes.ImplementationProvider>{
provideImplementation: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position));
}
});
return undefined;
}
$registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(selector, <modes.TypeDefinitionProvider>{
provideTypeDefinition: (model, position, token): Thenable<modes.Definition> => {
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position));
}
});
return undefined;
}
// --- extra info
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.HoverProviderRegistry.register(selector, <modes.HoverProvider>{
provideHover: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.Hover> => {
return wireCancellationToken(token, this._proxy.$provideHover(handle, model.uri, position));
}
});
return undefined;
}
// --- occurrences
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(selector, <modes.DocumentHighlightProvider>{
provideDocumentHighlights: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentHighlights(handle, model.uri, position));
}
});
return undefined;
}
// --- references
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.ReferenceProviderRegistry.register(selector, <modes.ReferenceProvider>{
provideReferences: (model: IReadOnlyModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> => {
return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context));
}
});
return undefined;
}
// --- quick fix
$registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
provideCodeActions: (model: IReadOnlyModel, range: EditorRange, token: CancellationToken): Thenable<modes.CodeAction[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range)));
}
});
return undefined;
}
// --- formatting
$registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(selector, <modes.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits: (model: IReadOnlyModel, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options));
}
});
return undefined;
}
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(selector, <modes.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits: (model: IReadOnlyModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options));
}
});
return undefined;
}
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): TPromise<any> {
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(selector, <modes.OnTypeFormattingEditProvider>{
autoFormatTriggerCharacters,
provideOnTypeFormattingEdits: (model: IReadOnlyModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
return wireCancellationToken(token, this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options));
}
});
return undefined;
}
// --- navigate type
$registerNavigateTypeSupport(handle: number): TPromise<any> {
this._registrations[handle] = WorkspaceSymbolProviderRegistry.register(<IWorkspaceSymbolProvider>{
provideWorkspaceSymbols: (search: string): TPromise<modes.SymbolInformation[]> => {
return this._heapService.trackRecursive(this._proxy.$provideWorkspaceSymbols(handle, search));
},
resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise<modes.SymbolInformation> => {
return this._proxy.$resolveWorkspaceSymbol(handle, item);
}
});
return undefined;
}
// --- rename
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.RenameProviderRegistry.register(selector, <modes.RenameProvider>{
provideRenameEdits: (model: IReadOnlyModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName));
}
});
return undefined;
}
// --- suggest
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[]): TPromise<any> {
this._registrations[handle] = modes.SuggestRegistry.register(selector, <modes.ISuggestSupport>{
triggerCharacters,
provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.ISuggestResult> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position)));
},
resolveCompletionItem: (model: IReadOnlyModel, position: EditorPosition, suggestion: modes.ISuggestion, token: CancellationToken): Thenable<modes.ISuggestion> => {
return wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion));
}
});
return undefined;
}
// --- parameter hints
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise<any> {
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(selector, <modes.SignatureHelpProvider>{
signatureHelpTriggerCharacters: triggerCharacter,
provideSignatureHelp: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.SignatureHelp> => {
return wireCancellationToken(token, this._proxy.$provideSignatureHelp(handle, model.uri, position));
}
});
return undefined;
}
// --- links
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
this._registrations[handle] = modes.LinkProviderRegistry.register(selector, <modes.LinkProvider>{
provideLinks: (model, token) => {
return wireCancellationToken(token, this._proxy.$provideDocumentLinks(handle, model.uri));
},
resolveLink: (link, token) => {
return wireCancellationToken(token, this._proxy.$resolveDocumentLink(handle, link));
}
});
return undefined;
}
// --- configuration
$setLanguageConfiguration(handle: number, languageId: string, _configuration: vscode.LanguageConfiguration): TPromise<any> {
let configuration: LanguageConfiguration = {
comments: _configuration.comments,
brackets: _configuration.brackets,
wordPattern: _configuration.wordPattern,
indentationRules: _configuration.indentationRules,
onEnterRules: _configuration.onEnterRules,
autoClosingPairs: null,
surroundingPairs: null,
__electricCharacterSupport: null
};
if (_configuration.__characterPairSupport) {
// backwards compatibility
configuration.autoClosingPairs = _configuration.__characterPairSupport.autoClosingPairs;
}
if (_configuration.__electricCharacterSupport && _configuration.__electricCharacterSupport.docComment) {
configuration.__electricCharacterSupport = {
docComment: {
open: _configuration.__electricCharacterSupport.docComment.open,
close: _configuration.__electricCharacterSupport.docComment.close
}
};
}
let languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (languageIdentifier) {
this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration);
}
return undefined;
}
}

View File

@@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IModeService } from 'vs/editor/common/services/modeService';
import { MainThreadLanguagesShape } from './extHost.protocol';
export class MainThreadLanguages extends MainThreadLanguagesShape {
private _modeService: IModeService;
constructor(
@IModeService modeService: IModeService
) {
super();
this._modeService = modeService;
}
$getLanguages(): TPromise<string[]> {
return TPromise.as(this._modeService.getRegisteredModes());
}
}

View File

@@ -1,95 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import { IMessageService, IChoiceService } from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
import { Action } from 'vs/base/common/actions';
import { TPromise as Promise } from 'vs/base/common/winjs.base';
import { MainThreadMessageServiceShape } from './extHost.protocol';
import * as vscode from 'vscode';
export class MainThreadMessageService extends MainThreadMessageServiceShape {
constructor(
@IMessageService private _messageService: IMessageService,
@IChoiceService private _choiceService: IChoiceService
) {
super();
}
$showMessage(severity: Severity, message: string, options: vscode.MessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
if (options.modal) {
return this.showModalMessage(severity, message, commands);
} else {
return this.showMessage(severity, message, commands);
}
}
private showMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
return new Promise<number>(resolve => {
let messageHide: Function;
let actions: MessageItemAction[] = [];
let hasCloseAffordance = false;
class MessageItemAction extends Action {
constructor(id: string, label: string, handle: number) {
super(id, label, undefined, true, () => {
resolve(handle);
messageHide(); // triggers dispose! make sure promise is already resolved
return undefined;
});
}
dispose(): void {
resolve(undefined);
}
}
commands.forEach(command => {
if (command.isCloseAffordance === true) {
hasCloseAffordance = true;
}
actions.push(new MessageItemAction('_extension_message_handle_' + command.handle, command.title, command.handle));
});
if (!hasCloseAffordance) {
actions.push(new MessageItemAction('__close', nls.localize('close', "Close"), undefined));
}
messageHide = this._messageService.show(severity, {
message,
actions
});
});
}
private showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Thenable<number> {
let cancelId: number | undefined = void 0;
const options = commands.map((command, index) => {
if (command.isCloseAffordance === true) {
cancelId = index;
}
return command.title;
});
if (cancelId === void 0) {
if (options.length > 0) {
options.push(nls.localize('cancel', "Cancel"));
} else {
options.push(nls.localize('ok', "OK"));
}
cancelId = options.length - 1;
}
return this._choiceService.choose(severity, message, options, cancelId, true)
.then(result => result === commands.length ? undefined : commands[result].handle);
}
}

View File

@@ -1,66 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { Registry } from 'vs/platform/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 { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { MainThreadOutputServiceShape } from './extHost.protocol';
export class MainThreadOutputService extends MainThreadOutputServiceShape {
private _outputService: IOutputService;
private _partService: IPartService;
private _panelService: IPanelService;
constructor( @IOutputService outputService: IOutputService,
@IPartService partService: IPartService,
@IPanelService panelService: IPanelService
) {
super();
this._outputService = outputService;
this._partService = partService;
this._panelService = panelService;
}
public $append(channelId: string, label: string, value: string): TPromise<void> {
this._getChannel(channelId, label).append(value);
return undefined;
}
public $clear(channelId: string, label: string): TPromise<void> {
this._getChannel(channelId, label).clear();
return undefined;
}
public $reveal(channelId: string, label: string, preserveFocus: boolean): TPromise<void> {
this._getChannel(channelId, label).show(preserveFocus);
return undefined;
}
private _getChannel(channelId: string, label: string): IOutputChannel {
if (!Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannel(channelId)) {
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel(channelId, label);
}
return this._outputService.getChannel(channelId);
}
public $close(channelId: string): TPromise<void> {
const panel = this._panelService.getActivePanel();
if (panel && panel.getId() === OUTPUT_PANEL_ID && channelId === this._outputService.getActiveChannel().id) {
return this._partService.setPanelHidden(true);
}
return undefined;
}
public $dispose(channelId: string, label: string): TPromise<void> {
this._getChannel(channelId, label).dispose();
return undefined;
}
}

View File

@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IProgressService2, IProgress, IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainThreadProgressShape } from './extHost.protocol';
export class MainThreadProgress extends MainThreadProgressShape {
private _progressService: IProgressService2;
private progress = new Map<number, { resolve: Function, progress: IProgress<IProgressStep> }>();
constructor(
@IProgressService2 progressService: IProgressService2
) {
super();
this._progressService = progressService;
}
$startProgress(handle: number, options: IProgressOptions): void {
const task = this._createTask(handle);
this._progressService.withProgress(options, task);
}
$progressReport(handle: number, message: IProgressStep): void {
this.progress.get(handle).progress.report(message);
}
$progressEnd(handle: number): void {
this.progress.get(handle).resolve();
this.progress.delete(handle);
}
private _createTask(handle: number) {
return (progress: IProgress<IProgressStep>) => {
return new TPromise<any>(resolve => {
this.progress.set(handle, { resolve, progress });
});
};
}
}

View File

@@ -1,99 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { asWinJsPromise } from 'vs/base/common/async';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { IQuickOpenService, IPickOptions, IInputOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { InputBoxOptions } from 'vscode';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems } from './extHost.protocol';
export class MainThreadQuickOpen extends MainThreadQuickOpenShape {
private _proxy: ExtHostQuickOpenShape;
private _quickOpenService: IQuickOpenService;
private _doSetItems: (items: MyQuickPickItems[]) => any;
private _doSetError: (error: Error) => any;
private _contents: TPromise<MyQuickPickItems[]>;
private _token: number = 0;
constructor(
@IThreadService threadService: IThreadService,
@IQuickOpenService quickOpenService: IQuickOpenService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostQuickOpen);
this._quickOpenService = quickOpenService;
}
$show(options: IPickOptions): Thenable<number> {
const myToken = ++this._token;
this._contents = new TPromise<MyQuickPickItems[]>((c, e) => {
this._doSetItems = (items) => {
if (myToken === this._token) {
c(items);
}
};
this._doSetError = (error) => {
if (myToken === this._token) {
e(error);
}
};
});
return asWinJsPromise(token => this._quickOpenService.pick(this._contents, options, token)).then(item => {
if (item) {
return item.handle;
}
return undefined;
}, undefined, progress => {
if (progress) {
this._proxy.$onItemSelected((<MyQuickPickItems>progress).handle);
}
});
}
$setItems(items: MyQuickPickItems[]): Thenable<any> {
if (this._doSetItems) {
this._doSetItems(items);
}
return undefined;
}
$setError(error: Error): Thenable<any> {
if (this._doSetError) {
this._doSetError(error);
}
return undefined;
}
// ---- input
$input(options: InputBoxOptions, validateInput: boolean): TPromise<string> {
const inputOptions: IInputOptions = Object.create(null);
if (options) {
inputOptions.password = options.password;
inputOptions.placeHolder = options.placeHolder;
inputOptions.valueSelection = options.valueSelection;
inputOptions.prompt = options.prompt;
inputOptions.value = options.value;
inputOptions.ignoreFocusLost = options.ignoreFocusOut;
}
if (validateInput) {
inputOptions.validateInput = (value) => {
return this._proxy.$validateInput(value);
};
}
return asWinJsPromise(token => this._quickOpenService.input(inputOptions, token));
}
}

View File

@@ -1,302 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import URI 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 { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResource, SCMGroupFeatures } from './extHost.protocol';
import { Command } from 'vs/editor/common/modes';
class MainThreadSCMResourceGroup implements ISCMResourceGroup {
constructor(
private sourceControlHandle: number,
private handle: number,
public provider: ISCMProvider,
public features: SCMGroupFeatures,
public label: string,
public id: string,
public resources: ISCMResource[]
) { }
toJSON(): any {
return {
$mid: 4,
sourceControlHandle: this.sourceControlHandle,
groupHandle: this.handle
};
}
}
class MainThreadSCMResource implements ISCMResource {
constructor(
private sourceControlHandle: number,
private groupHandle: number,
private handle: number,
public sourceUri: URI,
public command: Command | undefined,
public resourceGroup: ISCMResourceGroup,
public decorations: ISCMResourceDecorations
) { }
toJSON(): any {
return {
$mid: 3,
sourceControlHandle: this.sourceControlHandle,
groupHandle: this.groupHandle,
handle: this.handle
};
}
}
class MainThreadSCMProvider implements ISCMProvider {
private _groups: MainThreadSCMResourceGroup[] = [];
private _groupsByHandle: { [handle: number]: MainThreadSCMResourceGroup; } = Object.create(null);
get resources(): ISCMResourceGroup[] {
return this._groups
.filter(g => g.resources.length > 0 || !g.features.hideWhenEmpty);
}
private _onDidChange = new Emitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
private features: SCMProviderFeatures = {};
get handle(): number { return this._handle; }
get label(): string { return this._label; }
get id(): string { return this._id; }
get commitTemplate(): string | undefined { return this.features.commitTemplate; }
get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; }
get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; }
private _onDidChangeCommitTemplate = new Emitter<string>();
get onDidChangeCommitTemplate(): Event<string> { return this._onDidChangeCommitTemplate.event; }
private _count: number | undefined = undefined;
get count(): number | undefined { return this._count; }
constructor(
private proxy: ExtHostSCMShape,
private _handle: number,
private _id: string,
private _label: string,
@ISCMService scmService: ISCMService,
@ICommandService private commandService: ICommandService
) { }
$updateSourceControl(features: SCMProviderFeatures): void {
if ('count' in features) {
this._count = features.count;
}
this.features = assign(this.features, features);
this._onDidChange.fire();
if (typeof features.commitTemplate !== 'undefined') {
this._onDidChangeCommitTemplate.fire(this.commitTemplate);
}
}
$registerGroup(handle: number, id: string, label: string): void {
const group = new MainThreadSCMResourceGroup(
this.handle,
handle,
this,
{},
label,
id,
[]
);
this._groups.push(group);
this._groupsByHandle[handle] = group;
}
$updateGroup(handle: number, features: SCMGroupFeatures): void {
const group = this._groupsByHandle[handle];
if (!group) {
return;
}
group.features = assign(group.features, features);
this._onDidChange.fire();
}
$updateGroupResourceStates(groupHandle: number, resources: SCMRawResource[]): void {
const group = this._groupsByHandle[groupHandle];
if (!group) {
return;
}
group.resources = resources.map(rawResource => {
const [handle, sourceUri, command, icons, strikeThrough, faded] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
icon: icon && URI.parse(icon),
iconDark: iconDark && URI.parse(iconDark),
strikeThrough,
faded
};
return new MainThreadSCMResource(
this.handle,
groupHandle,
handle,
URI.parse(sourceUri),
command,
group,
decorations
);
});
this._onDidChange.fire();
}
$unregisterGroup(handle: number): void {
const group = this._groupsByHandle[handle];
if (!group) {
return;
}
delete this._groupsByHandle[handle];
this._groups.splice(this._groups.indexOf(group), 1);
}
getOriginalResource(uri: URI): TPromise<URI> {
if (!this.features.hasQuickDiffProvider) {
return TPromise.as(null);
}
return this.proxy.$provideOriginalResource(this.handle, uri);
}
dispose(): void {
}
}
export class MainThreadSCM extends MainThreadSCMShape {
private _proxy: ExtHostSCMShape;
private _sourceControls: { [handle: number]: MainThreadSCMProvider; } = Object.create(null);
private _sourceControlDisposables: { [handle: number]: IDisposable; } = Object.create(null);
private _disposables: IDisposable[] = [];
constructor(
@IThreadService threadService: IThreadService,
@IInstantiationService private instantiationService: IInstantiationService,
@ISCMService private scmService: ISCMService,
@ICommandService private commandService: ICommandService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostSCM);
this.scmService.onDidChangeProvider(this.onDidChangeProvider, this, this._disposables);
this.scmService.input.onDidChange(this._proxy.$onInputBoxValueChange, this._proxy, this._disposables);
}
$registerSourceControl(handle: number, id: string, label: string): void {
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, this.scmService, this.commandService);
this._sourceControls[handle] = provider;
this._sourceControlDisposables[handle] = this.scmService.registerSCMProvider(provider);
}
$updateSourceControl(handle: number, features: SCMProviderFeatures): void {
const sourceControl = this._sourceControls[handle];
if (!sourceControl) {
return;
}
sourceControl.$updateSourceControl(features);
}
$unregisterSourceControl(handle: number): void {
const sourceControl = this._sourceControls[handle];
if (!sourceControl) {
return;
}
this._sourceControlDisposables[handle].dispose();
delete this._sourceControlDisposables[handle];
sourceControl.dispose();
delete this._sourceControls[handle];
}
$registerGroup(sourceControlHandle: number, groupHandle: number, id: string, label: string): void {
const provider = this._sourceControls[sourceControlHandle];
if (!provider) {
return;
}
provider.$registerGroup(groupHandle, id, label);
}
$updateGroup(sourceControlHandle: number, groupHandle: number, features: SCMGroupFeatures): void {
const provider = this._sourceControls[sourceControlHandle];
if (!provider) {
return;
}
provider.$updateGroup(groupHandle, features);
}
$updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void {
const provider = this._sourceControls[sourceControlHandle];
if (!provider) {
return;
}
provider.$updateGroupResourceStates(groupHandle, resources);
}
$unregisterGroup(sourceControlHandle: number, handle: number): void {
const provider = this._sourceControls[sourceControlHandle];
if (!provider) {
return;
}
provider.$unregisterGroup(handle);
}
$setInputBoxValue(value: string): void {
this.scmService.input.value = value;
}
private onDidChangeProvider(provider: ISCMProvider): void {
const handle = Object.keys(this._sourceControls).filter(handle => this._sourceControls[handle] === provider)[0];
this._proxy.$onActiveSourceControlChange(handle && parseInt(handle));
}
dispose(): void {
Object.keys(this._sourceControls)
.forEach(id => this._sourceControls[id].dispose());
this._sourceControls = Object.create(null);
this._disposables = dispose(this._disposables);
}
}

View File

@@ -1,264 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { sequence } from 'vs/base/common/async';
import * as strings from 'vs/base/common/strings';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IModel, ICommonCodeEditor, ISingleEditOperation, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { Position } from 'vs/editor/common/core/position';
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
import { getDocumentFormattingEdits } from 'vs/editor/contrib/format/common/format';
import { EditOperationsCommand } from 'vs/editor/contrib/format/common/formatCommand';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from './extHost.protocol';
import { EditOperation } from 'vs/editor/common/core/editOperation';
export interface INamedSaveParticpant extends ISaveParticipant {
readonly name: string;
}
class TrimWhitespaceParticipant implements INamedSaveParticpant {
readonly name = 'TrimWhitespaceParticipant';
constructor(
@IConfigurationService private configurationService: IConfigurationService,
@ICodeEditorService private codeEditorService: ICodeEditorService
) {
// Nothing
}
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): any {
if (this.configurationService.lookup('files.trimTrailingWhitespace', model.textEditorModel.getLanguageIdentifier().language).value) {
this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO);
}
}
private doTrimTrailingWhitespace(model: IModel, isAutoSaved: boolean): void {
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
const cursors: Position[] = [];
let 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
prevSelection = editor.getSelections();
if (isAutoSaved) {
cursors.push(...prevSelection.map(s => new Position(s.positionLineNumber, s.positionColumn)));
}
}
const ops = trimTrailingWhitespace(model, cursors);
if (!ops.length) {
return; // Nothing to do
}
model.pushEditOperations(prevSelection, ops, (edits) => prevSelection);
}
}
function findEditor(model: IModel, codeEditorService: ICodeEditorService): ICommonCodeEditor {
let candidate: ICommonCodeEditor = null;
if (model.isAttachedToEditor()) {
for (const editor of codeEditorService.listCodeEditors()) {
if (editor.getModel() === model) {
if (editor.isFocused()) {
return editor; // favour focussed editor if there are multiple
}
candidate = editor;
}
}
}
return candidate;
}
export class FinalNewLineParticipant implements INamedSaveParticpant {
readonly name = 'FinalNewLineParticipant';
constructor(
@IConfigurationService private configurationService: IConfigurationService,
@ICodeEditorService private codeEditorService: ICodeEditorService
) {
// Nothing
}
public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): any {
if (this.configurationService.lookup('files.insertFinalNewline', model.textEditorModel.getLanguageIdentifier().language).value) {
this.doInsertFinalNewLine(model.textEditorModel);
}
}
private doInsertFinalNewLine(model: IModel): void {
const lineCount = model.getLineCount();
const lastLine = model.getLineContent(lineCount);
const lastLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(lastLine) === -1;
if (!lineCount || lastLineIsEmptyOrWhitespace) {
return;
}
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
const editor = findEditor(model, this.codeEditorService);
if (editor) {
prevSelection = editor.getSelections();
}
model.pushEditOperations(prevSelection, [EditOperation.insert(new Position(lineCount, model.getLineMaxColumn(lineCount)), model.getEOL())], edits => prevSelection);
if (editor) {
editor.setSelections(prevSelection);
}
}
}
class FormatOnSaveParticipant implements INamedSaveParticpant {
readonly name = 'FormatOnSaveParticipant';
constructor(
@ICodeEditorService private _editorService: ICodeEditorService,
@IConfigurationService private _configurationService: IConfigurationService
) {
// Nothing
}
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<any> {
const model = editorModel.textEditorModel;
if (env.reason === SaveReason.AUTO
|| !this._configurationService.lookup('editor.formatOnSave', model.getLanguageIdentifier().language).value) {
return undefined;
}
const versionNow = model.getVersionId();
const { tabSize, insertSpaces } = model.getOptions();
return new TPromise<ISingleEditOperation[]>((resolve, reject) => {
setTimeout(reject, 750);
getDocumentFormattingEdits(model, { tabSize, insertSpaces }).then(resolve, reject);
}).then(edits => {
if (edits && versionNow === model.getVersionId()) {
const editor = findEditor(model, this._editorService);
if (editor) {
this._editsWithEditor(editor, edits);
} else {
this._editWithModel(model, edits);
}
}
});
}
private _editsWithEditor(editor: ICommonCodeEditor, edits: ISingleEditOperation[]): void {
EditOperationsCommand.execute(editor, edits);
}
private _editWithModel(model: IModel, edits: ISingleEditOperation[]): void {
const [{ range }] = edits;
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
model.pushEditOperations([initialSelection], edits.map(FormatOnSaveParticipant._asIdentEdit), undoEdits => {
for (const { range } of undoEdits) {
if (Range.areIntersectingOrTouching(range, initialSelection)) {
return [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];
}
}
return undefined;
});
}
private static _asIdentEdit({ text, range }: ISingleEditOperation): IIdentifiedSingleEditOperation {
return {
text,
range: Range.lift(range),
identifier: undefined,
forceMoveMarkers: true
};
}
}
class ExtHostSaveParticipant implements INamedSaveParticpant {
private _proxy: ExtHostDocumentSaveParticipantShape;
readonly name = 'ExtHostSaveParticipant';
constructor( @IThreadService threadService: IThreadService) {
this._proxy = threadService.get(ExtHostContext.ExtHostDocumentSaveParticipant);
}
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<any> {
return new TPromise<any>((resolve, reject) => {
setTimeout(reject, 1750);
this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => {
for (const success of values) {
if (!success) {
return TPromise.wrapError('listener failed');
}
}
return undefined;
}).then(resolve, reject);
});
}
}
// The save participant can change a model before its saved to support various scenarios like trimming trailing whitespace
export class SaveParticipant implements ISaveParticipant {
private _saveParticipants: INamedSaveParticpant[];
constructor(
@ITelemetryService private _telemetryService: ITelemetryService,
@IInstantiationService instantiationService: IInstantiationService,
@IThreadService threadService: IThreadService
) {
this._saveParticipants = [
instantiationService.createInstance(TrimWhitespaceParticipant),
instantiationService.createInstance(FormatOnSaveParticipant),
instantiationService.createInstance(FinalNewLineParticipant),
instantiationService.createInstance(ExtHostSaveParticipant)
];
// Hook into model
TextFileEditorModel.setSaveParticipant(this);
}
participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<any> {
const stats: { [name: string]: number } = Object.create(null);
const promiseFactory = this._saveParticipants.map(p => () => {
const { name } = p;
const t1 = Date.now();
return TPromise.as(p.participate(model, env)).then(() => {
stats[`Success-${name}`] = Date.now() - t1;
}, err => {
stats[`Failure-${name}`] = Date.now() - t1;
// console.error(err);
});
});
return sequence(promiseFactory).then(() => {
this._telemetryService.publicLog('saveParticipantStats', stats);
});
}
}

View File

@@ -1,39 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IDisposable } from 'vs/base/common/lifecycle';
import { MainThreadStatusBarShape } from './extHost.protocol';
export class MainThreadStatusBar extends MainThreadStatusBarShape {
private mapIdToDisposable: { [id: number]: IDisposable };
constructor(
@IStatusbarService private statusbarService: IStatusbarService
) {
super();
this.mapIdToDisposable = Object.create(null);
}
$setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string, alignment: MainThreadStatusBarAlignment, priority: number): void {
// Dispose any old
this.$dispose(id);
// Add new
let disposeable = this.statusbarService.addEntry({ text, tooltip, command, color, extensionId }, alignment, priority);
this.mapIdToDisposable[id] = disposeable;
}
$dispose(id: number) {
let disposeable = this.mapIdToDisposable[id];
if (disposeable) {
disposeable.dispose();
}
delete this.mapIdToDisposable[id];
}
}

View File

@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { MainThreadStorageShape } from './extHost.protocol';
export class MainThreadStorage extends MainThreadStorageShape {
private _storageService: IStorageService;
constructor( @IStorageService storageService: IStorageService) {
super();
this._storageService = storageService;
}
$getValue<T>(shared: boolean, key: string): TPromise<T> {
let jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
if (!jsonValue) {
return TPromise.as(undefined);
}
let value: T;
try {
value = JSON.parse(jsonValue);
return TPromise.as(value);
} catch (err) {
return TPromise.wrapError<T>(err);
}
}
$setValue(shared: boolean, key: string, value: any): TPromise<any> {
let jsonValue: any;
try {
jsonValue = JSON.stringify(value);
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
} catch (err) {
return TPromise.wrapError(err);
}
return undefined;
}
}

View File

@@ -1,36 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape } from './extHost.protocol';
export class MainThreadTask extends MainThreadTaskShape {
private _proxy: ExtHostTaskShape;
constructor( @IThreadService threadService: IThreadService, @ITaskService private _taskService: ITaskService) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostTask);
}
public $registerTaskProvider(handle: number): TPromise<void> {
this._taskService.registerTaskProvider(handle, {
provideTasks: () => {
return this._proxy.$provideTasks(handle);
}
});
return TPromise.as<void>(undefined);
}
public $unregisterTaskProvider(handle: number): TPromise<any> {
this._taskService.unregisterTaskProvider(handle);
return TPromise.as<void>(undefined);
}
}

View File

@@ -1,30 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadTelemetryShape } from './extHost.protocol';
/**
* Helper always instantiated in the main process to receive telemetry events from remote telemetry services
*/
export class MainThreadTelemetry extends MainThreadTelemetryShape {
private _telemetryService: ITelemetryService;
constructor( @ITelemetryService telemetryService: ITelemetryService) {
super();
this._telemetryService = telemetryService;
}
public $publicLog(eventName: string, data?: any): void {
this._telemetryService.publicLog(eventName, data);
}
public $getTelemetryInfo(): TPromise<ITelemetryInfo> {
return this._telemetryService.getTelemetryInfo();
}
}

View File

@@ -1,91 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig } from 'vs/workbench/parts/terminal/common/terminal';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape } from './extHost.protocol';
export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
private _proxy: ExtHostTerminalServiceShape;
private _toDispose: IDisposable[];
constructor(
@IThreadService threadService: IThreadService,
@ITerminalService private terminalService: ITerminalService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostTerminalService);
this._toDispose = [];
this._toDispose.push(terminalService.onInstanceDisposed((terminalInstance) => this._onTerminalDisposed(terminalInstance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady((terminalInstance) => this._onTerminalProcessIdReady(terminalInstance)));
this._toDispose.push(terminalService.onInstanceData(event => this._onTerminalData(event.instance, event.data)));
}
public dispose(): void {
this._toDispose = dispose(this._toDispose);
}
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise<number> {
const shellLaunchConfig: IShellLaunchConfig = {
name,
executable: shellPath,
args: shellArgs,
waitOnExit,
ignoreConfigurationCwd: true
};
return TPromise.as(this.terminalService.createInstance(shellLaunchConfig).id);
}
public $show(terminalId: number, preserveFocus: boolean): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
this.terminalService.setActiveInstance(terminalInstance);
this.terminalService.showPanel(!preserveFocus);
}
}
public $hide(terminalId: number): void {
if (this.terminalService.getActiveInstance().id === terminalId) {
this.terminalService.hidePanel();
}
}
public $registerOnData(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.enableApiOnData();
}
}
public $dispose(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.dispose();
}
}
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.sendText(text, addNewLine);
}
}
private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
this._proxy.$acceptTerminalClosed(terminalInstance.id);
}
private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
}
private _onTerminalData(terminalInstance: ITerminalInstance, data: string): void {
this._proxy.$acceptTerminalData(terminalInstance.id, data);
}
}

View File

@@ -1,64 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostContext, MainThreadTreeViewShape, ExtHostTreeViewShape } from './extHost.protocol';
import { ITreeExplorerService } from 'vs/workbench/parts/explorers/common/treeExplorerService';
import { InternalTreeNodeContent, InternalTreeNodeProvider } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { ICommandService } from 'vs/platform/commands/common/commands';
export class MainThreadTreeView extends MainThreadTreeViewShape {
private _proxy: ExtHostTreeViewShape;
constructor(
@IThreadService threadService: IThreadService,
@ITreeExplorerService private treeExplorerService: ITreeExplorerService,
@IMessageService private messageService: IMessageService,
@ICommandService private commandService: ICommandService
) {
super();
this._proxy = threadService.get(ExtHostContext.ExtHostTreeView);
}
$registerTreeDataProvider(providerId: string): void {
const provider = new TreeExplorerNodeProvider(providerId, this._proxy, this.messageService, this.commandService);
this.treeExplorerService.registerTreeExplorerNodeProvider(providerId, provider);
}
$refresh(providerId: string, node: InternalTreeNodeContent): void {
(<TreeExplorerNodeProvider>this.treeExplorerService.getProvider(providerId))._onRefresh.fire(node);
}
}
class TreeExplorerNodeProvider implements InternalTreeNodeProvider {
readonly _onRefresh: Emitter<InternalTreeNodeContent> = new Emitter<InternalTreeNodeContent>();
readonly onRefresh: Event<InternalTreeNodeContent> = this._onRefresh.event;
constructor(public readonly id: string, private _proxy: ExtHostTreeViewShape,
private messageService: IMessageService,
private commandService: ICommandService
) {
}
provideRootNode(): TPromise<InternalTreeNodeContent> {
return this._proxy.$provideRootNode(this.id).then(rootNode => rootNode, err => this.messageService.show(Severity.Error, err));
}
resolveChildren(node: InternalTreeNodeContent): TPromise<InternalTreeNodeContent[]> {
return this._proxy.$resolveChildren(this.id, node).then(children => children, err => this.messageService.show(Severity.Error, err));
}
executeCommand(node: InternalTreeNodeContent): TPromise<any> {
return this._proxy.$getInternalCommand(this.id, node).then(command => {
return this.commandService.executeCommand(command.id, ...command.arguments);
});
}
}

View File

@@ -1,107 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import { ISearchService, QueryType } from 'vs/platform/search/common/search';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ICommonCodeEditor, isCommonCodeEditor } from 'vs/editor/common/editorCommon';
import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { TPromise } from 'vs/base/common/winjs.base';
import { Uri } from 'vscode';
import { MainThreadWorkspaceShape } from './extHost.protocol';
import { ITextModelResolverService } from 'vs/editor/common/services/resolverService';
import { IFileService } from 'vs/platform/files/common/files';
export class MainThreadWorkspace extends MainThreadWorkspaceShape {
private _activeSearches: { [id: number]: TPromise<Uri[]> } = Object.create(null);
private _searchService: ISearchService;
private _contextService: IWorkspaceContextService;
private _textFileService: ITextFileService;
private _editorService: IWorkbenchEditorService;
private _textModelResolverService: ITextModelResolverService;
private _fileService: IFileService;
constructor(
@ISearchService searchService: ISearchService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@ITextFileService textFileService: ITextFileService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@ITextModelResolverService textModelResolverService: ITextModelResolverService,
@IFileService fileService: IFileService
) {
super();
this._searchService = searchService;
this._contextService = contextService;
this._textFileService = textFileService;
this._editorService = editorService;
this._fileService = fileService;
this._textModelResolverService = textModelResolverService;
}
$startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable<URI[]> {
const workspace = this._contextService.getWorkspace();
if (!workspace) {
return undefined;
}
const search = this._searchService.search({
folderResources: [workspace.resource],
type: QueryType.File,
maxResults,
includePattern: { [include]: true },
excludePattern: { [exclude]: true },
}).then(result => {
return result.results.map(m => m.resource);
}, err => {
if (!isPromiseCanceledError(err)) {
return TPromise.wrapError(err);
}
return undefined;
});
this._activeSearches[requestId] = search;
const onDone = () => delete this._activeSearches[requestId];
search.done(onDone, onDone);
return search;
}
$cancelSearch(requestId: number): Thenable<boolean> {
const search = this._activeSearches[requestId];
if (search) {
delete this._activeSearches[requestId];
search.cancel();
return TPromise.as(true);
}
return undefined;
}
$saveAll(includeUntitled?: boolean): Thenable<boolean> {
return this._textFileService.saveAll(includeUntitled).then(result => {
return result.results.every(each => each.success === true);
});
}
$applyWorkspaceEdit(edits: IResourceEdit[]): TPromise<boolean> {
let codeEditor: ICommonCodeEditor;
let editor = this._editorService.getActiveEditor();
if (editor) {
let candidate = editor.getControl();
if (isCommonCodeEditor(candidate)) {
codeEditor = candidate;
}
}
return bulkEdit(this._textModelResolverService, codeEditor, edits, this._fileService)
.then(() => true);
}
}