mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-26 03:29:00 +01:00
Merge branch 'master' into resolveInitialRenameValue
This commit is contained in:
@@ -55,8 +55,8 @@ import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
|
||||
import { toGlobPattern, toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription): typeof vscode;
|
||||
@@ -89,18 +89,19 @@ export function createApiFactory(
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extensionService: ExtHostExtensionService,
|
||||
logService: ILogService
|
||||
extHostLogService: ExtHostLogService
|
||||
): IExtensionApiFactory {
|
||||
|
||||
// Addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
|
||||
const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
|
||||
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol));
|
||||
const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol));
|
||||
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(logService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadEditors)));
|
||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadEditors)));
|
||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostHeapService, logService));
|
||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostHeapService, extHostLogService));
|
||||
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
|
||||
const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace));
|
||||
@@ -111,7 +112,7 @@ export function createApiFactory(
|
||||
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol));
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, logService));
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
@@ -418,6 +419,9 @@ export function createApiFactory(
|
||||
set name(value) {
|
||||
throw errors.readonly();
|
||||
},
|
||||
updateWorkspaceFolders: proposedApiFunction(extension, (index, deleteCount, ...workspaceFoldersToAdd) => {
|
||||
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount, ...workspaceFoldersToAdd);
|
||||
}),
|
||||
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
|
||||
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
|
||||
},
|
||||
@@ -537,7 +541,13 @@ export function createApiFactory(
|
||||
},
|
||||
registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider) {
|
||||
return extHostDebugService.registerDebugConfigurationProvider(debugType, provider);
|
||||
}
|
||||
},
|
||||
addBreakpoints: proposedApiFunction(extension, (breakpoints: vscode.Breakpoint[]) => {
|
||||
return extHostDebugService.addBreakpoints(breakpoints);
|
||||
}),
|
||||
removeBreakpoints: proposedApiFunction(extension, (breakpoints: vscode.Breakpoint[]) => {
|
||||
return extHostDebugService.removeBreakpoints(breakpoints);
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
@@ -556,6 +566,7 @@ export function createApiFactory(
|
||||
Breakpoint: extHostTypes.Breakpoint,
|
||||
CancellationTokenSource: CancellationTokenSource,
|
||||
CodeAction: extHostTypes.CodeAction,
|
||||
CodeActionKind: extHostTypes.CodeActionKind,
|
||||
CodeLens: extHostTypes.CodeLens,
|
||||
Color: extHostTypes.Color,
|
||||
ColorPresentation: extHostTypes.ColorPresentation,
|
||||
|
||||
@@ -4,17 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
createMainContextProxyIdentifier as createMainId,
|
||||
createExtHostContextProxyIdentifier as createExtId,
|
||||
ProxyIdentifier,
|
||||
IRPCProtocol,
|
||||
ProxyType
|
||||
} from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { createMainContextProxyIdentifier as createMainId, createExtHostContextProxyIdentifier as createExtId, ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
@@ -52,8 +46,9 @@ import { IStat, FileChangeType } from 'vs/platform/files/common/files';
|
||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { ILineMatch, IPatternInfo } from 'vs/platform/search/common/search';
|
||||
import { LogLevel } from 'vs/platform/log/common/log';
|
||||
|
||||
export interface IEnvironment {
|
||||
isExtensionDevelopmentDebug: boolean;
|
||||
@@ -71,6 +66,7 @@ export interface IWorkspaceData {
|
||||
id: string;
|
||||
name: string;
|
||||
folders: { uri: UriComponents, name: string, index: number }[];
|
||||
configuration?: UriComponents;
|
||||
}
|
||||
|
||||
export interface IInitData {
|
||||
@@ -83,6 +79,7 @@ export interface IInitData {
|
||||
windowId: number;
|
||||
args: ParsedArgs;
|
||||
execPath: string;
|
||||
logLevel: LogLevel;
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
@@ -192,8 +189,6 @@ export interface IApplyEditsOptions extends IUndoStopOptions {
|
||||
setEndOfLine: EndOfLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface ITextDocumentShowOptions {
|
||||
position?: EditorPosition;
|
||||
preserveFocus?: boolean;
|
||||
@@ -201,16 +196,6 @@ export interface ITextDocumentShowOptions {
|
||||
selection?: IRange;
|
||||
}
|
||||
|
||||
export interface IWorkspaceResourceEdit {
|
||||
resource: UriComponents;
|
||||
modelVersionId?: number;
|
||||
edits: {
|
||||
range?: IRange;
|
||||
newText: string;
|
||||
newEol?: EndOfLineSequence;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface MainThreadEditorsShape extends IDisposable {
|
||||
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string>;
|
||||
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
|
||||
@@ -223,7 +208,7 @@ export interface MainThreadEditorsShape extends IDisposable {
|
||||
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void>;
|
||||
$trySetSelections(id: string, selections: ISelection[]): TPromise<void>;
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean>;
|
||||
$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean>;
|
||||
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto): TPromise<boolean>;
|
||||
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise<boolean>;
|
||||
$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]>;
|
||||
}
|
||||
@@ -364,6 +349,7 @@ export interface MainThreadWorkspaceShape extends IDisposable {
|
||||
$startSearch(includePattern: string, includeFolder: string, excludePattern: string, maxResults: number, requestId: number): Thenable<UriComponents[]>;
|
||||
$cancelSearch(requestId: number): Thenable<boolean>;
|
||||
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
|
||||
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface IFileChangeDto {
|
||||
@@ -383,8 +369,8 @@ export interface MainThreadFileSystemShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadTaskShape extends IDisposable {
|
||||
$registerTaskProvider(handle: number): TPromise<any>;
|
||||
$unregisterTaskProvider(handle: number): TPromise<any>;
|
||||
$registerTaskProvider(handle: number): TPromise<void>;
|
||||
$unregisterTaskProvider(handle: number): TPromise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadExtensionServiceShape extends IDisposable {
|
||||
@@ -457,6 +443,8 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise<any>;
|
||||
$appendDebugConsole(value: string): TPromise<any>;
|
||||
$startBreakpointEvents(): TPromise<any>;
|
||||
$registerBreakpoints(breakpoints: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise<void>;
|
||||
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadWindowShape extends IDisposable {
|
||||
@@ -549,7 +537,7 @@ export interface ExtHostFileSystemShape {
|
||||
$readdir(handle: number, resource: UriComponents): TPromise<[UriComponents, IStat][]>;
|
||||
$rmdir(handle: number, resource: UriComponents): TPromise<void>;
|
||||
$findFiles(handle: number, session: number, query: string): TPromise<void>;
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, include: string, exclude: string): TPromise<void>;
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostExtensionServiceShape {
|
||||
@@ -623,22 +611,44 @@ export interface WorkspaceSymbolsDto extends IdObject {
|
||||
symbols: SymbolInformationDto[];
|
||||
}
|
||||
|
||||
export interface ResourceEditDto {
|
||||
export interface ResourceFileEditDto {
|
||||
oldUri: UriComponents;
|
||||
newUri: UriComponents;
|
||||
}
|
||||
|
||||
export interface ResourceTextEditDto {
|
||||
resource: UriComponents;
|
||||
range: IRange;
|
||||
newText: string;
|
||||
modelVersionId?: number;
|
||||
edits: modes.TextEdit[];
|
||||
}
|
||||
|
||||
export interface WorkspaceEditDto {
|
||||
edits: ResourceEditDto[];
|
||||
edits: (ResourceFileEditDto | ResourceTextEditDto)[];
|
||||
|
||||
// todo@joh reject should go into rename
|
||||
rejectReason?: string;
|
||||
}
|
||||
|
||||
export function reviveWorkspaceEditDto(data: WorkspaceEditDto): modes.WorkspaceEdit {
|
||||
if (data && data.edits) {
|
||||
for (const edit of data.edits) {
|
||||
if (typeof (<ResourceTextEditDto>edit).resource === 'object') {
|
||||
(<ResourceTextEditDto>edit).resource = URI.revive((<ResourceTextEditDto>edit).resource);
|
||||
} else {
|
||||
(<ResourceFileEditDto>edit).newUri = URI.revive((<ResourceFileEditDto>edit).newUri);
|
||||
(<ResourceFileEditDto>edit).oldUri = URI.revive((<ResourceFileEditDto>edit).oldUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
return <modes.WorkspaceEdit>data;
|
||||
}
|
||||
|
||||
export interface CodeActionDto {
|
||||
title: string;
|
||||
edit?: WorkspaceEditDto;
|
||||
diagnostics?: IMarkerData[];
|
||||
command?: modes.Command;
|
||||
kind?: string;
|
||||
}
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
@@ -651,7 +661,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Hover>;
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DocumentHighlight[]>;
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext): TPromise<LocationDto[]>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, range: IRange): TPromise<CodeActionDto[]>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]>;
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
|
||||
@@ -690,30 +700,43 @@ export interface ExtHostTaskShape {
|
||||
$provideTasks(handle: number): TPromise<TaskSet>;
|
||||
}
|
||||
|
||||
export interface IBreakpointData {
|
||||
type: 'source' | 'function';
|
||||
id: string;
|
||||
export interface IFunctionBreakpointDto {
|
||||
type: 'function';
|
||||
id?: string;
|
||||
enabled: boolean;
|
||||
condition?: string;
|
||||
hitCondition?: string;
|
||||
functionName: string;
|
||||
}
|
||||
|
||||
export interface ISourceBreakpointData extends IBreakpointData {
|
||||
export interface ISourceBreakpointDto {
|
||||
type: 'source';
|
||||
id?: string;
|
||||
enabled: boolean;
|
||||
condition?: string;
|
||||
hitCondition?: string;
|
||||
uri: UriComponents;
|
||||
line: number;
|
||||
character: number;
|
||||
}
|
||||
|
||||
export interface IFunctionBreakpointData extends IBreakpointData {
|
||||
type: 'function';
|
||||
functionName: string;
|
||||
export interface IBreakpointsDeltaDto {
|
||||
added?: (ISourceBreakpointDto | IFunctionBreakpointDto)[];
|
||||
removed?: string[];
|
||||
changed?: (ISourceBreakpointDto | IFunctionBreakpointDto)[];
|
||||
}
|
||||
|
||||
export interface IBreakpointsDelta {
|
||||
added?: (ISourceBreakpointData | IFunctionBreakpointData)[];
|
||||
removed?: string[];
|
||||
changed?: (ISourceBreakpointData | IFunctionBreakpointData)[];
|
||||
export interface ISourceMultiBreakpointDto {
|
||||
type: 'sourceMulti';
|
||||
uri: UriComponents;
|
||||
lines: {
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
condition?: string;
|
||||
hitCondition?: string;
|
||||
line: number;
|
||||
character: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface ExtHostDebugServiceShape {
|
||||
@@ -723,7 +746,7 @@ export interface ExtHostDebugServiceShape {
|
||||
$acceptDebugSessionTerminated(id: DebugSessionUUID, type: string, name: string): void;
|
||||
$acceptDebugSessionActiveChanged(id: DebugSessionUUID | undefined, type?: string, name?: string): void;
|
||||
$acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void;
|
||||
$acceptBreakpointsDelta(delat: IBreakpointsDelta): void;
|
||||
$acceptBreakpointsDelta(delat: IBreakpointsDeltaDto): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -744,6 +767,10 @@ export interface ExtHostWindowShape {
|
||||
$onDidChangeWindowFocus(value: boolean): void;
|
||||
}
|
||||
|
||||
export interface ExtHostLogServiceShape {
|
||||
$setLevel(level: LogLevel);
|
||||
}
|
||||
|
||||
// --- proxy identifiers
|
||||
|
||||
export const MainContext = {
|
||||
@@ -772,7 +799,7 @@ export const MainContext = {
|
||||
MainThreadFileSystem: createMainId<MainThreadFileSystemShape>('MainThreadFileSystem'),
|
||||
MainThreadExtensionService: createMainId<MainThreadExtensionServiceShape>('MainThreadExtensionService'),
|
||||
MainThreadSCM: createMainId<MainThreadSCMShape>('MainThreadSCM'),
|
||||
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask', ProxyType.CustomMarshaller),
|
||||
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask'),
|
||||
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
|
||||
};
|
||||
|
||||
@@ -794,10 +821,10 @@ export const ExtHostContext = {
|
||||
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
|
||||
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
|
||||
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
|
||||
// ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
|
||||
ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
|
||||
ExtHostTerminalService: createExtId<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
|
||||
ExtHostSCM: createExtId<ExtHostSCMShape>('ExtHostSCM'),
|
||||
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask', ProxyType.CustomMarshaller),
|
||||
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask'),
|
||||
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
|
||||
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
|
||||
};
|
||||
|
||||
@@ -353,11 +353,7 @@ export class ExtHostApiCommands {
|
||||
if (value.rejectReason) {
|
||||
return TPromise.wrapError<types.WorkspaceEdit>(new Error(value.rejectReason));
|
||||
}
|
||||
let workspaceEdit = new types.WorkspaceEdit();
|
||||
for (let edit of value.edits) {
|
||||
workspaceEdit.replace(edit.resource, typeConverters.toRange(edit.range), edit.newText);
|
||||
}
|
||||
return workspaceEdit;
|
||||
return typeConverters.WorkspaceEdit.to(value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -417,8 +413,11 @@ export class ExtHostApiCommands {
|
||||
} else {
|
||||
const ret = new types.CodeAction(
|
||||
codeAction.title,
|
||||
typeConverters.WorkspaceEdit.to(codeAction.edit)
|
||||
codeAction.kind ? new types.CodeActionKind(codeAction.kind) : undefined
|
||||
);
|
||||
if (codeAction.edit) {
|
||||
ret.edit = typeConverters.WorkspaceEdit.to(codeAction.edit);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID, IMainContext, IBreakpointsDelta, ISourceBreakpointData, IFunctionBreakpointData } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import {
|
||||
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
|
||||
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto
|
||||
} from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
|
||||
export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
@@ -95,51 +99,161 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
public $acceptBreakpointsDelta(delta: IBreakpointsDelta): void {
|
||||
public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {
|
||||
|
||||
let a: vscode.Breakpoint[] = [];
|
||||
let r: vscode.Breakpoint[] = [];
|
||||
let c: vscode.Breakpoint[] = [];
|
||||
|
||||
if (delta.added) {
|
||||
a = delta.added.map(bpd => {
|
||||
const bp = this.fromWire(bpd);
|
||||
this._breakpoints.set(bpd.id, bp);
|
||||
return bp;
|
||||
});
|
||||
for (const bpd of delta.added) {
|
||||
|
||||
if (!this._breakpoints.has(bpd.id)) {
|
||||
let bp: vscode.Breakpoint;
|
||||
if (bpd.type === 'function') {
|
||||
bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition);
|
||||
} else {
|
||||
const uri = URI.revive(bpd.uri);
|
||||
bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition);
|
||||
}
|
||||
bp['_id'] = bpd.id;
|
||||
this._breakpoints.set(bpd.id, bp);
|
||||
a.push(bp);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.removed) {
|
||||
r = delta.removed.map(id => {
|
||||
for (const id of delta.removed) {
|
||||
const bp = this._breakpoints.get(id);
|
||||
if (bp) {
|
||||
this._breakpoints.delete(id);
|
||||
r.push(bp);
|
||||
}
|
||||
return bp;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.changed) {
|
||||
c = delta.changed.map(bpd => {
|
||||
const bp = this.fromWire(bpd);
|
||||
this._breakpoints.set(bpd.id, bp);
|
||||
return bp;
|
||||
});
|
||||
for (const bpd of delta.changed) {
|
||||
let bp = this._breakpoints.get(bpd.id);
|
||||
if (bp) {
|
||||
if (bpd.type === 'function') {
|
||||
const fbp = <any>bp;
|
||||
fbp.enabled = bpd.enabled;
|
||||
fbp.condition = bpd.condition;
|
||||
fbp.hitCondition = bpd.hitCondition;
|
||||
fbp.functionName = bpd.functionName;
|
||||
} else {
|
||||
const sbp = <any>bp;
|
||||
sbp.enabled = bpd.enabled;
|
||||
sbp.condition = bpd.condition;
|
||||
sbp.hitCondition = bpd.hitCondition;
|
||||
}
|
||||
c.push(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidChangeBreakpoints.fire(Object.freeze({
|
||||
added: Object.freeze<vscode.Breakpoint[]>(a || []),
|
||||
removed: Object.freeze<vscode.Breakpoint[]>(r || []),
|
||||
changed: Object.freeze<vscode.Breakpoint[]>(c || [])
|
||||
}));
|
||||
this.fireBreakpointChanges(a, r, c);
|
||||
}
|
||||
|
||||
private fromWire(bp: ISourceBreakpointData | IFunctionBreakpointData): vscode.Breakpoint {
|
||||
if (bp.type === 'function') {
|
||||
return new FunctionBreakpoint(bp.enabled, bp.condition, bp.hitCondition, bp.functionName);
|
||||
public addBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise<void> {
|
||||
|
||||
this.startBreakpoints();
|
||||
|
||||
// assign uuids for brand new breakpoints
|
||||
const breakpoints: vscode.Breakpoint[] = [];
|
||||
for (const bp of breakpoints0) {
|
||||
let id = bp['_id'];
|
||||
if (id) { // has already id
|
||||
if (this._breakpoints.has(id)) {
|
||||
// already there
|
||||
} else {
|
||||
breakpoints.push(bp);
|
||||
}
|
||||
} else {
|
||||
id = generateUuid();
|
||||
bp['_id'] = id;
|
||||
this._breakpoints.set(id, bp);
|
||||
breakpoints.push(bp);
|
||||
}
|
||||
}
|
||||
|
||||
// send notification for added breakpoints
|
||||
this.fireBreakpointChanges(breakpoints, [], []);
|
||||
|
||||
// convert added breakpoints to DTOs
|
||||
const dtos: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[] = [];
|
||||
const map = new Map<string, ISourceMultiBreakpointDto>();
|
||||
for (const bp of breakpoints) {
|
||||
if (bp instanceof SourceBreakpoint) {
|
||||
let dto = map.get(bp.location.uri.toString());
|
||||
if (!dto) {
|
||||
dto = <ISourceMultiBreakpointDto>{
|
||||
type: 'sourceMulti',
|
||||
uri: bp.location.uri,
|
||||
lines: []
|
||||
};
|
||||
map.set(bp.location.uri.toString(), dto);
|
||||
dtos.push(dto);
|
||||
}
|
||||
dto.lines.push({
|
||||
id: bp['_id'],
|
||||
enabled: bp.enabled,
|
||||
condition: bp.condition,
|
||||
hitCondition: bp.hitCondition,
|
||||
line: bp.location.range.start.line,
|
||||
character: bp.location.range.start.character
|
||||
});
|
||||
} else if (bp instanceof FunctionBreakpoint) {
|
||||
dtos.push({
|
||||
type: 'function',
|
||||
id: bp['_id'],
|
||||
enabled: bp.enabled,
|
||||
functionName: bp.functionName,
|
||||
hitCondition: bp.hitCondition,
|
||||
condition: bp.condition
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// send DTOs to VS Code
|
||||
return this._debugServiceProxy.$registerBreakpoints(dtos);
|
||||
}
|
||||
|
||||
public removeBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise<void> {
|
||||
|
||||
this.startBreakpoints();
|
||||
|
||||
// remove from array
|
||||
const breakpoints: vscode.Breakpoint[] = [];
|
||||
for (const b of breakpoints0) {
|
||||
let id = b['_id'];
|
||||
if (id && this._breakpoints.delete(id)) {
|
||||
breakpoints.push(b);
|
||||
}
|
||||
}
|
||||
|
||||
// send notification
|
||||
this.fireBreakpointChanges([], breakpoints, []);
|
||||
|
||||
// unregister with VS Code
|
||||
const ids = breakpoints.filter(bp => bp instanceof SourceBreakpoint).map(bp => bp['_id']);
|
||||
const fids = breakpoints.filter(bp => bp instanceof FunctionBreakpoint).map(bp => bp['_id']);
|
||||
return this._debugServiceProxy.$unregisterBreakpoints(ids, fids);
|
||||
}
|
||||
|
||||
private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) {
|
||||
if (added.length > 0 || removed.length > 0 || changed.length > 0) {
|
||||
this._onDidChangeBreakpoints.fire(Object.freeze({
|
||||
added: Object.freeze<vscode.Breakpoint[]>(added),
|
||||
removed: Object.freeze<vscode.Breakpoint[]>(removed),
|
||||
changed: Object.freeze<vscode.Breakpoint[]>(changed)
|
||||
}));
|
||||
}
|
||||
const uri = URI.revive(bp.uri);
|
||||
return new SourceBreakpoint(bp.enabled, bp.condition, bp.hitCondition, new Location(uri, new Position(bp.line, bp.character)));
|
||||
}
|
||||
|
||||
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable {
|
||||
|
||||
@@ -8,7 +8,7 @@ import Event from 'vs/base/common/event';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { sequence, always } from 'vs/base/common/async';
|
||||
import { illegalState } from 'vs/base/common/errors';
|
||||
import { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, ResourceTextEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { TextEdit } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { fromRange, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
@@ -142,7 +142,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
|
||||
|
||||
}).then(values => {
|
||||
|
||||
let workspaceResourceEdit: IWorkspaceResourceEdit = {
|
||||
const resourceEdit: ResourceTextEditDto = {
|
||||
resource: document.uri,
|
||||
edits: []
|
||||
};
|
||||
@@ -150,10 +150,10 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
|
||||
for (const value of values) {
|
||||
if (Array.isArray(value) && (<vscode.TextEdit[]>value).every(e => e instanceof TextEdit)) {
|
||||
for (const { newText, newEol, range } of value) {
|
||||
workspaceResourceEdit.edits.push({
|
||||
resourceEdit.edits.push({
|
||||
range: range && fromRange(range),
|
||||
newText,
|
||||
newEol: EndOfLine.from(newEol)
|
||||
text: newText,
|
||||
eol: EndOfLine.from(newEol)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -161,12 +161,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
|
||||
|
||||
// apply edits if any and if document
|
||||
// didn't change somehow in the meantime
|
||||
if (workspaceResourceEdit.edits.length === 0) {
|
||||
if (resourceEdit.edits.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (version === document.version) {
|
||||
return this._mainThreadEditors.$tryApplyWorkspaceEdit([workspaceResourceEdit]);
|
||||
return this._mainThreadEditors.$tryApplyWorkspaceEdit({ edits: [resourceEdit] });
|
||||
}
|
||||
|
||||
// TODO@joh bubble this to listener?
|
||||
|
||||
@@ -22,6 +22,7 @@ import { Barrier } from 'vs/base/common/async';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
class ExtensionMemento implements IExtensionMemento {
|
||||
|
||||
@@ -106,7 +107,11 @@ class ExtensionStoragePath {
|
||||
await mkdirp(storagePath);
|
||||
await writeFile(
|
||||
join(storagePath, 'meta.json'),
|
||||
JSON.stringify({ id: this._workspace.id })
|
||||
JSON.stringify({
|
||||
id: this._workspace.id,
|
||||
configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(),
|
||||
name: this._workspace.name
|
||||
}, undefined, 2)
|
||||
);
|
||||
return storagePath;
|
||||
|
||||
@@ -125,7 +130,6 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
private readonly _storage: ExtHostStorage;
|
||||
private readonly _storagePath: ExtensionStoragePath;
|
||||
private readonly _proxy: MainThreadExtensionServiceShape;
|
||||
private readonly _logService: ILogService;
|
||||
private readonly _extHostLogService: ExtHostLogService;
|
||||
private _activator: ExtensionsActivator;
|
||||
private _extensionPathIndex: TPromise<TernarySearchTree<IExtensionDescription>>;
|
||||
@@ -136,21 +140,20 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
extHostContext: IExtHostContext,
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
logService: ILogService,
|
||||
extHostLogService: ExtHostLogService,
|
||||
environmentService: IEnvironmentService
|
||||
) {
|
||||
this._barrier = new Barrier();
|
||||
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
|
||||
this._logService = logService;
|
||||
this._extHostLogService = extHostLogService;
|
||||
this._mainThreadTelemetry = extHostContext.getProxy(MainContext.MainThreadTelemetry);
|
||||
this._storage = new ExtHostStorage(extHostContext);
|
||||
this._storagePath = new ExtensionStoragePath(initData.workspace, initData.environment);
|
||||
this._proxy = extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
||||
this._activator = null;
|
||||
this._extHostLogService = new ExtHostLogService(environmentService);
|
||||
|
||||
// initialize API first (i.e. do not release barrier until the API is initialized)
|
||||
const apiFactory = createApiFactory(initData, extHostContext, extHostWorkspace, extHostConfiguration, this, logService);
|
||||
const apiFactory = createApiFactory(initData, extHostContext, extHostWorkspace, extHostConfiguration, this, this._extHostLogService);
|
||||
|
||||
initializeExtensionApi(this, apiFactory).then(() => {
|
||||
|
||||
@@ -311,14 +314,14 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
return TPromise.as(new EmptyExtension(ExtensionActivationTimes.NONE));
|
||||
}
|
||||
|
||||
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.id} ${JSON.stringify(reason)}`);
|
||||
this._extHostLogService.info(`ExtensionService#_doActivateExtension ${extensionDescription.id} ${JSON.stringify(reason)}`);
|
||||
|
||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||
return TPromise.join<any>([
|
||||
loadCommonJSModule(this._logService, extensionDescription.main, activationTimesBuilder),
|
||||
loadCommonJSModule(this._extHostLogService, extensionDescription.main, activationTimesBuilder),
|
||||
this._loadExtensionContext(extensionDescription)
|
||||
]).then(values => {
|
||||
return ExtHostExtensionService._callActivate(this._logService, extensionDescription.id, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
||||
return ExtHostExtensionService._callActivate(this._extHostLogService, extensionDescription.id, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
||||
}, (errors: any[]) => {
|
||||
// Avoid failing with an array of errors, fail with a single error
|
||||
if (errors[0]) {
|
||||
@@ -336,7 +339,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
let globalState = new ExtensionMemento(extensionDescription.id, true, this._storage);
|
||||
let workspaceState = new ExtensionMemento(extensionDescription.id, false, this._storage);
|
||||
|
||||
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.id}`);
|
||||
this._extHostLogService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.id}`);
|
||||
return TPromise.join([
|
||||
globalState.whenReady,
|
||||
workspaceState.whenReady,
|
||||
|
||||
@@ -137,7 +137,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
};
|
||||
return asWinJsPromise(token => provider.findFiles(query, progress, token));
|
||||
}
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, include: string, exclude: string): TPromise<void> {
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void> {
|
||||
const provider = this._provider.get(handle);
|
||||
if (!provider.provideTextSearchResults) {
|
||||
return TPromise.as(undefined);
|
||||
@@ -151,6 +151,6 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
}]);
|
||||
}
|
||||
};
|
||||
return asWinJsPromise(token => provider.provideTextSearchResults(pattern, include, exclude, progress, token));
|
||||
return asWinJsPromise(token => provider.provideTextSearchResults(pattern, options, progress, token));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range, Disposable, CompletionList, SnippetString, Color, CodeActionKind } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
@@ -17,7 +17,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostDiagnostics, DiagnosticCollection } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, SymbolInformationDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto } from './extHost.protocol';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, SymbolInformationDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto } from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
@@ -255,7 +255,7 @@ class ReferenceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
export interface CustomCodeAction extends modes.CodeAction {
|
||||
export interface CustomCodeAction extends CodeActionDto {
|
||||
_isSynthetic?: boolean;
|
||||
}
|
||||
|
||||
@@ -273,7 +273,8 @@ class CodeActionAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideCodeActions(resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
|
||||
|
||||
provideCodeActions(resource: URI, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
|
||||
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const ran = <vscode.Range>TypeConverters.toRange(range);
|
||||
@@ -289,8 +290,12 @@ class CodeActionAdapter {
|
||||
}
|
||||
});
|
||||
|
||||
const codeActionContext: vscode.CodeActionContext = {
|
||||
diagnostics: allDiagnostics,
|
||||
only: context.only ? new CodeActionKind(context.only) : undefined
|
||||
};
|
||||
return asWinJsPromise(token =>
|
||||
this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)
|
||||
this._provider.provideCodeActions(doc, ran, codeActionContext, token)
|
||||
).then(commandsOrActions => {
|
||||
if (isFalsyOrEmpty(commandsOrActions)) {
|
||||
return undefined;
|
||||
@@ -314,6 +319,7 @@ class CodeActionAdapter {
|
||||
command: candidate.command && this._commands.toInternal(candidate.command),
|
||||
diagnostics: candidate.diagnostics && candidate.diagnostics.map(DiagnosticCollection.toMarkerData),
|
||||
edit: candidate.edit && TypeConverters.WorkspaceEdit.from(candidate.edit),
|
||||
kind: candidate.kind && candidate.kind.value
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -963,8 +969,9 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideCodeActions(handle: number, resource: UriComponents, range: IRange): TPromise<modes.CodeAction[]> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), range));
|
||||
|
||||
$provideCodeActions(handle: number, resource: UriComponents, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), range, context));
|
||||
}
|
||||
|
||||
// --- formatting
|
||||
|
||||
@@ -4,51 +4,65 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { join } from 'vs/base/common/paths';
|
||||
import { mkdirp, dirExists } from 'vs/base/node/pfs';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import Event from 'vs/base/common/event';
|
||||
import { LogLevel } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, DelegatedLogService } from 'vs/platform/log/common/log';
|
||||
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { ExtHostLogServiceShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
|
||||
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
|
||||
|
||||
export class ExtHostLogService {
|
||||
private _loggers: Map<string, ExtHostLogger> = new Map();
|
||||
|
||||
constructor(private _environmentService: IEnvironmentService) {
|
||||
constructor(
|
||||
windowId: number,
|
||||
logLevel: LogLevel,
|
||||
private _environmentService: IEnvironmentService
|
||||
) {
|
||||
super(createSpdLogService(`exthost${windowId}`, logLevel, _environmentService.logsPath));
|
||||
}
|
||||
|
||||
$setLevel(level: LogLevel): void {
|
||||
this.setLevel(level);
|
||||
}
|
||||
|
||||
getExtLogger(extensionID: string): ExtHostLogger {
|
||||
if (!this._loggers.has(extensionID)) {
|
||||
const logService = createSpdLogService(extensionID, this._environmentService, extensionID);
|
||||
const logsDirPath = path.join(this._environmentService.logsPath, extensionID);
|
||||
this._loggers.set(extensionID, new ExtHostLogger(logService, logsDirPath));
|
||||
let logger = this._loggers.get(extensionID);
|
||||
if (!logger) {
|
||||
logger = this.createLogger(extensionID);
|
||||
this._loggers.set(extensionID, logger);
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
return this._loggers.get(extensionID);
|
||||
private createLogger(extensionID: string): ExtHostLogger {
|
||||
const logsDirPath = join(this._environmentService.logsPath, extensionID);
|
||||
const logService = createSpdLogService(extensionID, this.getLevel(), logsDirPath);
|
||||
this._register(this.onDidChangeLogLevel(level => logService.setLevel(level)));
|
||||
return new ExtHostLogger(logService, logsDirPath);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostLogger implements vscode.Logger {
|
||||
private _currentLevel: LogLevel;
|
||||
private _onDidChangeLogLevel: Emitter<LogLevel>;
|
||||
|
||||
constructor(
|
||||
private readonly _logService: ILogService,
|
||||
private readonly _logDirectory: string
|
||||
) {
|
||||
this._currentLevel = this._logService.getLevel();
|
||||
this._onDidChangeLogLevel = new Emitter<LogLevel>();
|
||||
this.onDidChangeLogLevel = this._onDidChangeLogLevel.event;
|
||||
}
|
||||
|
||||
// TODO
|
||||
readonly onDidChangeLogLevel: Event<LogLevel>;
|
||||
get onDidChangeLogLevel(): Event<LogLevel> {
|
||||
return this._logService.onDidChangeLogLevel;
|
||||
}
|
||||
|
||||
get currentLevel(): LogLevel { return this._currentLevel; }
|
||||
get currentLevel(): LogLevel { return this._logService.getLevel(); }
|
||||
|
||||
@memoize
|
||||
get logDirectory(): TPromise<string> {
|
||||
|
||||
@@ -294,11 +294,11 @@ namespace ShellConfiguration {
|
||||
|
||||
namespace Tasks {
|
||||
|
||||
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.Task[] {
|
||||
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask[] {
|
||||
if (tasks === void 0 || tasks === null) {
|
||||
return [];
|
||||
}
|
||||
let result: TaskSystem.Task[] = [];
|
||||
let result: TaskSystem.ContributedTask[] = [];
|
||||
for (let task of tasks) {
|
||||
let converted = fromSingle(task, rootFolder, extension);
|
||||
if (converted) {
|
||||
@@ -351,7 +351,7 @@ namespace Tasks {
|
||||
// We can't transfer a workspace folder object from the extension host to main since they differ
|
||||
// in shape and we don't have backwards converting function. So transfer the URI and resolve the
|
||||
// workspace folder on the main side.
|
||||
(source as any).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
|
||||
(source as any as TaskSystem.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
|
||||
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
|
||||
let key = (task as types.Task).definitionKey;
|
||||
let kind = (task as types.Task).definition;
|
||||
|
||||
@@ -12,7 +12,7 @@ import * as TypeConverters from './extHostTypeConverters';
|
||||
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
|
||||
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
|
||||
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
|
||||
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, IWorkspaceResourceEdit } from './extHost.protocol';
|
||||
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, WorkspaceEditDto } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
@@ -92,36 +92,23 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
|
||||
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
|
||||
|
||||
let workspaceResourceEdits: IWorkspaceResourceEdit[] = [];
|
||||
const dto: WorkspaceEditDto = { edits: [] };
|
||||
|
||||
let entries = edit.entries();
|
||||
for (let entry of entries) {
|
||||
let [uri, edits] = entry;
|
||||
|
||||
let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString());
|
||||
let docVersion: number = undefined;
|
||||
if (doc) {
|
||||
docVersion = doc.version;
|
||||
}
|
||||
|
||||
let workspaceResourceEdit: IWorkspaceResourceEdit = {
|
||||
resource: uri,
|
||||
modelVersionId: docVersion,
|
||||
edits: []
|
||||
};
|
||||
|
||||
for (let edit of edits) {
|
||||
workspaceResourceEdit.edits.push({
|
||||
newText: edit.newText,
|
||||
newEol: TypeConverters.EndOfLine.from(edit.newEol),
|
||||
range: edit.range && TypeConverters.fromRange(edit.range)
|
||||
for (let entry of edit.allEntries()) {
|
||||
let [uri, uriOrEdits] = entry;
|
||||
if (Array.isArray(uriOrEdits)) {
|
||||
let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString());
|
||||
dto.edits.push({
|
||||
resource: uri,
|
||||
modelVersionId: doc && doc.version,
|
||||
edits: uriOrEdits.map(TypeConverters.TextEdit.from)
|
||||
});
|
||||
} else {
|
||||
dto.edits.push({ oldUri: uri, newUri: uriOrEdits });
|
||||
}
|
||||
|
||||
workspaceResourceEdits.push(workspaceResourceEdit);
|
||||
}
|
||||
|
||||
return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits);
|
||||
return this._proxy.$tryApplyWorkspaceEdit(dto);
|
||||
}
|
||||
|
||||
// --- called from main thread
|
||||
|
||||
@@ -114,7 +114,7 @@ class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
return null;
|
||||
})
|
||||
))).then(extTreeItems => extTreeItems.map((({ element, extTreeItem }) => this.createTreeItem(element, extTreeItem, parentHandle))));
|
||||
))).then(extTreeItems => coalesce(extTreeItems).map((({ element, extTreeItem }) => this.createTreeItem(element, extTreeItem, parentHandle))));
|
||||
}
|
||||
|
||||
getExtensionElement(treeItemHandle: TreeItemHandle): T {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import * as htmlContent from 'vs/base/common/htmlContent';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { LanguageSelector, LanguageFilter } from 'vs/editor/common/modes/languageSelector';
|
||||
import { WorkspaceEditDto, ResourceTextEditDto, ResourceFileEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
export interface PositionLike {
|
||||
line: number;
|
||||
@@ -228,24 +229,36 @@ export const TextEdit = {
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
export function from(value: vscode.WorkspaceEdit): modes.WorkspaceEdit {
|
||||
const result: modes.WorkspaceEdit = { edits: [] };
|
||||
for (let entry of value.entries()) {
|
||||
let [uri, textEdits] = entry;
|
||||
for (let textEdit of textEdits) {
|
||||
result.edits.push({
|
||||
resource: uri,
|
||||
newText: textEdit.newText,
|
||||
range: fromRange(textEdit.range)
|
||||
});
|
||||
const result: modes.WorkspaceEdit = {
|
||||
edits: []
|
||||
};
|
||||
for (const entry of value.allEntries()) {
|
||||
const [uri, uriOrEdits] = entry;
|
||||
if (Array.isArray(uriOrEdits)) {
|
||||
// text edits
|
||||
result.edits.push({ resource: uri, edits: uriOrEdits.map(TextEdit.from) });
|
||||
} else {
|
||||
// resource edits
|
||||
result.edits.push({ oldUri: uri, newUri: uriOrEdits });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function to(value: modes.WorkspaceEdit) {
|
||||
export function to(value: WorkspaceEditDto) {
|
||||
const result = new types.WorkspaceEdit();
|
||||
for (const edit of value.edits) {
|
||||
result.replace(edit.resource, toRange(edit.range), edit.newText);
|
||||
if (Array.isArray((<ResourceTextEditDto>edit).edits)) {
|
||||
result.set(
|
||||
URI.revive((<ResourceTextEditDto>edit).resource),
|
||||
<types.TextEdit[]>(<ResourceTextEditDto>edit).edits.map(TextEdit.to)
|
||||
);
|
||||
} else {
|
||||
result.renameResource(
|
||||
URI.revive((<ResourceFileEditDto>edit).oldUri),
|
||||
URI.revive((<ResourceFileEditDto>edit).newUri)
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as vscode from 'vscode';
|
||||
import { isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { relative } from 'path';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
|
||||
export class Disposable {
|
||||
|
||||
@@ -491,10 +492,28 @@ export class TextEdit {
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkspaceEdit {
|
||||
export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
|
||||
private _values: [URI, TextEdit[]][] = [];
|
||||
private _index = new Map<string, number>();
|
||||
private _seqPool: number = 0;
|
||||
|
||||
private _resourceEdits: { seq: number, from: URI, to: URI }[] = [];
|
||||
private _textEdits = new Map<string, { seq: number, uri: URI, edits: TextEdit[] }>();
|
||||
|
||||
createResource(uri: vscode.Uri): void {
|
||||
this.renameResource(undefined, uri);
|
||||
}
|
||||
|
||||
deleteResource(uri: vscode.Uri): void {
|
||||
this.renameResource(uri, undefined);
|
||||
}
|
||||
|
||||
renameResource(from: vscode.Uri, to: vscode.Uri): void {
|
||||
this._resourceEdits.push({ seq: this._seqPool++, from, to });
|
||||
}
|
||||
|
||||
resourceEdits(): [vscode.Uri, vscode.Uri][] {
|
||||
return this._resourceEdits.map(({ from, to }) => (<[vscode.Uri, vscode.Uri]>[from, to]));
|
||||
}
|
||||
|
||||
replace(uri: URI, range: Range, newText: string): void {
|
||||
let edit = new TextEdit(range, newText);
|
||||
@@ -502,8 +521,9 @@ export class WorkspaceEdit {
|
||||
if (array) {
|
||||
array.push(edit);
|
||||
} else {
|
||||
this.set(uri, [edit]);
|
||||
array = [edit];
|
||||
}
|
||||
this.set(uri, array);
|
||||
}
|
||||
|
||||
insert(resource: URI, position: Position, newText: string): void {
|
||||
@@ -515,34 +535,58 @@ export class WorkspaceEdit {
|
||||
}
|
||||
|
||||
has(uri: URI): boolean {
|
||||
return this._index.has(uri.toString());
|
||||
return this._textEdits.has(uri.toString());
|
||||
}
|
||||
|
||||
set(uri: URI, edits: TextEdit[]): void {
|
||||
const idx = this._index.get(uri.toString());
|
||||
if (typeof idx === 'undefined') {
|
||||
let newLen = this._values.push([uri, edits]);
|
||||
this._index.set(uri.toString(), newLen - 1);
|
||||
let data = this._textEdits.get(uri.toString());
|
||||
if (!data) {
|
||||
data = { seq: this._seqPool++, uri, edits: [] };
|
||||
this._textEdits.set(uri.toString(), data);
|
||||
}
|
||||
if (!edits) {
|
||||
data.edits = undefined;
|
||||
} else {
|
||||
this._values[idx][1] = edits;
|
||||
data.edits = edits.slice(0);
|
||||
}
|
||||
}
|
||||
|
||||
get(uri: URI): TextEdit[] {
|
||||
let idx = this._index.get(uri.toString());
|
||||
return typeof idx !== 'undefined' && this._values[idx][1];
|
||||
if (!this._textEdits.has(uri.toString())) {
|
||||
return undefined;
|
||||
}
|
||||
const { edits } = this._textEdits.get(uri.toString());
|
||||
return edits ? edits.slice() : undefined;
|
||||
}
|
||||
|
||||
entries(): [URI, TextEdit[]][] {
|
||||
return this._values;
|
||||
const res: [URI, TextEdit[]][] = [];
|
||||
this._textEdits.forEach(value => res.push([value.uri, value.edits]));
|
||||
return res.slice();
|
||||
}
|
||||
|
||||
allEntries(): ([URI, TextEdit[]] | [URI, URI])[] {
|
||||
// use the 'seq' the we have assigned when inserting
|
||||
// the operation and use that order in the resulting
|
||||
// array
|
||||
const res: ([URI, TextEdit[]] | [URI, URI])[] = [];
|
||||
this._textEdits.forEach(value => {
|
||||
const { seq, uri, edits } = value;
|
||||
res[seq] = [uri, edits];
|
||||
});
|
||||
this._resourceEdits.forEach(value => {
|
||||
const { seq, from, to } = value;
|
||||
res[seq] = [from, to];
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._values.length;
|
||||
return this._textEdits.size + this._resourceEdits.length;
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
return this._values;
|
||||
return this.entries();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -818,12 +862,39 @@ export class CodeAction {
|
||||
|
||||
dianostics?: Diagnostic[];
|
||||
|
||||
constructor(title: string, edit?: WorkspaceEdit) {
|
||||
kind?: CodeActionKind;
|
||||
|
||||
constructor(title: string, kind?: CodeActionKind) {
|
||||
this.title = title;
|
||||
this.edit = edit;
|
||||
this.kind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class CodeActionKind {
|
||||
private static readonly sep = '.';
|
||||
|
||||
public static readonly Empty = new CodeActionKind('');
|
||||
public static readonly QuickFix = CodeActionKind.Empty.append('quickfix');
|
||||
public static readonly Refactor = CodeActionKind.Empty.append('refactor');
|
||||
public static readonly RefactorExtract = CodeActionKind.Refactor.append('extract');
|
||||
public static readonly RefactorInline = CodeActionKind.Refactor.append('inline');
|
||||
public static readonly RefactorRewrite = CodeActionKind.Refactor.append('rewrite');
|
||||
|
||||
constructor(
|
||||
public readonly value: string
|
||||
) { }
|
||||
|
||||
public append(parts: string): CodeActionKind {
|
||||
return new CodeActionKind(this.value ? this.value + CodeActionKind.sep + parts : parts);
|
||||
}
|
||||
|
||||
public contains(other: CodeActionKind): boolean {
|
||||
return this.value === other.value || startsWith(other.value, this.value + CodeActionKind.sep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class CodeLens {
|
||||
|
||||
range: Range;
|
||||
@@ -1510,19 +1581,21 @@ export class Breakpoint {
|
||||
readonly condition?: string;
|
||||
readonly hitCondition?: string;
|
||||
|
||||
protected constructor(enabled: boolean, condition: string, hitCondition: string) {
|
||||
this.enabled = enabled;
|
||||
this.condition = condition;
|
||||
this.hitCondition = hitCondition;
|
||||
this.condition = condition;
|
||||
this.hitCondition = hitCondition;
|
||||
protected constructor(enabled?: boolean, condition?: string, hitCondition?: string) {
|
||||
this.enabled = typeof enabled === 'boolean' ? enabled : true;
|
||||
if (typeof condition === 'string') {
|
||||
this.condition = condition;
|
||||
}
|
||||
if (typeof hitCondition === 'string') {
|
||||
this.hitCondition = hitCondition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceBreakpoint extends Breakpoint {
|
||||
readonly location: Location;
|
||||
|
||||
constructor(enabled: boolean, condition: string, hitCondition: string, location: Location) {
|
||||
constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string) {
|
||||
super(enabled, condition, hitCondition);
|
||||
this.location = location;
|
||||
}
|
||||
@@ -1531,7 +1604,7 @@ export class SourceBreakpoint extends Breakpoint {
|
||||
export class FunctionBreakpoint extends Breakpoint {
|
||||
readonly functionName: string;
|
||||
|
||||
constructor(enabled: boolean, condition: string, hitCondition: string, functionName: string) {
|
||||
constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string) {
|
||||
super(enabled, condition, hitCondition);
|
||||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
@@ -7,40 +7,109 @@
|
||||
import URI from 'vs/base/common/uri';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { normalize } from 'vs/base/common/paths';
|
||||
import { delta } from 'vs/base/common/arrays';
|
||||
import { delta as arrayDelta } from 'vs/base/common/arrays';
|
||||
import { relative, dirname } from 'path';
|
||||
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol';
|
||||
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext, MainThreadMessageServiceShape } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { basenameOrAuthority, isEqual } from 'vs/base/common/resources';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { Severity } from 'vs/platform/message/common/message';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
class Workspace2 extends Workspace {
|
||||
function isFolderEqual(folderA: URI, folderB: URI): boolean {
|
||||
return isEqual(folderA, folderB, !isLinux);
|
||||
}
|
||||
|
||||
static fromData(data: IWorkspaceData) {
|
||||
function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
|
||||
return isFolderEqual(a.uri, b.uri) ? 0 : compare(a.uri.toString(), b.uri.toString());
|
||||
}
|
||||
|
||||
function compareWorkspaceFolderByUriAndNameAndIndex(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
|
||||
if (a.index !== b.index) {
|
||||
return a.index < b.index ? -1 : 1;
|
||||
}
|
||||
|
||||
return isFolderEqual(a.uri, b.uri) ? compare(a.name, b.name) : compare(a.uri.toString(), b.uri.toString());
|
||||
}
|
||||
|
||||
function delta(oldFolders: vscode.WorkspaceFolder[], newFolders: vscode.WorkspaceFolder[], compare: (a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder) => number): { removed: vscode.WorkspaceFolder[], added: vscode.WorkspaceFolder[] } {
|
||||
const oldSortedFolders = oldFolders.slice(0).sort(compare);
|
||||
const newSortedFolders = newFolders.slice(0).sort(compare);
|
||||
|
||||
return arrayDelta(oldSortedFolders, newSortedFolders, compare);
|
||||
}
|
||||
|
||||
interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
|
||||
name: string;
|
||||
index: number;
|
||||
}
|
||||
|
||||
class ExtHostWorkspaceImpl extends Workspace {
|
||||
|
||||
static toExtHostWorkspace(data: IWorkspaceData, previousConfirmedWorkspace?: ExtHostWorkspaceImpl, previousUnconfirmedWorkspace?: ExtHostWorkspaceImpl): { workspace: ExtHostWorkspaceImpl, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } {
|
||||
if (!data) {
|
||||
return null;
|
||||
} else {
|
||||
const { id, name, folders } = data;
|
||||
return new Workspace2(
|
||||
id,
|
||||
name,
|
||||
folders.map(({ uri, name, index }) => new WorkspaceFolder({ name, index, uri: URI.revive(uri) }))
|
||||
);
|
||||
return { workspace: null, added: [], removed: [] };
|
||||
}
|
||||
|
||||
const { id, name, folders } = data;
|
||||
const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
|
||||
|
||||
// If we have an existing workspace, we try to find the folders that match our
|
||||
// data and update their properties. It could be that an extension stored them
|
||||
// for later use and we want to keep them "live" if they are still present.
|
||||
const oldWorkspace = previousConfirmedWorkspace;
|
||||
if (oldWorkspace) {
|
||||
folders.forEach((folderData, index) => {
|
||||
const folderUri = URI.revive(folderData.uri);
|
||||
const existingFolder = ExtHostWorkspaceImpl._findFolder(previousUnconfirmedWorkspace || previousConfirmedWorkspace, folderUri);
|
||||
|
||||
if (existingFolder) {
|
||||
existingFolder.name = folderData.name;
|
||||
existingFolder.index = folderData.index;
|
||||
|
||||
newWorkspaceFolders.push(existingFolder);
|
||||
} else {
|
||||
newWorkspaceFolders.push({ uri: folderUri, name: folderData.name, index });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
newWorkspaceFolders.push(...folders.map(({ uri, name, index }) => ({ uri: URI.revive(uri), name, index })));
|
||||
}
|
||||
|
||||
// make sure to restore sort order based on index
|
||||
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
|
||||
|
||||
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders);
|
||||
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri);
|
||||
|
||||
return { workspace, added, removed };
|
||||
}
|
||||
|
||||
private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI): MutableWorkspaceFolder {
|
||||
for (let i = 0; i < workspace.folders.length; i++) {
|
||||
const folder = workspace.workspaceFolders[i];
|
||||
if (isFolderEqual(folder.uri, folderUriToFind)) {
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
|
||||
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
|
||||
|
||||
private constructor(id: string, name: string, folders: WorkspaceFolder[]) {
|
||||
super(id, name, folders);
|
||||
private constructor(id: string, name: string, folders: vscode.WorkspaceFolder[]) {
|
||||
super(id, name, folders.map(f => new WorkspaceFolder(f)));
|
||||
|
||||
// setup the workspace folder data structure
|
||||
this.folders.forEach(({ name, uri, index }) => {
|
||||
const workspaceFolder = { name, uri, index };
|
||||
this._workspaceFolders.push(workspaceFolder);
|
||||
this._structure.set(workspaceFolder.uri.toString(), workspaceFolder);
|
||||
folders.forEach(folder => {
|
||||
this._workspaceFolders.push(folder);
|
||||
this._structure.set(folder.uri.toString(), folder);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,44 +132,116 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
|
||||
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
|
||||
private readonly _proxy: MainThreadWorkspaceShape;
|
||||
private _workspace: Workspace2;
|
||||
|
||||
private _confirmedWorkspace: ExtHostWorkspaceImpl;
|
||||
private _unconfirmedWorkspace: ExtHostWorkspaceImpl;
|
||||
|
||||
private _messageService: MainThreadMessageServiceShape;
|
||||
|
||||
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
|
||||
|
||||
constructor(mainContext: IMainContext, data: IWorkspaceData) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
this._workspace = Workspace2.fromData(data);
|
||||
this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService);
|
||||
this._confirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace(data).workspace;
|
||||
}
|
||||
|
||||
// --- workspace ---
|
||||
|
||||
get workspace(): Workspace {
|
||||
return this._workspace;
|
||||
return this._actualWorkspace;
|
||||
}
|
||||
|
||||
private get _actualWorkspace(): ExtHostWorkspaceImpl {
|
||||
return this._unconfirmedWorkspace || this._confirmedWorkspace;
|
||||
}
|
||||
|
||||
getWorkspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
if (!this._workspace) {
|
||||
if (!this._actualWorkspace) {
|
||||
return undefined;
|
||||
} else {
|
||||
return this._workspace.workspaceFolders.slice(0);
|
||||
}
|
||||
return this._actualWorkspace.workspaceFolders.slice(0);
|
||||
}
|
||||
|
||||
updateWorkspaceFolders(extension: IExtensionDescription, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[]): boolean {
|
||||
const validatedDistinctWorkspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[] = [];
|
||||
if (Array.isArray(workspaceFoldersToAdd)) {
|
||||
workspaceFoldersToAdd.forEach(folderToAdd => {
|
||||
if (URI.isUri(folderToAdd.uri) && !validatedDistinctWorkspaceFoldersToAdd.some(f => isFolderEqual(f.uri, folderToAdd.uri))) {
|
||||
validatedDistinctWorkspaceFoldersToAdd.push({ uri: folderToAdd.uri, name: folderToAdd.name || basenameOrAuthority(folderToAdd.uri) });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!!this._unconfirmedWorkspace) {
|
||||
return false; // prevent accumulated calls without a confirmed workspace
|
||||
}
|
||||
|
||||
if ([index, deleteCount].some(i => typeof i !== 'number' || i < 0)) {
|
||||
return false; // validate numbers
|
||||
}
|
||||
|
||||
if (deleteCount === 0 && validatedDistinctWorkspaceFoldersToAdd.length === 0) {
|
||||
return false; // nothing to delete or add
|
||||
}
|
||||
|
||||
const currentWorkspaceFolders: MutableWorkspaceFolder[] = this._actualWorkspace ? this._actualWorkspace.workspaceFolders : [];
|
||||
if (index + deleteCount > currentWorkspaceFolders.length) {
|
||||
return false; // cannot delete more than we have
|
||||
}
|
||||
|
||||
// Simulate the updateWorkspaceFolders method on our data to do more validation
|
||||
const newWorkspaceFolders = currentWorkspaceFolders.slice(0);
|
||||
newWorkspaceFolders.splice(index, deleteCount, ...validatedDistinctWorkspaceFoldersToAdd.map(f => ({ uri: f.uri, name: f.name || basenameOrAuthority(f.uri) })));
|
||||
|
||||
for (let i = 0; i < newWorkspaceFolders.length; i++) {
|
||||
const folder = newWorkspaceFolders[i];
|
||||
if (newWorkspaceFolders.some((otherFolder, index) => index !== i && isFolderEqual(folder.uri, otherFolder.uri))) {
|
||||
return false; // cannot add the same folder multiple times
|
||||
}
|
||||
}
|
||||
|
||||
newWorkspaceFolders.forEach((f, index) => f.index = index); // fix index
|
||||
const { added, removed } = delta(currentWorkspaceFolders, newWorkspaceFolders, compareWorkspaceFolderByUriAndNameAndIndex);
|
||||
if (added.length === 0 && removed.length === 0) {
|
||||
return false; // nothing actually changed
|
||||
}
|
||||
|
||||
// Trigger on main side
|
||||
if (this._proxy) {
|
||||
const extName = extension.displayName || extension.name;
|
||||
this._proxy.$updateWorkspaceFolders(extName, index, deleteCount, validatedDistinctWorkspaceFoldersToAdd).then(null, error => {
|
||||
|
||||
// in case of an error, make sure to clear out the unconfirmed workspace
|
||||
// because we cannot expect the acknowledgement from the main side for this
|
||||
this._unconfirmedWorkspace = undefined;
|
||||
|
||||
// show error to user
|
||||
this._messageService.$showMessage(Severity.Error, localize('updateerror', "Extension '{0}' failed to update workspace folders: {1}", extName, error.toString()), { extension }, []);
|
||||
});
|
||||
}
|
||||
|
||||
// Try to accept directly
|
||||
return this.trySetWorkspaceFolders(newWorkspaceFolders);
|
||||
}
|
||||
|
||||
getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder {
|
||||
if (!this._workspace) {
|
||||
if (!this._actualWorkspace) {
|
||||
return undefined;
|
||||
}
|
||||
return this._workspace.getWorkspaceFolder(uri, resolveParent);
|
||||
return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
|
||||
}
|
||||
|
||||
getPath(): string {
|
||||
|
||||
// this is legacy from the days before having
|
||||
// multi-root and we keep it only alive if there
|
||||
// is just one workspace folder.
|
||||
if (!this._workspace) {
|
||||
if (!this._actualWorkspace) {
|
||||
return undefined;
|
||||
}
|
||||
const { folders } = this._workspace;
|
||||
|
||||
const { folders } = this._actualWorkspace;
|
||||
if (folders.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -130,7 +271,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
}
|
||||
|
||||
if (typeof includeWorkspace === 'undefined') {
|
||||
includeWorkspace = this.workspace.folders.length > 1;
|
||||
includeWorkspace = this._actualWorkspace.folders.length > 1;
|
||||
}
|
||||
|
||||
let result = relative(folder.uri.fsPath, path);
|
||||
@@ -140,27 +281,40 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
return normalize(result, true);
|
||||
}
|
||||
|
||||
private trySetWorkspaceFolders(folders: vscode.WorkspaceFolder[]): boolean {
|
||||
|
||||
// Update directly here. The workspace is unconfirmed as long as we did not get an
|
||||
// acknowledgement from the main side (via $acceptWorkspaceData)
|
||||
if (this._actualWorkspace) {
|
||||
this._unconfirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace({
|
||||
id: this._actualWorkspace.id,
|
||||
name: this._actualWorkspace.name,
|
||||
configuration: this._actualWorkspace.configuration,
|
||||
folders
|
||||
} as IWorkspaceData, this._actualWorkspace).workspace;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$acceptWorkspaceData(data: IWorkspaceData): void {
|
||||
|
||||
// keep old workspace folder, build new workspace, and
|
||||
// capture new workspace folders. Compute delta between
|
||||
// them send that as event
|
||||
const oldRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
|
||||
const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace);
|
||||
|
||||
this._workspace = Workspace2.fromData(data);
|
||||
const newRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
|
||||
// Update our workspace object. We have a confirmed workspace, so we drop our
|
||||
// unconfirmed workspace.
|
||||
this._confirmedWorkspace = workspace;
|
||||
this._unconfirmedWorkspace = undefined;
|
||||
|
||||
const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder);
|
||||
// Events
|
||||
this._onDidChangeWorkspace.fire(Object.freeze({
|
||||
added: Object.freeze<vscode.WorkspaceFolder[]>(added),
|
||||
removed: Object.freeze<vscode.WorkspaceFolder[]>(removed)
|
||||
}));
|
||||
}
|
||||
|
||||
private static _compareWorkspaceFolder(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
|
||||
return compare(a.uri.toString(), b.uri.toString());
|
||||
}
|
||||
|
||||
// --- search ---
|
||||
|
||||
findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
|
||||
|
||||
Reference in New Issue
Block a user