Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -5,7 +5,7 @@
'use strict';
import { Emitter } from 'vs/base/common/event';
import { TrieMap } from 'vs/base/common/map';
import { TernarySearchTree } from 'vs/base/common/map';
import { score } from 'vs/editor/common/modes/languageSelector';
import * as Platform from 'vs/base/common/platform';
import * as errors from 'vs/base/common/errors';
@@ -54,7 +54,9 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService';
import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem';
import { FileChangeType, FileType } from 'vs/platform/files/common/files';
import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
export interface IExtensionApiFactory {
(extension: IExtensionDescription): typeof vscode;
@@ -76,31 +78,33 @@ function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
export function createApiFactory(
initData: IInitData,
threadService: ExtHostThreadService,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
extensionService: ExtHostExtensionService
): IExtensionApiFactory {
const mainThreadTelemetry = threadService.get(MainContext.MainThreadTelemetry);
// Addressable instances
const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService, extensionService));
const extHostDecorations = threadService.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(threadService));
const extHostDocumentsAndEditors = threadService.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(threadService));
const extHostDocuments = threadService.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(threadService, extHostDocumentsAndEditors));
const extHostDocumentContentProviders = threadService.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(threadService, extHostDocumentsAndEditors));
const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace)));
const extHostDocumentSaveParticipant = threadService.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadEditors)));
const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService));
const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands));
const extHostWorkspace = threadService.set(ExtHostContext.ExtHostWorkspace, new ExtHostWorkspace(threadService, initData.workspace));
threadService.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
// {{SQL CARBON EDIT}}
// const extHostDebugService = threadService.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace));
const extHostConfiguration = threadService.set(ExtHostContext.ExtHostConfiguration, new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration));
threadService.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
const extHostDiagnostics = threadService.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(threadService));
const languageFeatures = threadService.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostFileSystem = threadService.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(threadService));
const extHostFileSystemEvent = threadService.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService));
const extHostQuickOpen = threadService.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(threadService, extHostWorkspace, extHostCommands));
const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService));
const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands));
const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService));
const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService, extHostWorkspace));
const extHostCredentials = threadService.set(ExtHostContext.ExtHostCredentials, new ExtHostCredentials(threadService));
const extHostWindow = threadService.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(threadService));
threadService.set(ExtHostContext.ExtHostExtensionService, extensionService);
@@ -138,20 +142,6 @@ export function createApiFactory(
}
}
const apiUsage = new class {
private _seen = new Set<string>();
publicLog(apiName: string) {
if (this._seen.has(apiName)) {
return undefined;
}
this._seen.add(apiName);
return mainThreadTelemetry.$publicLog('apiUsage', {
name: apiName,
extension: extension.id
});
}
};
// namespace: commands
const commands: typeof vscode.commands = {
registerCommand<T>(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
@@ -283,13 +273,12 @@ export function createApiFactory(
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
return languageFeatures.registerDocumentLinkProvider(selector, provider);
},
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
return languageFeatures.registerColorProvider(selector, provider);
},
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
return languageFeatures.setLanguageConfiguration(language, configuration);
},
// proposed API
registerColorProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider) => {
return languageFeatures.registerColorProvider(selector, provider);
})
}
};
// namespace: window
@@ -335,9 +324,9 @@ export function createApiFactory(
get state() {
return extHostWindow.state;
},
onDidChangeWindowState: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
onDidChangeWindowState(listener, thisArg?, disposables?) {
return extHostWindow.onDidChangeWindowState(listener, thisArg, disposables);
}),
},
showInformationMessage(message, first, ...rest) {
return extHostMessageService.showMessage(extension, Severity.Info, message, first, rest);
},
@@ -350,9 +339,18 @@ export function createApiFactory(
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) {
return extHostQuickOpen.showQuickPick(items, options, token);
},
showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) {
return extHostQuickOpen.showWorkspaceFolderPick(options);
},
showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
return extHostQuickOpen.showInput(options, token);
},
showOpenDialog(options) {
return extHostDialogs.showOpenDialog(options);
},
showSaveDialog(options) {
return extHostDialogs.showSaveDialog(options);
},
createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem {
return extHostStatusBar.createStatusBarEntry(extension.id, <number>position, priority);
},
@@ -382,15 +380,14 @@ export function createApiFactory(
sampleFunction: proposedApiFunction(extension, () => {
return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []);
}),
showOpenDialog: proposedApiFunction(extension, options => {
return extHostDialogs.showOpenDialog(options);
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => {
return extHostDecorations.registerDecorationProvider(provider, extension.id);
})
};
// namespace: workspace
const workspace: typeof vscode.workspace = {
get rootPath() {
apiUsage.publicLog('workspace#rootPath');
return extHostWorkspace.getPath();
},
set rootPath(value) {
@@ -400,11 +397,15 @@ export function createApiFactory(
return extHostWorkspace.getWorkspaceFolder(resource);
},
get workspaceFolders() {
apiUsage.publicLog('workspace#workspaceFolders');
return extHostWorkspace.getWorkspaceFolders();
},
get name() {
return extHostWorkspace.workspace ? extHostWorkspace.workspace.name : undefined;
},
set name(value) {
throw errors.readonly();
},
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
apiUsage.publicLog('workspace#onDidChangeWorkspaceFolders');
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
},
asRelativePath: (pathOrUri, includeWorkspace) => {
@@ -417,7 +418,7 @@ export function createApiFactory(
return extHostWorkspace.saveAll(includeUntitled);
},
applyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
return extHostWorkspace.appyEdit(edit);
return extHostEditors.applyWorkspaceEdit(edit);
},
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
return extHostFileSystemEvent.createFileSystemWatcher(pattern, ignoreCreate, ignoreChange, ignoreDelete);
@@ -432,12 +433,12 @@ export function createApiFactory(
let uriPromise: TPromise<URI>;
let options = uriOrFileNameOrOptions as { language?: string; content?: string; };
if (!options || typeof options.language === 'string') {
uriPromise = extHostDocuments.createDocumentData(options);
} else if (typeof uriOrFileNameOrOptions === 'string') {
if (typeof uriOrFileNameOrOptions === 'string') {
uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions));
} else if (uriOrFileNameOrOptions instanceof URI) {
uriPromise = TPromise.as(<URI>uriOrFileNameOrOptions);
uriPromise = TPromise.as(uriOrFileNameOrOptions);
} else if (!options || typeof options === 'object') {
uriPromise = extHostDocuments.createDocumentData(options);
} else {
throw new Error('illegal argument - uriOrFileNameOrOptions');
}
@@ -467,8 +468,9 @@ export function createApiFactory(
onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables);
},
getConfiguration: (section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration => {
return extHostConfiguration.getConfiguration(section, <URI>resource);
getConfiguration(section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration {
resource = arguments.length === 1 ? void 0 : resource;
return extHostConfiguration.getConfiguration(section, resource, extension.id);
},
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) {
return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider);
@@ -477,7 +479,7 @@ export function createApiFactory(
return extHostTask.registerTaskProvider(extension, provider);
},
registerFileSystemProvider: proposedApiFunction(extension, (authority, provider) => {
return extHostWorkspace.registerFileSystemProvider(authority, provider);
return extHostFileSystem.registerFileSystemProvider(authority, provider);
})
};
@@ -486,20 +488,15 @@ export function createApiFactory(
get inputBox() {
return extHostSCM.getLastInputBox(extension);
},
createSourceControl(id: string, label: string) {
mainThreadTelemetry.$publicLog('registerSCMProvider', {
extensionId: extension.id,
providerId: id,
providerLabel: label
});
return extHostSCM.createSourceControl(extension, id, label);
createSourceControl(id: string, label: string, rootUri?: vscode.Uri) {
return extHostSCM.createSourceControl(extension, id, label, rootUri);
}
};
// {{SQL CARBON EDIT}}
// delete namespace: debug
// namespace: credentials
const credentials = {
readSecret(service: string, account: string): Thenable<string | undefined> {
@@ -530,11 +527,13 @@ export function createApiFactory(
CancellationTokenSource: CancellationTokenSource,
CodeLens: extHostTypes.CodeLens,
Color: extHostTypes.Color,
ColorRange: extHostTypes.ColorRange,
ColorPresentation: extHostTypes.ColorPresentation,
ColorInformation: extHostTypes.ColorInformation,
EndOfLine: extHostTypes.EndOfLine,
CompletionItem: extHostTypes.CompletionItem,
CompletionItemKind: extHostTypes.CompletionItemKind,
CompletionList: extHostTypes.CompletionList,
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
Diagnostic: extHostTypes.Diagnostic,
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
Disposable: extHostTypes.Disposable,
@@ -545,7 +544,7 @@ export function createApiFactory(
Hover: extHostTypes.Hover,
IndentAction: languageConfiguration.IndentAction,
Location: extHostTypes.Location,
MarkdownString: MarkdownString,
MarkdownString: extHostTypes.MarkdownString,
OverviewRulerLane: EditorCommon.OverviewRulerLane,
ParameterInformation: extHostTypes.ParameterInformation,
Position: extHostTypes.Position,
@@ -564,7 +563,7 @@ export function createApiFactory(
TextEditorRevealType: extHostTypes.TextEditorRevealType,
TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind,
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
Uri: <any>URI,
Uri: URI,
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
ProgressLocation: extHostTypes.ProgressLocation,
@@ -577,8 +576,14 @@ export function createApiFactory(
TaskGroup: extHostTypes.TaskGroup,
ProcessExecution: extHostTypes.ProcessExecution,
ShellExecution: extHostTypes.ShellExecution,
TaskScope: extHostTypes.TaskScope,
Task: extHostTypes.Task,
ConfigurationTarget: extHostTypes.ConfigurationTarget
ConfigurationTarget: extHostTypes.ConfigurationTarget,
RelativePattern: extHostTypes.RelativePattern,
// TODO@JOH,remote
FileChangeType: <any>FileChangeType,
FileType: <any>FileType
};
if (extension.enableProposedApi && extension.isBuiltin) {
api['credentials'] = credentials;
@@ -619,7 +624,7 @@ export function initializeExtensionApi(extensionService: ExtHostExtensionService
return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie));
}
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TrieMap<IExtensionDescription>): void {
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree<IExtensionDescription>): void {
// each extension is meant to get its own api implementation
const extApiImpl = new Map<string, typeof vscode>();

View File

@@ -26,11 +26,9 @@ import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/pro
import * as editorCommon from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { ITextSource } from 'vs/editor/common/model/textSource';
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { IConfigurationData } from 'vs/platform/configuration/common/configuration';
import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
@@ -44,10 +42,14 @@ import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { ITreeItem } from 'vs/workbench/parts/views/common/views';
import { ITreeItem } from 'vs/workbench/common/views';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { SerializedError } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
import { IStat, IFileChange } from 'vs/platform/files/common/files';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -64,7 +66,7 @@ export interface IEnvironment {
export interface IWorkspaceData {
id: string;
name: string;
roots: URI[];
folders: IWorkspaceFolderData[];
}
export interface IInitData {
@@ -72,10 +74,19 @@ export interface IInitData {
environment: IEnvironment;
workspace: IWorkspaceData;
extensions: IExtensionDescription[];
configuration: IConfigurationData<any>;
configuration: IConfigurationInitData;
telemetryInfo: ITelemetryInfo;
}
export interface IConfigurationInitData extends IConfigurationData {
configurationScopes: ConfigurationScope[];
}
export interface IWorkspaceConfigurationChangeEventData {
changedConfiguration: IConfigurationModel;
changedConfigurationByResource: { [folder: string]: IConfigurationModel };
}
export interface IExtHostContext {
/**
* Returns a proxy to an object addressable/named in the extension host process.
@@ -114,16 +125,30 @@ export interface MainThreadDiagnosticsShape extends IDisposable {
$clear(owner: string): TPromise<any>;
}
export interface MainThreadDialogOptions {
uri?: URI;
export interface MainThreadDialogOpenOptions {
defaultUri?: URI;
openLabel?: string;
openFiles?: boolean;
openFolders?: boolean;
openMany?: boolean;
canSelectFiles?: boolean;
canSelectFolders?: boolean;
canSelectMany?: boolean;
filters?: { [name: string]: string[] };
}
export interface MainThreadDialogSaveOptions {
defaultUri?: URI;
saveLabel?: string;
filters?: { [name: string]: string[] };
}
export interface MainThreadDiaglogsShape extends IDisposable {
$showOpenDialog(options: MainThreadDialogOptions): TPromise<string[]>;
$showOpenDialog(options: MainThreadDialogOpenOptions): TPromise<string[]>;
$showSaveDialog(options: MainThreadDialogSaveOptions): TPromise<string>;
}
export interface MainThreadDecorationsShape extends IDisposable {
$registerDecorationProvider(handle: number, label: string): void;
$unregisterDecorationProvider(handle: number): void;
$onDidChange(handle: number, resources: URI[]): void;
}
export interface MainThreadDocumentContentProvidersShape extends IDisposable {
@@ -182,6 +207,16 @@ export interface ITextDocumentShowOptions {
selection?: IRange;
}
export interface IWorkspaceResourceEdit {
resource: URI;
modelVersionId?: number;
edits: {
range?: IRange;
newText: string;
newEol?: editorCommon.EndOfLineSequence;
}[];
}
export interface MainThreadEditorsShape extends IDisposable {
$tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise<string>;
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
@@ -190,9 +225,11 @@ export interface MainThreadEditorsShape extends IDisposable {
$tryHideEditor(id: string): TPromise<void>;
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<any>;
$trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): TPromise<any>;
$trySetDecorationsFast(id: string, key: string, ranges: string): TPromise<any>;
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any>;
$trySetSelections(id: string, selections: ISelection[]): TPromise<any>;
$tryApplyEdits(id: string, modelVersionId: number, edits: editorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean>;
$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean>;
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise<any>;
$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]>;
}
@@ -223,10 +260,9 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): TPromise<any>;
$registerNavigateTypeSupport(handle: number): TPromise<any>;
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[]): TPromise<any>;
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): TPromise<any>;
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise<any>;
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerColorFormats(formats: IRawColorFormatMap): TPromise<any>;
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$setLanguageConfiguration(handle: number, languageId: string, configuration: vscode.LanguageConfiguration): TPromise<any>;
}
@@ -260,7 +296,7 @@ export interface MainThreadProgressShape extends IDisposable {
}
export interface MainThreadTerminalServiceShape extends IDisposable {
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], waitOnExit?: boolean): TPromise<number>;
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number>;
$dispose(terminalId: number): void;
$hide(terminalId: number): void;
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
@@ -279,7 +315,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
export interface MainThreadStatusBarShape extends IDisposable {
$setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void;
$dispose(id: number);
$dispose(id: number): void;
}
export interface MainThreadStorageShape extends IDisposable {
@@ -292,16 +328,20 @@ export interface MainThreadTelemetryShape extends IDisposable {
}
export interface MainThreadWorkspaceShape extends IDisposable {
$startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable<URI[]>;
$startSearch(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults: number, requestId: number): Thenable<URI[]>;
$cancelSearch(requestId: number): Thenable<boolean>;
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
$applyWorkspaceEdit(edits: IResourceEdit[]): TPromise<boolean>;
}
$registerFileSystemProvider(handle: number, authority: string): void;
$unregisterFileSystemProvider(handle): void;
$onFileSystemChange(handle: number, resource: URI): void;
$updateSearchSession(session: number, data): void;
$finishSearchSession(session: number, err?: any): void;
export interface MainThreadFileSystemShape extends IDisposable {
$registerFileSystemProvider(handle: number, scheme: string): void;
$unregisterFileSystemProvider(handle: number): void;
$onDidAddFileSystemRoot(root: URI): void;
$onFileSystemChange(handle: number, resource: IFileChange[]): void;
$reportFileChunk(handle: number, resource: URI, chunk: number[] | null): void;
$handleSearchProgress(handle: number, session: number, resource: URI): void;
}
export interface MainThreadTaskShape extends IDisposable {
@@ -330,24 +370,39 @@ export interface SCMGroupFeatures {
export type SCMRawResource = [
number /*handle*/,
string /*resourceUri*/,
modes.Command /*command*/,
string[] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/
boolean /*faded*/,
string | undefined /*source*/,
string | undefined /*letter*/,
ThemeColor | null /*color*/
];
export type SCMRawResourceSplice = [
number /* start */,
number /* delete count */,
SCMRawResource[]
];
export type SCMRawResourceSplices = [
number, /*handle*/
SCMRawResourceSplice[]
];
export interface MainThreadSCMShape extends IDisposable {
$registerSourceControl(handle: number, id: string, label: string): void;
$registerSourceControl(handle: number, id: string, label: string, rootUri: string | undefined): void;
$updateSourceControl(handle: number, features: SCMProviderFeatures): void;
$unregisterSourceControl(handle: number): void;
$registerGroup(sourceControlHandle: number, handle: number, id: string, label: string): void;
$updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): void;
$updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void;
$updateGroupResourceStates(sourceControlHandle: number, groupHandle: number, resources: SCMRawResource[]): void;
$unregisterGroup(sourceControlHandle: number, handle: number): void;
$spliceResourceStates(sourceControlHandle: number, splices: SCMRawResourceSplices[]): void;
$setInputBoxValue(sourceControlHandle: number, value: string): void;
}
@@ -359,9 +414,9 @@ export type DebugSessionUUID = string;
export interface MainThreadDebugServiceShape extends IDisposable {
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, handle: number): TPromise<any>;
$unregisterDebugConfigurationProvider(handle: number): TPromise<any>;
$startDebugging(folderUri: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean>;
$startDebugSession(folderUri: URI | undefined, config: vscode.DebugConfiguration): TPromise<DebugSessionUUID>;
$startDebugging(folder: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean>;
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise<any>;
$appendDebugConsole(value: string): TPromise<any>;
}
*/
export interface MainThreadCredentialsShape extends IDisposable {
@@ -382,7 +437,7 @@ export interface ExtHostCommandsShape {
}
export interface ExtHostConfigurationShape {
$acceptConfigurationChanged(data: IConfigurationData<any>);
$acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData): void;
}
export interface ExtHostDiagnosticsShape {
@@ -447,11 +502,19 @@ export interface ExtHostTreeViewsShape {
export interface ExtHostWorkspaceShape {
$acceptWorkspaceData(workspace: IWorkspaceData): void;
}
$resolveFile(handle: number, resource: URI): TPromise<string>;
$storeFile(handle: number, resource: URI, content: string): TPromise<any>;
$startSearch(handle: number, session: number, query: string): void;
$cancelSearch(handle: number, session: number): void;
export interface ExtHostFileSystemShape {
$utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise<IStat>;
$stat(handle: number, resource: URI): TPromise<IStat>;
$read(handle: number, offset: number, count: number, resource: URI): TPromise<number>;
$write(handle: number, resource: URI, content: number[]): TPromise<void>;
$unlink(handle: number, resource: URI): TPromise<void>;
$move(handle: number, resource: URI, target: URI): TPromise<IStat>;
$mkdir(handle: number, resource: URI): TPromise<IStat>;
$readdir(handle: number, resource: URI): TPromise<[URI, IStat][]>;
$rmdir(handle: number, resource: URI): TPromise<void>;
$fileFiles(handle: number, session: number, query: string): TPromise<void>;
}
export interface ExtHostExtensionServiceShape {
@@ -464,7 +527,7 @@ export interface FileSystemEvents {
deleted: URI[];
}
export interface ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents);
$onFileEvent(events: FileSystemEvents): void;
}
export interface ObjectIdentifier {
@@ -487,11 +550,34 @@ export interface ExtHostHeapServiceShape {
}
export interface IRawColorInfo {
color: [number, number, number, number];
availableFormats: (number | [number, number])[];
range: IRange;
}
export type IRawColorFormatMap = [number, string][];
export interface IExtHostSuggestion extends modes.ISuggestion {
_id: number;
_parentId: number;
}
export interface IExtHostSuggestResult {
_id: number;
suggestions: IExtHostSuggestion[];
incomplete?: boolean;
}
export interface IdObject {
_id: number;
}
export namespace IdObject {
let n = 0;
export function mixin<T extends object>(object: T): T & IdObject {
(<any>object)._id = n++;
return <any>object;
}
}
export type IWorkspaceSymbol = IdObject & modes.SymbolInformation;
export interface IWorkspaceSymbols extends IdObject { symbols: IWorkspaceSymbol[]; };
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]>;
@@ -507,15 +593,18 @@ export interface ExtHostLanguageFeaturesShape {
$provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;
$provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;
$provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<editorCommon.ISingleEditOperation[]>;
$provideWorkspaceSymbols(handle: number, search: string): TPromise<modes.SymbolInformation[]>;
$resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise<modes.SymbolInformation>;
$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbols>;
$resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise<IWorkspaceSymbol>;
$releaseWorkspaceSymbols(handle: number, id: number): void;
$provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit>;
$provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise<modes.ISuggestResult>;
$provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<IExtHostSuggestResult>;
$resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion>;
$releaseCompletionItems(handle: number, id: number): void;
$provideSignatureHelp(handle: number, resource: URI, position: IPosition): TPromise<modes.SignatureHelp>;
$provideDocumentLinks(handle: number, resource: URI): TPromise<modes.ILink[]>;
$provideDocumentColors(handle: number, resource: URI): TPromise<IRawColorInfo[]>;
$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink>;
$provideDocumentColors(handle: number, resource: URI): TPromise<IRawColorInfo[]>;
$provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]>;
}
export interface ExtHostQuickOpenShape {
@@ -531,6 +620,7 @@ export interface ExtHostTerminalServiceShape {
export interface ExtHostSCMShape {
$provideOriginalResource(sourceControlHandle: number, uri: URI): TPromise<URI>;
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void>;
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void>;
}
export interface ExtHostTaskShape {
@@ -549,6 +639,12 @@ export interface ExtHostDebugServiceShape {
}
*/
export type DecorationData = [number, boolean, string, string, ThemeColor, string];
export interface ExtHostDecorationsShape {
$providerDecorations(handle: number, uri: URI): TPromise<DecorationData>;
}
export interface ExtHostCredentialsShape {
}
@@ -563,6 +659,7 @@ export const MainContext = {
MainThreadConfiguration: createMainId<MainThreadConfigurationShape>('MainThreadConfiguration'),
// {{SQL CARBON EDIT}}
// MainThreadDebugService: createMainId<MainThreadDebugServiceShape>('MainThreadDebugService'),
MainThreadDecorations: createMainId<MainThreadDecorationsShape>('MainThreadDecorations'),
MainThreadDiagnostics: createMainId<MainThreadDiagnosticsShape>('MainThreadDiagnostics'),
MainThreadDialogs: createMainId<MainThreadDiaglogsShape>('MainThreadDiaglogs'),
MainThreadDocuments: createMainId<MainThreadDocumentsShape>('MainThreadDocuments'),
@@ -581,6 +678,7 @@ export const MainContext = {
MainThreadTelemetry: createMainId<MainThreadTelemetryShape>('MainThreadTelemetry'),
MainThreadTerminalService: createMainId<MainThreadTerminalServiceShape>('MainThreadTerminalService'),
MainThreadWorkspace: createMainId<MainThreadWorkspaceShape>('MainThreadWorkspace'),
MainThreadFileSystem: createMainId<MainThreadFileSystemShape>('MainThreadFileSystem'),
MainThreadExtensionService: createMainId<MainThreadExtensionServiceShape>('MainThreadExtensionService'),
MainThreadSCM: createMainId<MainThreadSCMShape>('MainThreadSCM'),
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask'),
@@ -594,12 +692,14 @@ export const ExtHostContext = {
ExtHostDiagnostics: createExtId<ExtHostDiagnosticsShape>('ExtHostDiagnostics'),
// {{SQL CARBON EDIT}}
// ExtHostDebugService: createExtId<ExtHostDebugServiceShape>('ExtHostDebugService'),
ExtHostDecorations: createExtId<ExtHostDecorationsShape>('ExtHostDecorations'),
ExtHostDocumentsAndEditors: createExtId<ExtHostDocumentsAndEditorsShape>('ExtHostDocumentsAndEditors'),
ExtHostDocuments: createExtId<ExtHostDocumentsShape>('ExtHostDocuments'),
ExtHostDocumentContentProviders: createExtId<ExtHostDocumentContentProvidersShape>('ExtHostDocumentContentProviders'),
ExtHostDocumentSaveParticipant: createExtId<ExtHostDocumentSaveParticipantShape>('ExtHostDocumentSaveParticipant'),
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors'),
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
ExtHostHeapService: createExtId<ExtHostHeapServiceShape>('ExtHostHeapMonitor'),
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),

View File

@@ -195,15 +195,6 @@ export class ExtHostApiCommands {
]
});
this._register('vscode.startDebug', (configuration?: any, folderUri?: URI) => {
return this._commands.executeCommand('_workbench.startDebug', configuration, folderUri);
}, {
description: 'Start a debugging session.',
args: [
{ name: 'configuration', description: '(optional) Name of the debug configuration from \'launch.json\' to use. Or a configuration json object to use.' }
]
});
this._register('vscode.diff', (left: URI, right: URI, label: string, options?: vscode.TextDocumentShowOptions) => {
let editorOptions: ITextEditorOptions;
if (options) {
@@ -376,7 +367,8 @@ export class ExtHostApiCommands {
return this._commands.executeCommand<modes.ISuggestResult>('_executeCompletionItemProvider', args).then(result => {
if (result) {
const items = result.suggestions.map(suggestion => typeConverters.Suggest.to(position, suggestion));
return new types.CompletionList(items, result.incomplete);
// {{SQL CARBON EDIT}}
return new types.CompletionList(<any>items, result.incomplete);
}
return undefined;
});

View File

@@ -7,12 +7,15 @@
import { mixin } from 'vs/base/common/objects';
import URI from 'vs/base/common/uri';
import Event, { Emitter } from 'vs/base/common/event';
import { WorkspaceConfiguration } from 'vscode';
import * as vscode from 'vscode';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol';
import { ExtHostConfigurationShape, MainThreadConfigurationShape, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from './extHost.protocol';
import { ConfigurationTarget as ExtHostConfigurationTarget } from './extHostTypes';
import { IConfigurationData, Configuration } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
import { IConfigurationData, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { Configuration, ConfigurationModel, ConfigurationChangeEvent } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels';
import { StrictResourceMap } from 'vs/base/common/map';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
function lookUp(tree: any, key: string) {
if (key) {
@@ -35,30 +38,36 @@ type ConfigurationInspect<T> = {
export class ExtHostConfiguration implements ExtHostConfigurationShape {
private readonly _onDidChangeConfiguration = new Emitter<void>();
private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
private readonly _proxy: MainThreadConfigurationShape;
private readonly _extHostWorkspace: ExtHostWorkspace;
private _configuration: Configuration<any>;
private _configurationScopes: Map<string, ConfigurationScope>;
private _configuration: Configuration;
constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationData<any>) {
constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) {
this._proxy = proxy;
this._extHostWorkspace = extHostWorkspace;
this._configuration = Configuration.parse(data, extHostWorkspace.workspace);
this._configuration = Configuration.parse(data);
this._readConfigurationScopes(data.configurationScopes);
}
get onDidChangeConfiguration(): Event<void> {
get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event;
}
$acceptConfigurationChanged(data: IConfigurationData<any>) {
this._configuration = Configuration.parse(data, this._extHostWorkspace.workspace);
this._onDidChangeConfiguration.fire(undefined);
$acceptConfigurationChanged(data: IConfigurationData, eventData: IWorkspaceConfigurationChangeEventData) {
this._configuration = Configuration.parse(data);
this._onDidChangeConfiguration.fire(this._toConfigurationChangeEvent(eventData));
}
getConfiguration(section?: string, resource?: URI): WorkspaceConfiguration {
getConfiguration(section?: string, resource?: URI, extensionId?: string): vscode.WorkspaceConfiguration {
const config = section
? lookUp(this._configuration.getValue(null, { resource }), section)
: this._configuration.getValue(null, { resource });
? lookUp(this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace), section)
: this._configuration.getSection(null, { resource }, this._extHostWorkspace.workspace);
if (section) {
this._validateConfigurationAccess(section, resource, extensionId);
}
function parseConfigurationTarget(arg: boolean | ExtHostConfigurationTarget): ConfigurationTarget {
if (arg === void 0 || arg === null) {
@@ -71,15 +80,16 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
switch (arg) {
case ExtHostConfigurationTarget.Global: return ConfigurationTarget.USER;
case ExtHostConfigurationTarget.Workspace: return ConfigurationTarget.WORKSPACE;
case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.FOLDER;
case ExtHostConfigurationTarget.WorkspaceFolder: return ConfigurationTarget.WORKSPACE_FOLDER;
}
}
const result: WorkspaceConfiguration = {
const result: vscode.WorkspaceConfiguration = {
has(key: string): boolean {
return typeof lookUp(config, key) !== 'undefined';
},
get<T>(key: string, defaultValue?: T): T {
get: <T>(key: string, defaultValue?: T) => {
this._validateConfigurationAccess(section ? `${section}.${key}` : key, resource, extensionId);
let result = lookUp(config, key);
if (typeof result === 'undefined') {
result = defaultValue;
@@ -97,14 +107,14 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
},
inspect: <T>(key: string): ConfigurationInspect<T> => {
key = section ? `${section}.${key}` : key;
const config = this._configuration.lookup<T>(key, { resource });
const config = this._configuration.lookup<T>(key, { resource }, this._extHostWorkspace.workspace);
if (config) {
return {
key,
defaultValue: config.default,
globalValue: config.user,
workspaceValue: config.workspace,
workspaceFolderValue: config.folder
workspaceFolderValue: config.workspaceFolder
};
}
return undefined;
@@ -115,6 +125,49 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
mixin(result, config, false);
}
return <WorkspaceConfiguration>Object.freeze(result);
return <vscode.WorkspaceConfiguration>Object.freeze(result);
}
private _validateConfigurationAccess(key: string, resource: URI, extensionId: string): void {
const scope = this._configurationScopes.get(key);
const extensionIdText = extensionId ? `[${extensionId}] ` : '';
if (ConfigurationScope.RESOURCE === scope) {
if (resource === void 0) {
console.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`);
}
return;
}
if (ConfigurationScope.WINDOW === scope) {
if (resource) {
console.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`);
}
return;
}
}
private _readConfigurationScopes(scopes: ConfigurationScope[]): void {
this._configurationScopes = new Map<string, ConfigurationScope>();
if (scopes.length) {
const defaultKeys = this._configuration.keys(this._extHostWorkspace.workspace).default;
if (defaultKeys.length === scopes.length) {
for (let i = 0; i < defaultKeys.length; i++) {
this._configurationScopes.set(defaultKeys[i], scopes[i]);
}
}
}
}
private _toConfigurationChangeEvent(data: IWorkspaceConfigurationChangeEventData): vscode.ConfigurationChangeEvent {
const changedConfiguration = new ConfigurationModel(data.changedConfiguration.contents, data.changedConfiguration.keys, data.changedConfiguration.overrides);
const changedConfigurationByResource: StrictResourceMap<ConfigurationModel> = new StrictResourceMap<ConfigurationModel>();
for (const key of Object.keys(data.changedConfigurationByResource)) {
const resource = URI.parse(key);
const model = data.changedConfigurationByResource[key];
changedConfigurationByResource.set(resource, new ConfigurationModel(model.contents, model.keys, model.overrides));
}
const event = new WorkspaceConfigurationChangeEvent(new ConfigurationChangeEvent(changedConfiguration, changedConfigurationByResource), this._extHostWorkspace.workspace);
return Object.freeze({
affectsConfiguration: (section: string, resource?: URI) => event.affectsConfiguration(section, resource)
});
}
}

View File

@@ -42,6 +42,9 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
private _onDidReceiveDebugSessionCustomEvent: Emitter<vscode.DebugSessionCustomEvent>;
get onDidReceiveDebugSessionCustomEvent(): Event<vscode.DebugSessionCustomEvent> { return this._onDidReceiveDebugSessionCustomEvent.event; }
private _debugConsole: ExtHostDebugConsole;
get debugConsole(): ExtHostDebugConsole { return this._debugConsole; }
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace) {
@@ -56,6 +59,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
this._onDidReceiveDebugSessionCustomEvent = new Emitter<vscode.DebugSessionCustomEvent>();
this._debugServiceProxy = mainContext.get(MainContext.MainThreadDebugService);
this._debugConsole = new ExtHostDebugConsole(this._debugServiceProxy);
}
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable {
@@ -97,17 +102,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
}
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean> {
return this._debugServiceProxy.$startDebugging(folder ? <URI>folder.uri : undefined, nameOrConfig);
}
public startDebugSession(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): TPromise<vscode.DebugSession> {
return this._debugServiceProxy.$startDebugSession(folder ? <URI>folder.uri : undefined, config).then((id: DebugSessionUUID) => {
const debugSession = new ExtHostDebugSession(this._debugServiceProxy, id, config.type, config.name);
this._debugSessions.set(id, debugSession);
return debugSession;
});
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig);
}
public $acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void {
@@ -190,7 +185,7 @@ export class ExtHostDebugSession implements vscode.DebugSession {
this._id = id;
this._type = type;
this._name = name;
};
}
public get id(): string {
return this._id;
@@ -209,5 +204,22 @@ export class ExtHostDebugSession implements vscode.DebugSession {
}
}
export class ExtHostDebugConsole implements vscode.DebugConsole {
private _debugServiceProxy: MainThreadDebugServiceShape;
constructor(proxy: MainThreadDebugServiceShape) {
this._debugServiceProxy = proxy;
}
append(value: string): void {
this._debugServiceProxy.$appendDebugConsole(value);
}
appendLine(value: string): void {
this.append(value + '\n');
}
}
// {{SQL CARBON EDIT}}
*/

View File

@@ -0,0 +1,47 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import { MainContext, IMainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData } from 'vs/workbench/api/node/extHost.protocol';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
import { asWinJsPromise } from 'vs/base/common/async';
export class ExtHostDecorations implements ExtHostDecorationsShape {
private static _handlePool = 0;
private readonly _provider = new Map<number, vscode.DecorationProvider>();
private readonly _proxy: MainThreadDecorationsShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadDecorations);
}
registerDecorationProvider(provider: vscode.DecorationProvider, label: string): vscode.Disposable {
const handle = ExtHostDecorations._handlePool++;
this._provider.set(handle, provider);
this._proxy.$registerDecorationProvider(handle, label);
const listener = provider.onDidChangeDecorations(e => {
this._proxy.$onDidChange(handle, !e ? null : Array.isArray(e) ? e : [e]);
});
return new Disposable(() => {
listener.dispose();
this._proxy.$unregisterDecorationProvider(handle);
this._provider.delete(handle);
});
}
$providerDecorations(handle: number, uri: URI): TPromise<DecorationData> {
const provider = this._provider.get(handle);
return asWinJsPromise(token => provider.provideDecoration(uri, token)).then(data => {
return data && <DecorationData>[data.priority, data.bubble, data.title, data.abbreviation, data.color, data.source];
});
}
}

View File

@@ -133,7 +133,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
}
}
entries.push([<URI>uri, marker]);
entries.push([uri, marker]);
}
this._proxy.$changeMany(this.name, entries);
@@ -142,7 +142,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
delete(uri: vscode.Uri): void {
this._checkDisposed();
this._data.delete(uri.toString());
this._proxy.$changeMany(this.name, [[<URI>uri, undefined]]);
this._proxy.$changeMany(this.name, [[uri, undefined]]);
}
clear(): void {

View File

@@ -17,8 +17,14 @@ export class ExtHostDialogs {
}
showOpenDialog(options: vscode.OpenDialogOptions): Thenable<URI[]> {
return this._proxy.$showOpenDialog(<any>options).then(filepaths => {
return this._proxy.$showOpenDialog(options).then(filepaths => {
return filepaths && filepaths.map(URI.file);
});
}
showSaveDialog(options: vscode.SaveDialogOptions): Thenable<URI> {
return this._proxy.$showSaveDialog(options).then(filepath => {
return filepath && URI.file(filepath);
});
}
}

View File

@@ -47,7 +47,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
if (typeof provider.onDidChange === 'function') {
subscription = provider.onDidChange(uri => {
if (this._documentsAndEditors.getDocument(uri.toString())) {
this.$provideTextDocumentContent(handle, <URI>uri).then(value => {
this.$provideTextDocumentContent(handle, uri).then(value => {
const document = this._documentsAndEditors.getDocument(uri.toString());
if (!document) {
@@ -60,7 +60,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
// broadcast event when content changed
if (!document.equalLines(textSource)) {
return this._proxy.$onVirtualDocumentChange(<URI>uri, textSource);
return this._proxy.$onVirtualDocumentChange(uri, textSource);
}
}, onUnexpectedError);

View File

@@ -78,7 +78,7 @@ export class ExtHostDocumentData extends MirrorModel {
getText(range?) { return range ? data._getTextInRange(range) : data.getText(); },
get eol() { return data._eol === '\n' ? EndOfLine.LF : EndOfLine.CRLF; },
get lineCount() { return data._lines.length; },
lineAt(lineOrPos) { return data._lineAt(lineOrPos); },
lineAt(lineOrPos: number | vscode.Position) { return data._lineAt(lineOrPos); },
offsetAt(pos) { return data._offsetAt(pos); },
positionAt(offset) { return data._positionAt(offset); },
validateRange(ran) { return data._validateRange(ran); },

View File

@@ -10,10 +10,9 @@ import URI from 'vs/base/common/uri';
import { sequence, always } from 'vs/base/common/async';
import { illegalState } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainThreadWorkspaceShape, ExtHostDocumentSaveParticipantShape } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, IWorkspaceResourceEdit } 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 { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import * as vscode from 'vscode';
@@ -21,14 +20,14 @@ import * as vscode from 'vscode';
export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSaveParticipantShape {
private _documents: ExtHostDocuments;
private _workspace: MainThreadWorkspaceShape;
private _mainThreadEditors: MainThreadEditorsShape;
private _callbacks = new CallbackList();
private _badListeners = new WeakMap<Function, number>();
private _thresholds: { timeout: number; errors: number; };
constructor(documents: ExtHostDocuments, workspace: MainThreadWorkspaceShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) {
constructor(documents: ExtHostDocuments, mainThreadEditors: MainThreadEditorsShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) {
this._documents = documents;
this._workspace = workspace;
this._mainThreadEditors = mainThreadEditors;
this._thresholds = thresholds;
}
@@ -38,12 +37,8 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
get onWillSaveTextDocumentEvent(): Event<vscode.TextDocumentWillSaveEvent> {
return (listener, thisArg, disposables) => {
this._callbacks.add(listener, thisArg);
const result = {
dispose: () => {
this._callbacks.remove(listener, thisArg);
}
};
const remove = this._callbacks.add(listener, thisArg);
const result = { dispose: remove };
if (Array.isArray(disposables)) {
disposables.push(result);
}
@@ -133,13 +128,15 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}).then(values => {
let edits: IResourceEdit[] = [];
let workspaceResourceEdit: IWorkspaceResourceEdit = {
resource: document.uri,
edits: []
};
for (const value of values) {
if (Array.isArray(value) && (<vscode.TextEdit[]>value).every(e => e instanceof TextEdit)) {
for (const { newText, newEol, range } of value) {
edits.push({
resource: <URI>document.uri,
workspaceResourceEdit.edits.push({
range: range && fromRange(range),
newText,
newEol: EndOfLine.from(newEol)
@@ -150,12 +147,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
// apply edits if any and if document
// didn't change somehow in the meantime
if (edits.length === 0) {
if (workspaceResourceEdit.edits.length === 0) {
return undefined;
}
if (version === document.version) {
return this._workspace.$applyWorkspaceEdit(edits);
return this._mainThreadEditors.$tryApplyWorkspaceEdit([workspaceResourceEdit]);
}
// TODO@joh bubble this to listener?

View File

@@ -8,10 +8,9 @@ import Event, { Emitter } from 'vs/base/common/event';
import { dispose } from 'vs/base/common/lifecycle';
import { MainContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext } from './extHost.protocol';
import { ExtHostDocumentData } from './extHostDocumentData';
import { ExtHostTextEditor, ExtHostTextEditor2 } from './extHostTextEditor';
import { ExtHostTextEditor } from './extHostTextEditor';
import * as assert from 'assert';
import * as typeConverters from './extHostTypeConverters';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
@@ -30,8 +29,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
readonly onDidChangeActiveTextEditor: Event<ExtHostTextEditor> = this._onDidChangeActiveTextEditor.event;
constructor(
private readonly _mainContext: IMainContext,
private readonly _extHostExtensions?: ExtHostExtensionService
private readonly _mainContext: IMainContext
) {
}
@@ -81,9 +79,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`);
const documentData = this._documents.get(data.document.toString());
const editor = new ExtHostTextEditor2(
this._extHostExtensions,
this._mainContext.get(MainContext.MainThreadTelemetry),
const editor = new ExtHostTextEditor(
this._mainContext.get(MainContext.MainThreadEditors),
data.id,
documentData,

View File

@@ -18,8 +18,10 @@ import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironm
import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionAPI, IExtensionContext, EmptyExtension, IExtensionModule, ExtensionActivationTimesBuilder, ExtensionActivationTimes } from 'vs/workbench/api/node/extHostExtensionActivator';
import { Barrier } from 'vs/workbench/services/extensions/node/barrier';
import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostThreadService';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { realpath } from 'fs';
import { TrieMap } from 'vs/base/common/map';
import { TernarySearchTree } from 'vs/base/common/map';
class ExtensionMemento implements IExtensionMemento {
@@ -117,11 +119,15 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
private readonly _storagePath: ExtensionStoragePath;
private readonly _proxy: MainThreadExtensionServiceShape;
private _activator: ExtensionsActivator;
private _extensionPathIndex: TPromise<TrieMap<IExtensionDescription>>;
private _extensionPathIndex: TPromise<TernarySearchTree<IExtensionDescription>>;
/**
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
*/
constructor(initData: IInitData, threadService: ExtHostThreadService) {
constructor(initData: IInitData,
threadService: ExtHostThreadService,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration
) {
this._barrier = new Barrier();
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
this._threadService = threadService;
@@ -132,7 +138,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
this._activator = null;
// initialize API first (i.e. do not release barrier until the API is initialized)
const apiFactory = createApiFactory(initData, threadService, this);
const apiFactory = createApiFactory(initData, threadService, extHostWorkspace, extHostConfiguration, this);
initializeExtensionApi(this, apiFactory).then(() => {
@@ -205,9 +211,9 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
}
// create trie to enable fast 'filename -> extension id' look up
public getExtensionPathIndex(): TPromise<TrieMap<IExtensionDescription>> {
public getExtensionPathIndex(): TPromise<TernarySearchTree<IExtensionDescription>> {
if (!this._extensionPathIndex) {
const trie = new TrieMap<IExtensionDescription>();
const tree = TernarySearchTree.forPaths<IExtensionDescription>();
const extensions = this.getAllExtensionDescriptions().map(ext => {
if (!ext.main) {
return undefined;
@@ -217,13 +223,13 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
if (err) {
reject(err);
} else {
trie.insert(path, ext);
tree.set(path, ext);
resolve(void 0);
}
});
});
});
this._extensionPathIndex = TPromise.join(extensions).then(() => trie);
this._extensionPathIndex = TPromise.join(extensions).then(() => tree);
}
return this._extensionPathIndex;
}
@@ -282,6 +288,13 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
private _doActivateExtension(extensionDescription: IExtensionDescription, startup: boolean): TPromise<ActivatedExtension> {
let event = getTelemetryActivationEvent(extensionDescription);
/* __GDPR__
"activatePlugin" : {
"${include}": [
"${TelemetryActivationEvent}"
]
}
*/
this._mainThreadTelemetry.$publicLog('activatePlugin', event);
if (!extensionDescription.main) {
// Treat the extension as being empty => NOT AN ERROR CASE
@@ -343,7 +356,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
if (typeof extensionModule.activate === 'function') {
try {
activationTimesBuilder.activateCallStart();
const activateResult = extensionModule.activate.apply(global, [context]);
const activateResult: TPromise<IExtensionAPI> = extensionModule.activate.apply(global, [context]);
activationTimesBuilder.activateCallStop();
activationTimesBuilder.activateResolveStart();
@@ -381,6 +394,21 @@ function loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: Exten
}
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription): any {
/* __GDPR__FRAGMENT__
"TelemetryActivationEvent" : {
"id": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"name": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"publisherDisplayName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"activationEvents": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"${wildcard}": [
{
"${prefix}": "contribution.",
"${classification}": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
]
}
*/
let event = {
id: extensionDescription.id,
name: extensionDescription.name,

View File

@@ -0,0 +1,85 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape } from './extHost.protocol';
import * as vscode from 'vscode';
import { IStat } from 'vs/platform/files/common/files';
import { IDisposable } from 'vs/base/common/lifecycle';
import { asWinJsPromise } from 'vs/base/common/async';
export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
private readonly _provider = new Map<number, vscode.FileSystemProvider>();
private _handlePool: number = 0;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadFileSystem);
}
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) {
const handle = this._handlePool++;
this._provider.set(handle, provider);
this._proxy.$registerFileSystemProvider(handle, scheme);
this._proxy.$onDidAddFileSystemRoot(<any>provider.root);
let reg: IDisposable;
if (provider.onDidChange) {
reg = provider.onDidChange(event => this._proxy.$onFileSystemChange(handle, <any>event));
}
return {
dispose: () => {
if (reg) {
reg.dispose();
}
this._provider.delete(handle);
this._proxy.$unregisterFileSystemProvider(handle);
}
};
}
$utimes(handle: number, resource: URI, mtime: number, atime: number): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).utimes(resource, mtime, atime));
}
$stat(handle: number, resource: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).stat(resource));
}
$read(handle: number, offset: number, count: number, resource: URI): TPromise<number> {
const progress = {
report: chunk => {
this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk));
}
};
return asWinJsPromise(token => this._provider.get(handle).read(resource, offset, count, progress));
}
$write(handle: number, resource: URI, content: number[]): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).write(resource, Buffer.from(content)));
}
$unlink(handle: number, resource: URI): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).unlink(resource));
}
$move(handle: number, resource: URI, target: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).move(resource, target));
}
$mkdir(handle: number, resource: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).mkdir(resource));
}
$readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> {
return asWinJsPromise(token => this._provider.get(handle).readdir(resource));
}
$rmdir(handle: number, resource: URI): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).rmdir(resource));
}
$fileFiles(handle: number, session: number, query: string): TPromise<void> {
const provider = this._provider.get(handle);
if (!provider.findFiles) {
return TPromise.as(undefined);
}
const progress = { report: (uri) => this._proxy.$handleSearchProgress(handle, session, uri) };
return asWinJsPromise(token => provider.findFiles(query, progress, token));
}
}

View File

@@ -6,7 +6,7 @@
import Event, { Emitter } from 'vs/base/common/event';
import { Disposable } from './extHostTypes';
import { match } from 'vs/base/common/glob';
import { parse, IRelativePattern } from 'vs/base/common/glob';
import { Uri, FileSystemWatcher as _FileSystemWatcher } from 'vscode';
import { FileSystemEvents, ExtHostFileSystemEventServiceShape } from './extHost.protocol';
@@ -30,7 +30,7 @@ class FileSystemWatcher implements _FileSystemWatcher {
return Boolean(this._config & 0b100);
}
constructor(dispatcher: Event<FileSystemEvents>, globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) {
constructor(dispatcher: Event<FileSystemEvents>, globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean) {
this._config = 0;
if (ignoreCreateEvents) {
@@ -43,24 +43,26 @@ class FileSystemWatcher implements _FileSystemWatcher {
this._config += 0b100;
}
const parsedPattern = parse(globPattern);
let subscription = dispatcher(events => {
if (!ignoreCreateEvents) {
for (let created of events.created) {
if (match(globPattern, created.fsPath)) {
if (parsedPattern(created.fsPath)) {
this._onDidCreate.fire(created);
}
}
}
if (!ignoreChangeEvents) {
for (let changed of events.changed) {
if (match(globPattern, changed.fsPath)) {
if (parsedPattern(changed.fsPath)) {
this._onDidChange.fire(changed);
}
}
}
if (!ignoreDeleteEvents) {
for (let deleted of events.deleted) {
if (match(globPattern, deleted.fsPath)) {
if (parsedPattern(deleted.fsPath)) {
this._onDidDelete.fire(deleted);
}
}
@@ -94,7 +96,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
constructor() {
}
public createFileSystemWatcher(globPattern: string, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher {
public createFileSystemWatcher(globPattern: string | IRelativePattern, ignoreCreateEvents?: boolean, ignoreChangeEvents?: boolean, ignoreDeleteEvents?: boolean): _FileSystemWatcher {
return new FileSystemWatcher(this._emitter.event, globPattern, ignoreCreateEvents, ignoreChangeEvents, ignoreDeleteEvents);
}

View File

@@ -9,22 +9,19 @@ 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, CompletionItem, SnippetString } from 'vs/workbench/api/node/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, MainThreadTelemetryShape, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IRawColorFormatMap, IMainContext } from './extHost.protocol';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion, IWorkspaceSymbols, IWorkspaceSymbol, IdObject } 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';
import { containsCommandLink } from 'vs/base/common/htmlContent';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { once } from 'vs/base/common/functional';
// --- adapter
@@ -179,7 +176,6 @@ class HoverAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.HoverProvider,
private readonly _telemetryLog: (name: string, data: object) => void,
) {
//
}
@@ -200,14 +196,7 @@ class HoverAdapter {
value.range = new Range(pos, pos);
}
const result = TypeConverters.fromHover(value);
// we wanna know which extension uses command links
// because that is a potential trick-attack on users
if (result.contents.some(h => containsCommandLink(h.value))) {
this._telemetryLog('usesCommandLink', { from: 'hover' });
}
return result;
return TypeConverters.fromHover(value);
});
}
}
@@ -273,7 +262,7 @@ class QuickFixAdapter {
private _diagnostics: ExtHostDiagnostics;
private _provider: vscode.CodeActionProvider;
constructor(documents: ExtHostDocuments, commands: CommandsConverter, diagnostics: ExtHostDiagnostics, heapService: ExtHostHeapService, provider: vscode.CodeActionProvider) {
constructor(documents: ExtHostDocuments, commands: CommandsConverter, diagnostics: ExtHostDiagnostics, provider: vscode.CodeActionProvider) {
this._documents = documents;
this._commands = commands;
this._diagnostics = diagnostics;
@@ -283,13 +272,13 @@ class QuickFixAdapter {
provideCodeActions(resource: URI, range: IRange): TPromise<modes.Command[]> {
const doc = this._documents.getDocumentData(resource).document;
const ran = TypeConverters.toRange(range);
const ran = <vscode.Range>TypeConverters.toRange(range);
const allDiagnostics: vscode.Diagnostic[] = [];
this._diagnostics.forEach(collection => {
if (collection.has(resource)) {
for (let diagnostic of collection.get(resource)) {
if (diagnostic.range.intersection(ran)) {
if (ran.contains(diagnostic.range)) {
allDiagnostics.push(diagnostic);
}
}
@@ -378,45 +367,56 @@ class OnTypeFormattingAdapter {
}
}
class NavigateTypeAdapter {
class NavigateTypeAdapter implements IWorkspaceSymbolProvider {
private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null);
private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null);
private readonly _provider: vscode.WorkspaceSymbolProvider;
private _provider: vscode.WorkspaceSymbolProvider;
private _heapService: ExtHostHeapService;
constructor(provider: vscode.WorkspaceSymbolProvider, heapService: ExtHostHeapService) {
constructor(provider: vscode.WorkspaceSymbolProvider) {
this._provider = provider;
this._heapService = heapService;
}
provideWorkspaceSymbols(search: string): TPromise<modes.SymbolInformation[]> {
provideWorkspaceSymbols(search: string): TPromise<IWorkspaceSymbols> {
const result: IWorkspaceSymbols = IdObject.mixin({ symbols: [] });
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (Array.isArray(value)) {
return value.map(item => {
const id = this._heapService.keep(item);
const result = TypeConverters.fromSymbolInformation(item);
return ObjectIdentifier.mixin(result, id);
});
if (!isFalsyOrEmpty(value)) {
for (const item of value) {
const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item));
this._symbolCache[symbol._id] = item;
result.symbols.push(symbol);
}
}
return undefined;
}).then(() => {
this._resultCache[result._id] = [result.symbols[0]._id, result.symbols[result.symbols.length - 1]._id];
return result;
});
}
resolveWorkspaceSymbol(item: modes.SymbolInformation): TPromise<modes.SymbolInformation> {
resolveWorkspaceSymbol(symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
return TPromise.as(item);
return TPromise.as(symbol);
}
const symbolInfo = this._heapService.get<vscode.SymbolInformation>(ObjectIdentifier.of(item));
if (symbolInfo) {
return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(symbolInfo, token)).then(value => {
return value && TypeConverters.fromSymbolInformation(value);
const item = this._symbolCache[symbol._id];
if (item) {
return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => {
return value && mixin(symbol, TypeConverters.fromSymbolInformation(value), true);
});
}
return undefined;
}
releaseWorkspaceSymbols(id: number): any {
const range = this._resultCache[id];
if (range) {
for (let [from, to] = range; from <= to; from++) {
delete this._symbolCache[from];
}
delete this._resultCache[id];
}
}
}
class RenameAdapter {
@@ -447,7 +447,7 @@ class RenameAdapter {
let [uri, textEdits] = entry;
for (let textEdit of textEdits) {
result.edits.push({
resource: <URI>uri,
resource: uri,
newText: textEdit.newText,
range: TypeConverters.fromRange(textEdit.range)
});
@@ -469,26 +469,36 @@ class RenameAdapter {
class SuggestAdapter {
static supportsResolving(provider: vscode.CompletionItemProvider): boolean {
return typeof provider.resolveCompletionItem === 'function';
}
private _documents: ExtHostDocuments;
private _commands: CommandsConverter;
private _heapService: ExtHostHeapService;
private _provider: vscode.CompletionItemProvider;
constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider) {
private _cache = new Map<number, vscode.CompletionItem[]>();
private _idPool = 0;
constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) {
this._documents = documents;
this._commands = commands;
this._heapService = heapService;
this._provider = provider;
}
provideCompletionItems(resource: URI, position: IPosition): TPromise<modes.ISuggestResult> {
provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<IExtHostSuggestResult> {
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
return asWinJsPromise<vscode.CompletionItem[] | vscode.CompletionList>(token => this._provider.provideCompletionItems(doc, pos, token)).then(value => {
return asWinJsPromise<vscode.CompletionItem[] | vscode.CompletionList>(token => {
return this._provider.provideCompletionItems(doc, pos, token, TypeConverters.CompletionContext.from(context));
}).then(value => {
const result: modes.ISuggestResult = {
const _id = this._idPool++;
const result: IExtHostSuggestResult = {
_id,
suggestions: [],
};
@@ -509,19 +519,15 @@ class SuggestAdapter {
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
.with({ end: pos });
for (const item of list.items) {
const suggestion = this._convertCompletionItem(item, pos, wordRangeBeforePos);
// bad completion item
if (!suggestion) {
// converter did warn
continue;
for (let i = 0; i < list.items.length; i++) {
const suggestion = this._convertCompletionItem(list.items[i], pos, wordRangeBeforePos, i, _id);
// check for bad completion item
// for the converter did warn
if (suggestion) {
result.suggestions.push(suggestion);
}
ObjectIdentifier.mixin(suggestion, this._heapService.keep(item));
result.suggestions.push(suggestion);
}
this._cache.set(_id, list.items);
return result;
});
@@ -533,8 +539,8 @@ class SuggestAdapter {
return TPromise.as(suggestion);
}
const id = ObjectIdentifier.of(suggestion);
const item = this._heapService.get<CompletionItem>(id);
const { _parentId, _id } = (<IExtHostSuggestion>suggestion);
const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id];
if (!item) {
return TPromise.as(suggestion);
}
@@ -548,7 +554,7 @@ class SuggestAdapter {
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos)).with({ end: pos });
const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos);
const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId);
if (newSuggestion) {
mixin(suggestion, newSuggestion, true);
}
@@ -557,13 +563,20 @@ class SuggestAdapter {
});
}
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range): modes.ISuggestion {
releaseCompletionItems(id: number): any {
this._cache.delete(id);
}
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): IExtHostSuggestion {
if (typeof item.label !== 'string' || item.label.length === 0) {
console.warn('INVALID text edit -> must have at least a label');
return undefined;
}
const result: modes.ISuggestion = {
const result: IExtHostSuggestion = {
//
_id,
_parentId,
//
label: item.label,
type: TypeConverters.CompletionItemKind.from(item.kind),
@@ -693,8 +706,6 @@ class LinkProviderAdapter {
class ColorProviderAdapter {
private static _colorFormatHandlePool: number = 0;
constructor(
private _proxy: MainThreadLanguageFeaturesShape,
private _documents: ExtHostDocuments,
@@ -709,39 +720,25 @@ class ColorProviderAdapter {
return [];
}
const newRawColorFormats: IRawColorFormatMap = [];
const getFormatId = (format: string) => {
let id = this._colorFormatCache.get(format);
if (typeof id !== 'number') {
id = ColorProviderAdapter._colorFormatHandlePool++;
this._colorFormatCache.set(format, id);
newRawColorFormats.push([id, format]);
}
return id;
};
const colorInfos: IRawColorInfo[] = colors.map(ci => {
const availableFormats = ci.availableFormats.map(format => {
if (typeof format === 'string') {
return getFormatId(format);
} else {
return [getFormatId(format.opaque), getFormatId(format.transparent)] as [number, number];
}
});
return {
color: [ci.color.red, ci.color.green, ci.color.blue, ci.color.alpha] as [number, number, number, number],
availableFormats: availableFormats,
range: TypeConverters.fromRange(ci.range)
};
});
this._proxy.$registerColorFormats(newRawColorFormats);
return colorInfos;
});
}
provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
const document = this._documents.getDocumentData(resource).document;
const range = TypeConverters.toRange(raw.range);
const color = new Color(raw.color[0], raw.color[1], raw.color[2], raw.color[3]);
return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => {
return value.map(TypeConverters.ColorPresentation.from);
});
}
}
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
@@ -754,7 +751,6 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
private static _handlePool: number = 0;
private _proxy: MainThreadLanguageFeaturesShape;
private _telemetry: MainThreadTelemetryShape;
private _documents: ExtHostDocuments;
private _commands: ExtHostCommands;
private _heapService: ExtHostHeapService;
@@ -770,7 +766,6 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
diagnostics: ExtHostDiagnostics
) {
this._proxy = mainContext.get(MainContext.MainThreadLanguageFeatures);
this._telemetry = mainContext.get(MainContext.MainThreadTelemetry);
this._documents = documents;
this._commands = commands;
this._heapService = heapMonitor;
@@ -874,10 +869,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new HoverAdapter(this._documents, provider, once((name, data) => {
data['extension'] = extensionId;
this._telemetry.$publicLog(name, data);
})));
this._adapter.set(handle, new HoverAdapter(this._documents, provider));
this._proxy.$registerHoverProvider(handle, selector);
return this._createDisposable(handle);
}
@@ -916,7 +908,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, this._heapService, provider));
this._adapter.set(handle, new QuickFixAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
this._proxy.$registerQuickFixSupport(handle, selector);
return this._createDisposable(handle);
}
@@ -964,19 +956,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new NavigateTypeAdapter(provider, this._heapService));
this._adapter.set(handle, new NavigateTypeAdapter(provider));
this._proxy.$registerNavigateTypeSupport(handle);
return this._createDisposable(handle);
}
$provideWorkspaceSymbols(handle: number, search: string): TPromise<modes.SymbolInformation[]> {
$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbols> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
}
$resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise<modes.SymbolInformation> {
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
}
$releaseWorkspaceSymbols(handle: number, id: number) {
this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id));
}
// --- rename
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
@@ -994,19 +990,23 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider));
this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters);
this._adapter.set(handle, new SuggestAdapter(this._documents, this._commands.converter, provider));
this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters, SuggestAdapter.supportsResolving(provider));
return this._createDisposable(handle);
}
$provideCompletionItems(handle: number, resource: URI, position: IPosition): TPromise<modes.ISuggestResult> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position));
$provideCompletionItems(handle: number, resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<IExtHostSuggestResult> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position, context));
}
$resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(resource, position, suggestion));
}
$releaseCompletionItems(handle: number, id: number): void {
this._withAdapter(handle, SuggestAdapter, adapter => adapter.releaseCompletionItems(id));
}
// --- parameter hints
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
@@ -1048,6 +1048,10 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(resource));
}
$provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(resource, colorInfo));
}
// --- configuration
setLanguageConfiguration(languageId: string, configuration: vscode.LanguageConfiguration): vscode.Disposable {

View File

@@ -5,21 +5,28 @@
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { wireCancellationToken } from 'vs/base/common/async';
import { wireCancellationToken, asWinJsPromise } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickPickOptions, QuickPickItem, InputBoxOptions } from 'vscode';
import { QuickPickOptions, QuickPickItem, InputBoxOptions, WorkspaceFolderPickOptions, WorkspaceFolder } from 'vscode';
import { MainContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, MyQuickPickItems, IMainContext } from './extHost.protocol';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
export type Item = string | QuickPickItem;
export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
private _proxy: MainThreadQuickOpenShape;
private _onDidSelectItem: (handle: number) => void;
private _validateInput: (input: string) => string;
private _workspace: ExtHostWorkspace;
private _commands: ExtHostCommands;
constructor(mainContext: IMainContext) {
private _onDidSelectItem: (handle: number) => void;
private _validateInput: (input: string) => string | Thenable<string>;
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) {
this._proxy = mainContext.get(MainContext.MainThreadQuickOpen);
this._workspace = workspace;
this._commands = commands;
}
showQuickPick(itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
@@ -113,8 +120,20 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
$validateInput(input: string): TPromise<string> {
if (this._validateInput) {
return TPromise.as(this._validateInput(input));
return asWinJsPromise(_ => this._validateInput(input));
}
return undefined;
}
// ---- workspace folder picker
showWorkspaceFolderPick(options?: WorkspaceFolderPickOptions, token = CancellationToken.None): Thenable<WorkspaceFolder> {
return this._commands.executeCommand('_workbench.pickWorkspaceFolder', [options]).then((selectedFolder: WorkspaceFolder) => {
if (!selectedFolder) {
return undefined;
}
return this._workspace.getWorkspaceFolders().filter(folder => folder.uri.toString() === selectedFolder.uri.toString())[0];
});
}
}

View File

@@ -6,13 +6,21 @@
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import Event, { Emitter, once } from 'vs/base/common/event';
import { debounce } from 'vs/base/common/decorators';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { asWinJsPromise } from 'vs/base/common/async';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { MainContext, MainThreadSCMShape, SCMRawResource, IMainContext } from './extHost.protocol';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext } from './extHost.protocol';
import { sortedDiff } from 'vs/base/common/arrays';
import { comparePaths } from 'vs/base/common/comparers';
import * as vscode from 'vscode';
type ProviderHandle = number;
type GroupHandle = number;
type ResourceStateHandle = number;
function getIconPath(decorations: vscode.SourceControlResourceThemableDecorations) {
if (!decorations) {
return undefined;
@@ -24,6 +32,82 @@ function getIconPath(decorations: vscode.SourceControlResourceThemableDecoration
return undefined;
}
function compareResourceThemableDecorations(a: vscode.SourceControlResourceThemableDecorations, b: vscode.SourceControlResourceThemableDecorations): number {
if (!a.iconPath && !b.iconPath) {
return 0;
} else if (!a.iconPath) {
return -1;
} else if (!b.iconPath) {
return 1;
}
const aPath = typeof a.iconPath === 'string' ? a.iconPath : a.iconPath.fsPath;
const bPath = typeof b.iconPath === 'string' ? b.iconPath : b.iconPath.fsPath;
return comparePaths(aPath, bPath);
}
function compareResourceStatesDecorations(a: vscode.SourceControlResourceDecorations, b: vscode.SourceControlResourceDecorations): number {
let result = 0;
if (a.strikeThrough !== b.strikeThrough) {
return a.strikeThrough ? 1 : -1;
}
if (a.faded !== b.faded) {
return a.faded ? 1 : -1;
}
if (a.tooltip !== b.tooltip) {
return (a.tooltip || '').localeCompare(b.tooltip);
}
result = compareResourceThemableDecorations(a, b);
if (result !== 0) {
return result;
}
if (a.light && b.light) {
result = compareResourceThemableDecorations(a.light, b.light);
} else if (a.light) {
return 1;
} else if (b.light) {
return -1;
}
if (result !== 0) {
return result;
}
if (a.dark && b.dark) {
result = compareResourceThemableDecorations(a.dark, b.dark);
} else if (a.dark) {
return 1;
} else if (b.dark) {
return -1;
}
return result;
}
function compareResourceStates(a: vscode.SourceControlResourceState, b: vscode.SourceControlResourceState): number {
let result = comparePaths(a.resourceUri.fsPath, b.resourceUri.fsPath);
if (result !== 0) {
return result;
}
if (a.decorations && b.decorations) {
result = compareResourceStatesDecorations(a.decorations, b.decorations);
} else if (a.decorations) {
return 1;
} else if (b.decorations) {
return -1;
}
return result;
}
export class ExtHostSCMInputBox {
private _value: string = '';
@@ -62,99 +146,135 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
private static _handlePool: number = 0;
private _resourceHandlePool: number = 0;
private _resourceStates: vscode.SourceControlResourceState[] = [];
private _resourceStatesRollingDisposables: { (): void }[] = [];
private _resourceStatesMap: Map<ResourceStateHandle, vscode.SourceControlResourceState> = new Map<ResourceStateHandle, vscode.SourceControlResourceState>();
private _resourceStatesCommandsMap: Map<ResourceStateHandle, vscode.Command> = new Map<ResourceStateHandle, vscode.Command>();
get id(): string {
return this._id;
}
private _onDidUpdateResourceStates = new Emitter<void>();
readonly onDidUpdateResourceStates = this._onDidUpdateResourceStates.event;
private _onDidDispose = new Emitter<void>();
readonly onDidDispose = this._onDidDispose.event;
get label(): string {
return this._label;
}
private _handlesSnapshot: number[] = [];
private _resourceSnapshot: vscode.SourceControlResourceState[] = [];
get id(): string { return this._id; }
get label(): string { return this._label; }
set label(label: string) {
this._label = label;
this._proxy.$updateGroupLabel(this._sourceControlHandle, this._handle, label);
this._proxy.$updateGroupLabel(this._sourceControlHandle, this.handle, label);
}
private _hideWhenEmpty: boolean | undefined = undefined;
get hideWhenEmpty(): boolean | undefined {
return this._hideWhenEmpty;
}
get hideWhenEmpty(): boolean | undefined { return this._hideWhenEmpty; }
set hideWhenEmpty(hideWhenEmpty: boolean | undefined) {
this._hideWhenEmpty = hideWhenEmpty;
this._proxy.$updateGroup(this._sourceControlHandle, this._handle, { hideWhenEmpty });
}
get resourceStates(): vscode.SourceControlResourceState[] {
return [...this._resourceStates];
this._proxy.$updateGroup(this._sourceControlHandle, this.handle, { hideWhenEmpty });
}
get resourceStates(): vscode.SourceControlResourceState[] { return [...this._resourceStates]; }
set resourceStates(resources: vscode.SourceControlResourceState[]) {
this._resourceStates = [...resources];
const handles: number[] = [];
const rawResources = resources.map(r => {
const handle = this._resourceHandlePool++;
this._resourceStatesMap.set(handle, r);
handles.push(handle);
const sourceUri = r.resourceUri.toString();
const command = this._commands.toInternal(r.command);
const iconPath = getIconPath(r.decorations);
const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath;
const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath;
const icons: string[] = [];
if (lightIconPath || darkIconPath) {
icons.push(lightIconPath);
}
if (darkIconPath !== lightIconPath) {
icons.push(darkIconPath);
}
const tooltip = (r.decorations && r.decorations.tooltip) || '';
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
return [handle, sourceUri, command, icons, tooltip, strikeThrough, faded] as SCMRawResource;
});
const disposable = () => handles.forEach(handle => this._resourceStatesMap.delete(handle));
this._resourceStatesRollingDisposables.push(disposable);
while (this._resourceStatesRollingDisposables.length >= 10) {
this._resourceStatesRollingDisposables.shift()();
}
this._proxy.$updateGroupResourceStates(this._sourceControlHandle, this._handle, rawResources);
this._onDidUpdateResourceStates.fire();
}
private _handle: GroupHandle = ExtHostSourceControlResourceGroup._handlePool++;
get handle(): GroupHandle {
return this._handle;
}
readonly handle = ExtHostSourceControlResourceGroup._handlePool++;
private _disposables: IDisposable[] = [];
constructor(
private _proxy: MainThreadSCMShape,
private _commands: CommandsConverter,
private _commands: ExtHostCommands,
private _sourceControlHandle: number,
private _id: string,
private _label: string,
) {
this._proxy.$registerGroup(_sourceControlHandle, this._handle, _id, _label);
this._proxy.$registerGroup(_sourceControlHandle, this.handle, _id, _label);
}
getResourceState(handle: number): vscode.SourceControlResourceState | undefined {
return this._resourceStatesMap.get(handle);
}
async $executeResourceCommand(handle: number): TPromise<void> {
const command = this._resourceStatesCommandsMap.get(handle);
if (!command) {
return;
}
await this._commands.executeCommand(command.command, ...command.arguments);
}
_takeResourceStateSnapshot(): SCMRawResourceSplice[] {
const snapshot = [...this._resourceStates].sort(compareResourceStates);
const diffs = sortedDiff(this._resourceSnapshot, snapshot, compareResourceStates);
const handlesToDelete: number[] = [];
const splices = diffs.map(diff => {
const { start, deleteCount } = diff;
const handles: number[] = [];
const rawResources = diff.inserted
.map(r => {
const handle = this._resourceHandlePool++;
this._resourceStatesMap.set(handle, r);
handles.push(handle);
const sourceUri = r.resourceUri.toString();
const iconPath = getIconPath(r.decorations);
const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath;
const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath;
const icons: string[] = [];
if (r.command) {
this._resourceStatesCommandsMap.set(handle, r.command);
}
if (lightIconPath || darkIconPath) {
icons.push(lightIconPath);
}
if (darkIconPath !== lightIconPath) {
icons.push(darkIconPath);
}
const tooltip = (r.decorations && r.decorations.tooltip) || '';
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
const source = r.decorations && r.decorations.source || undefined;
const letter = r.decorations && r.decorations.letter || undefined;
const color = r.decorations && r.decorations.color || undefined;
return [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource;
});
handlesToDelete.push(...this._handlesSnapshot.splice(start, deleteCount, ...handles));
return [start, deleteCount, rawResources] as SCMRawResourceSplice;
});
const disposable = () => handlesToDelete.forEach(handle => {
this._resourceStatesMap.delete(handle);
this._resourceStatesCommandsMap.delete(handle);
});
this._resourceStatesRollingDisposables.push(disposable);
while (this._resourceStatesRollingDisposables.length >= 10) {
this._resourceStatesRollingDisposables.shift()();
}
this._resourceSnapshot = snapshot;
return splices;
}
dispose(): void {
this._proxy.$unregisterGroup(this._sourceControlHandle, this._handle);
this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle);
this._disposables = dispose(this._disposables);
this._onDidDispose.fire();
}
}
@@ -171,6 +291,10 @@ class ExtHostSourceControl implements vscode.SourceControl {
return this._label;
}
get rootUri(): vscode.Uri | undefined {
return this._rootUri;
}
private _inputBox: ExtHostSCMInputBox;
get inputBox(): ExtHostSCMInputBox { return this._inputBox; }
@@ -182,7 +306,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
set count(count: number | undefined) {
this._count = count;
this._proxy.$updateSourceControl(this._handle, { count });
this._proxy.$updateSourceControl(this.handle, { count });
}
private _quickDiffProvider: vscode.QuickDiffProvider | undefined = undefined;
@@ -193,7 +317,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
set quickDiffProvider(quickDiffProvider: vscode.QuickDiffProvider | undefined) {
this._quickDiffProvider = quickDiffProvider;
this._proxy.$updateSourceControl(this._handle, { hasQuickDiffProvider: !!quickDiffProvider });
this._proxy.$updateSourceControl(this.handle, { hasQuickDiffProvider: !!quickDiffProvider });
}
private _commitTemplate: string | undefined = undefined;
@@ -204,7 +328,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
set commitTemplate(commitTemplate: string | undefined) {
this._commitTemplate = commitTemplate;
this._proxy.$updateSourceControl(this._handle, { commitTemplate });
this._proxy.$updateSourceControl(this.handle, { commitTemplate });
}
private _acceptInputCommand: vscode.Command | undefined = undefined;
@@ -216,8 +340,8 @@ class ExtHostSourceControl implements vscode.SourceControl {
set acceptInputCommand(acceptInputCommand: vscode.Command | undefined) {
this._acceptInputCommand = acceptInputCommand;
const internal = this._commands.toInternal(acceptInputCommand);
this._proxy.$updateSourceControl(this._handle, { acceptInputCommand: internal });
const internal = this._commands.converter.toInternal(acceptInputCommand);
this._proxy.$updateSourceControl(this.handle, { acceptInputCommand: internal });
}
private _statusBarCommands: vscode.Command[] | undefined = undefined;
@@ -229,41 +353,74 @@ class ExtHostSourceControl implements vscode.SourceControl {
set statusBarCommands(statusBarCommands: vscode.Command[] | undefined) {
this._statusBarCommands = statusBarCommands;
const internal = (statusBarCommands || []).map(c => this._commands.toInternal(c));
this._proxy.$updateSourceControl(this._handle, { statusBarCommands: internal });
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c));
this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal });
}
private _handle: number = ExtHostSourceControl._handlePool++;
private handle: number = ExtHostSourceControl._handlePool++;
constructor(
private _proxy: MainThreadSCMShape,
private _commands: CommandsConverter,
private _commands: ExtHostCommands,
private _id: string,
private _label: string,
private _rootUri?: vscode.Uri
) {
this._inputBox = new ExtHostSCMInputBox(this._proxy, this._handle);
this._proxy.$registerSourceControl(this._handle, _id, _label);
this._inputBox = new ExtHostSCMInputBox(this._proxy, this.handle);
this._proxy.$registerSourceControl(this.handle, _id, _label, _rootUri && _rootUri.toString());
}
private updatedResourceGroups = new Set<ExtHostSourceControlResourceGroup>();
createResourceGroup(id: string, label: string): ExtHostSourceControlResourceGroup {
const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this._handle, id, label);
const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this.handle, id, label);
const updateListener = group.onDidUpdateResourceStates(() => {
this.updatedResourceGroups.add(group);
this.eventuallyUpdateResourceStates();
});
once(group.onDidDispose)(() => {
this.updatedResourceGroups.delete(group);
updateListener.dispose();
this._groups.delete(group.handle);
});
this._groups.set(group.handle, group);
return group;
}
@debounce(100)
eventuallyUpdateResourceStates(): void {
const splices: SCMRawResourceSplices[] = [];
this.updatedResourceGroups.forEach(group => {
const snapshot = group._takeResourceStateSnapshot();
if (snapshot.length === 0) {
return;
}
splices.push([group.handle, snapshot]);
});
if (splices.length > 0) {
this._proxy.$spliceResourceStates(this.handle, splices);
}
this.updatedResourceGroups.clear();
}
getResourceGroup(handle: GroupHandle): ExtHostSourceControlResourceGroup | undefined {
return this._groups.get(handle);
}
dispose(): void {
this._proxy.$unregisterSourceControl(this._handle);
this._groups.forEach(group => group.dispose());
this._proxy.$unregisterSourceControl(this.handle);
}
}
type ProviderHandle = number;
type GroupHandle = number;
type ResourceStateHandle = number;
export class ExtHostSCM {
private static _handlePool: number = 0;
@@ -320,9 +477,9 @@ export class ExtHostSCM {
});
}
createSourceControl(extension: IExtensionDescription, id: string, label: string): vscode.SourceControl {
createSourceControl(extension: IExtensionDescription, id: string, label: string, rootUri: vscode.Uri | undefined): vscode.SourceControl {
const handle = ExtHostSCM._handlePool++;
const sourceControl = new ExtHostSourceControl(this._proxy, this._commands.converter, id, label);
const sourceControl = new ExtHostSourceControl(this._proxy, this._commands, id, label, rootUri);
this._sourceControls.set(handle, sourceControl);
const sourceControls = this._sourceControlsByExtension.get(extension.id) || [];
@@ -357,11 +514,27 @@ export class ExtHostSCM {
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void> {
const sourceControl = this._sourceControls.get(sourceControlHandle);
if (!sourceControl || !sourceControl.quickDiffProvider) {
if (!sourceControl) {
return TPromise.as(null);
}
sourceControl.inputBox.$onInputBoxValueChange(value);
return TPromise.as(null);
}
async $executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void> {
const sourceControl = this._sourceControls.get(sourceControlHandle);
if (!sourceControl) {
return;
}
const group = sourceControl.getResourceGroup(groupHandle);
if (!group) {
return;
}
await group.$executeResourceCommand(handle);
}
}

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import * as Objects from 'vs/base/common/objects';
@@ -15,6 +16,7 @@ import * as TaskSystem from 'vs/workbench/parts/tasks/common/tasks';
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import * as vscode from 'vscode';
interface StringMap<V> {
@@ -116,7 +118,7 @@ namespace FileLocation {
case types.FileLocationKind.Absolute:
return { kind: Problems.FileLocationKind.Absolute };
case types.FileLocationKind.Relative:
return { kind: Problems.FileLocationKind.Relative, prefix: '${workspaceRoot}' };
return { kind: Problems.FileLocationKind.Relative, prefix: '${workspaceFolder}' };
}
return { kind: Problems.FileLocationKind.Auto };
}
@@ -295,13 +297,13 @@ namespace ShellConfiguration {
namespace Tasks {
export function from(tasks: vscode.Task[], extension: IExtensionDescription): TaskSystem.Task[] {
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.Task[] {
if (tasks === void 0 || tasks === null) {
return [];
}
let result: TaskSystem.Task[] = [];
for (let task of tasks) {
let converted = fromSingle(task, extension);
let converted = fromSingle(task, rootFolder, extension);
if (converted) {
result.push(converted);
}
@@ -309,7 +311,7 @@ namespace Tasks {
return result;
}
function fromSingle(task: vscode.Task, extension: IExtensionDescription): TaskSystem.ContributedTask {
function fromSingle(task: vscode.Task, rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask {
if (typeof task.name !== 'string') {
return undefined;
}
@@ -326,11 +328,33 @@ namespace Tasks {
return undefined;
}
command.presentation = PresentationOptions.from(task.presentationOptions);
let source = {
let taskScope: types.TaskScope.Global | types.TaskScope.Workspace | vscode.WorkspaceFolder | undefined = task.scope;
let workspaceFolder: vscode.WorkspaceFolder | undefined;
let scope: TaskSystem.TaskScope;
// For backwards compatibility
if (taskScope === void 0) {
scope = TaskSystem.TaskScope.Folder;
workspaceFolder = rootFolder;
} else if (taskScope === types.TaskScope.Global) {
scope = TaskSystem.TaskScope.Global;
} else if (taskScope === types.TaskScope.Workspace) {
scope = TaskSystem.TaskScope.Workspace;
} else {
scope = TaskSystem.TaskScope.Folder;
workspaceFolder = taskScope;
}
let source: TaskSystem.ExtensionTaskSource = {
kind: TaskSystem.TaskSourceKind.Extension,
label: typeof task.source === 'string' ? task.source : extension.name,
extension: extension.id
extension: extension.id,
scope: scope,
workspaceFolder: undefined
};
// 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;
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;
@@ -398,11 +422,13 @@ interface HandlerData {
export class ExtHostTask implements ExtHostTaskShape {
private _proxy: MainThreadTaskShape;
private _extHostWorkspace: ExtHostWorkspace;
private _handleCounter: number;
private _handlers: Map<number, HandlerData>;
constructor(mainContext: IMainContext) {
constructor(mainContext: IMainContext, extHostWorkspace: ExtHostWorkspace) {
this._proxy = mainContext.get(MainContext.MainThreadTask);
this._extHostWorkspace = extHostWorkspace;
this._handleCounter = 0;
this._handlers = new Map<number, HandlerData>();
};
@@ -426,8 +452,9 @@ export class ExtHostTask implements ExtHostTaskShape {
return TPromise.wrapError<TaskSystem.TaskSet>(new Error('no handler found'));
}
return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => {
let workspaceFolders = this._extHostWorkspace.getWorkspaceFolders();
return {
tasks: Tasks.from(value, handler.extension),
tasks: Tasks.from(value, workspaceFolders && workspaceFolders.length > 0 ? workspaceFolders[0] : undefined, handler.extension),
extension: handler.extension
};
});

View File

@@ -24,6 +24,7 @@ export class ExtHostTerminal implements vscode.Terminal {
name?: string,
shellPath?: string,
shellArgs?: string[],
env?: { [key: string]: string },
waitOnExit?: boolean
) {
this._name = name;
@@ -32,7 +33,7 @@ export class ExtHostTerminal implements vscode.Terminal {
this._pidPromise = new TPromise<number>(c => {
this._pidPromiseComplete = c;
});
this._proxy.$createTerminal(name, shellPath, shellArgs, waitOnExit).then((id) => {
this._proxy.$createTerminal(name, shellPath, shellArgs, env, waitOnExit).then((id) => {
this._id = id;
this._queuedRequests.forEach((r) => {
r.run(this._proxy, this._id);
@@ -113,7 +114,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs/*, options.waitOnExit*/);
let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs, options.env/*, options.waitOnExit*/);
this._terminals.push(terminal);
return terminal;
}
@@ -134,7 +135,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public $acceptTerminalProcessId(id: number, processId: number): void {
let terminal = this._getTerminalById(id);
terminal._setProcessId(processId);
if (terminal) {
terminal._setProcessId(processId);
}
}
private _getTerminalById(id: number): ExtHostTerminal {

View File

@@ -6,19 +6,17 @@
import { ok } from 'vs/base/common/assert';
import { readonly, illegalArgument, V8CallSite } from 'vs/base/common/errors';
import { readonly, illegalArgument } from 'vs/base/common/errors';
import { IdGenerator } from 'vs/base/common/idGenerator';
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 * as TypeConverters from './extHostTypeConverters';
import { MainThreadEditorsShape, MainThreadTelemetryShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } 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';
import { containsCommandLink } from 'vs/base/common/htmlContent';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
export class TextEditorDecorationType implements vscode.TextEditorDecorationType {
@@ -418,11 +416,29 @@ export class ExtHostTextEditor implements vscode.TextEditor {
setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
this._runOnProxy(
() => this._proxy.$trySetDecorations(
this._id,
decorationType.key,
TypeConverters.fromRangeOrRangeWithMessage(ranges)
)
() => {
if (TypeConverters.isDecorationOptionsArr(ranges)) {
return this._proxy.$trySetDecorations(
this._id,
decorationType.key,
TypeConverters.fromRangeOrRangeWithMessage(ranges)
);
} else {
let _ranges: number[] = new Array<number>(4 * ranges.length);
for (let i = 0, len = ranges.length; i < len; i++) {
const range = ranges[i];
_ranges[4 * i] = range.start.line + 1;
_ranges[4 * i + 1] = range.start.character + 1;
_ranges[4 * i + 2] = range.end.line + 1;
_ranges[4 * i + 3] = range.end.character + 1;
}
return this._proxy.$trySetDecorationsFast(
this._id,
decorationType.key,
/*TODO: marshaller is too slow*/JSON.stringify(_ranges)
);
}
}
);
}
@@ -552,70 +568,6 @@ export class ExtHostTextEditor implements vscode.TextEditor {
}
}
export class ExtHostTextEditor2 extends ExtHostTextEditor {
constructor(
private readonly _extHostExtensions: ExtHostExtensionService,
private readonly _mainThreadTelemetry: MainThreadTelemetryShape,
proxy: MainThreadEditorsShape,
id: string,
document: ExtHostDocumentData,
selections: Selection[],
options: IResolvedTextEditorConfiguration,
viewColumn: vscode.ViewColumn
) {
super(proxy, id, document, selections, options, viewColumn);
}
setDecorations(decorationType: vscode.TextEditorDecorationType, rangesOrOptions: Range[] | vscode.DecorationOptions[]): void {
// (1) find out if this decoration is important for us
let usesCommandLink = false;
outer: for (const rangeOrOption of rangesOrOptions) {
if (Range.isRange(rangeOrOption)) {
break;
}
if (typeof rangeOrOption.hoverMessage === 'string' && containsCommandLink(rangeOrOption.hoverMessage)) {
usesCommandLink = true;
break;
} else if (Array.isArray(rangeOrOption.hoverMessage)) {
for (const message of rangeOrOption.hoverMessage) {
if (typeof message === 'string' && containsCommandLink(message)) {
usesCommandLink = true;
break outer;
}
}
}
}
// (2) send event for important decorations
if (usesCommandLink) {
let tag = new Error();
this._extHostExtensions.getExtensionPathIndex().then(index => {
const oldHandler = (<any>Error).prepareStackTrace;
(<any>Error).prepareStackTrace = (error: Error, stackTrace: V8CallSite[]) => {
for (const call of stackTrace) {
const extension = index.findSubstr(call.getFileName());
if (extension) {
this._mainThreadTelemetry.$publicLog('usesCommandLink', {
extension: extension.id,
from: 'decoration',
});
return;
}
}
};
// it all happens here...
// tslint:disable-next-line:no-unused-expression
tag.stack;
(<any>Error).prepareStackTrace = oldHandler;
});
}
// (3) do it
super.setDecorations(decorationType, rangesOrOptions);
}
}
function warnOnError(promise: TPromise<any>): void {
promise.then(null, (err) => {
console.warn(err);

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import Event, { Emitter } from 'vs/base/common/event';
import { toThenable } from 'vs/base/common/async';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -13,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 } from './extHost.protocol';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, IWorkspaceResourceEdit } from './extHost.protocol';
import * as vscode from 'vscode';
export class ExtHostEditors implements ExtHostEditorsShape {
@@ -77,7 +76,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
};
}
return this._proxy.$tryShowTextDocument(<URI>document.uri, options).then(id => {
return this._proxy.$tryShowTextDocument(document.uri, options).then(id => {
let editor = this._extHostDocumentsAndEditors.getEditor(id);
if (editor) {
return editor;
@@ -91,6 +90,40 @@ export class ExtHostEditors implements ExtHostEditorsShape {
return new TextEditorDecorationType(this._proxy, options);
}
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
let workspaceResourceEdits: IWorkspaceResourceEdit[] = [];
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)
});
}
workspaceResourceEdits.push(workspaceResourceEdit);
}
return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits);
}
// --- called from main thread
$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void {

View File

@@ -12,7 +12,7 @@ import { debounceEvent } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/parts/views/common/views';
import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views';
import { TreeItemCollapsibleState } from './extHostTypes';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
@@ -175,7 +175,7 @@ class ExtHostTreeView<T> extends Disposable {
};
}
private getLightIconPath(extensionTreeItem: vscode.TreeItem) {
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
return this.getIconPath(extensionTreeItem.iconPath);
@@ -185,7 +185,7 @@ class ExtHostTreeView<T> extends Disposable {
return void 0;
}
private getDarkIconPath(extensionTreeItem: vscode.TreeItem) {
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}

View File

@@ -115,6 +115,8 @@ export function fromViewColumn(column?: vscode.ViewColumn): EditorPosition {
editorColumn = EditorPosition.TWO;
} else if (column === <number>types.ViewColumn.Three) {
editorColumn = EditorPosition.THREE;
} else if (column === <number>types.ViewColumn.Active) {
editorColumn = undefined;
}
return editorColumn;
}
@@ -137,7 +139,7 @@ function isDecorationOptions(something: any): something is vscode.DecorationOpti
return (typeof something.range !== 'undefined');
}
function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] {
export function isDecorationOptionsArr(something: vscode.Range[] | vscode.DecorationOptions[]): something is vscode.DecorationOptions[] {
if (something.length === 0) {
return true;
}
@@ -156,7 +158,7 @@ export namespace MarkdownString {
}
function isCodeblock(thing: any): thing is Codeblock {
return typeof thing === 'object'
return thing && typeof thing === 'object'
&& typeof (<Codeblock>thing).language === 'string'
&& typeof (<Codeblock>thing).value === 'string';
}
@@ -168,7 +170,7 @@ export namespace MarkdownString {
} else if (htmlContent.isMarkdownString(markup)) {
return markup;
} else if (typeof markup === 'string') {
return { value: <string>markup, isTrusted: true };
return { value: <string>markup };
} else {
return { value: '' };
}
@@ -178,6 +180,13 @@ export namespace MarkdownString {
ret.isTrusted = value.isTrusted;
return ret;
}
export function fromStrict(value: string | types.MarkdownString): undefined | string | htmlContent.IMarkdownString {
if (!value) {
return undefined;
}
return typeof value === 'string' ? value : MarkdownString.from(value);
}
}
export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.DecorationOptions[]): IDecorationOptions[] {
@@ -282,7 +291,7 @@ export const location = {
from(value: vscode.Location): modes.Location {
return {
range: value.range && fromRange(value.range),
uri: <URI>value.uri
uri: value.uri
};
},
to(value: modes.Location): types.Location {
@@ -305,6 +314,28 @@ export function toDocumentHighlight(occurrence: modes.DocumentHighlight): types.
return new types.DocumentHighlight(toRange(occurrence.range), occurrence.kind);
}
export namespace CompletionTriggerKind {
export function from(kind: modes.SuggestTriggerKind) {
switch (kind) {
case modes.SuggestTriggerKind.TriggerCharacter:
return types.CompletionTriggerKind.TriggerCharacter;
case modes.SuggestTriggerKind.Invoke:
default:
return types.CompletionTriggerKind.Invoke;
}
}
}
export namespace CompletionContext {
export function from(context: modes.SuggestContext): types.CompletionContext {
return {
triggerKind: CompletionTriggerKind.from(context.triggerKind),
triggerCharacter: context.triggerCharacter
};
}
}
export const CompletionItemKind = {
from(kind: types.CompletionItemKind): modes.SuggestionType {
@@ -354,7 +385,7 @@ export namespace Suggest {
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.type);
result.detail = suggestion.detail;
result.documentation = suggestion.documentation;
result.documentation = <string>suggestion.documentation; // htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation;
result.sortText = suggestion.sortText;
result.filterText = suggestion.filterText;
@@ -381,14 +412,56 @@ export namespace Suggest {
}
};
export namespace SignatureHelp {
export namespace ParameterInformation {
export function from(info: types.ParameterInformation): modes.ParameterInformation {
return {
label: info.label,
documentation: MarkdownString.fromStrict(info.documentation)
};
}
export function to(info: modes.ParameterInformation): types.ParameterInformation {
return {
label: info.label,
documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation
};
}
}
export function from(signatureHelp: types.SignatureHelp): modes.SignatureHelp {
return signatureHelp;
export namespace SignatureInformation {
export function from(info: types.SignatureInformation): modes.SignatureInformation {
return {
label: info.label,
documentation: MarkdownString.fromStrict(info.documentation),
parameters: info.parameters && info.parameters.map(ParameterInformation.from)
};
}
export function to(hints: modes.SignatureHelp): types.SignatureHelp {
return hints;
export function to(info: modes.SignatureInformation): types.SignatureInformation {
return {
label: info.label,
documentation: htmlContent.isMarkdownString(info.documentation) ? MarkdownString.to(info.documentation) : info.documentation,
parameters: info.parameters && info.parameters.map(ParameterInformation.to)
};
}
}
export namespace SignatureHelp {
export function from(help: types.SignatureHelp): modes.SignatureHelp {
return {
activeSignature: help.activeSignature,
activeParameter: help.activeParameter,
signatures: help.signatures && help.signatures.map(SignatureInformation.from)
};
}
export function to(help: modes.SignatureHelp): types.SignatureHelp {
return {
activeSignature: help.activeSignature,
activeParameter: help.activeParameter,
signatures: help.signatures && help.signatures.map(SignatureInformation.to)
};
}
}
@@ -406,6 +479,24 @@ export namespace DocumentLink {
}
}
export namespace ColorPresentation {
export function to(colorPresentation: modes.IColorPresentation): vscode.ColorPresentation {
return {
label: colorPresentation.label,
textEdit: colorPresentation.textEdit ? TextEdit.to(colorPresentation.textEdit) : undefined,
additionalTextEdits: colorPresentation.additionalTextEdits ? colorPresentation.additionalTextEdits.map(value => TextEdit.to(value)) : undefined
};
}
export function from(colorPresentation: vscode.ColorPresentation): modes.IColorPresentation {
return {
label: colorPresentation.label,
textEdit: colorPresentation.textEdit ? TextEdit.from(colorPresentation.textEdit) : undefined,
additionalTextEdits: colorPresentation.additionalTextEdits ? colorPresentation.additionalTextEdits.map(value => TextEdit.from(value)) : undefined
};
}
}
export namespace TextDocumentSaveReason {
export function to(reason: SaveReason): vscode.TextDocumentSaveReason {

View File

@@ -7,10 +7,10 @@
import * as crypto from 'crypto';
import URI from 'vs/base/common/uri';
import { Color as BaseColor, HSLA } from 'vs/base/common/color';
import { illegalArgument } from 'vs/base/common/errors';
import * as vscode from 'vscode';
import { isMarkdownString } from 'vs/base/common/htmlContent';
import { IRelativePattern } from 'vs/base/common/glob';
export class Disposable {
@@ -794,7 +794,7 @@ export class SymbolInformation {
if (locationOrUri instanceof Location) {
this.location = locationOrUri;
} else if (rangeOrContainer instanceof Range) {
this.location = new Location(<URI>locationOrUri, rangeOrContainer);
this.location = new Location(locationOrUri, rangeOrContainer);
}
}
@@ -824,12 +824,42 @@ export class CodeLens {
}
}
export class MarkdownString {
value: string;
isTrusted?: boolean;
constructor(value?: string) {
this.value = value || '';
}
appendText(value: string): MarkdownString {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
this.value += value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&');
return this;
}
appendMarkdown(value: string): MarkdownString {
this.value += value;
return this;
}
appendCodeblock(code: string, language: string = ''): MarkdownString {
this.value += '\n```';
this.value += language;
this.value += '\n';
this.value += code;
this.value += '\n```\n';
return this;
}
}
export class ParameterInformation {
label: string;
documentation?: string;
documentation?: string | MarkdownString;
constructor(label: string, documentation?: string) {
constructor(label: string, documentation?: string | MarkdownString) {
this.label = label;
this.documentation = documentation;
}
@@ -838,10 +868,10 @@ export class ParameterInformation {
export class SignatureInformation {
label: string;
documentation?: string;
documentation?: string | MarkdownString;
parameters: ParameterInformation[];
constructor(label: string, documentation?: string) {
constructor(label: string, documentation?: string | MarkdownString) {
this.label = label;
this.documentation = documentation;
this.parameters = [];
@@ -859,6 +889,16 @@ export class SignatureHelp {
}
}
export enum CompletionTriggerKind {
Invoke = 0,
TriggerCharacter = 1
}
export interface CompletionContext {
triggerKind: CompletionTriggerKind;
triggerCharacter: string;
}
export enum CompletionItemKind {
Text = 0,
Method = 1,
@@ -892,6 +932,7 @@ export class CompletionItem {
label: string;
kind: CompletionItemKind;
detail: string;
// {{SQL CARBON EDIT}}
documentation: string;
sortText: string;
filterText: string;
@@ -933,6 +974,7 @@ export class CompletionList {
}
export enum ViewColumn {
Active = -1,
One = 1,
Two = 2,
Three = 3
@@ -1031,47 +1073,46 @@ export class Color {
this.blue = blue;
this.alpha = alpha;
}
static fromHSLA(hue: number, saturation: number, luminance: number, alpha: number): Color {
const color = new BaseColor(new HSLA(hue, saturation, luminance, alpha)).rgba;
return new Color(color.r, color.g, color.b, color.a);
}
static fromHex(hex: string): Color | null {
let baseColor = BaseColor.Format.CSS.parseHex(hex);
if (baseColor) {
const rgba = baseColor.rgba;
return new Color(rgba.r, rgba.g, rgba.b, rgba.a);
}
return null;
}
}
export type IColorFormat = string | { opaque: string, transparent: string };
export class ColorRange {
export class ColorInformation {
range: Range;
color: Color;
availableFormats: IColorFormat[];
constructor(range: Range, color: Color, availableFormats: IColorFormat[]) {
constructor(range: Range, color: Color) {
if (color && !(color instanceof Color)) {
throw illegalArgument('color');
}
if (availableFormats && !Array.isArray(availableFormats)) {
throw illegalArgument('availableFormats');
}
if (!Range.isRange(range) || range.isEmpty) {
throw illegalArgument('range');
}
this.range = range;
this.color = color;
this.availableFormats = availableFormats;
}
}
export class ColorPresentation {
label: string;
textEdit?: TextEdit;
additionalTextEdits?: TextEdit[];
constructor(label: string) {
if (!label || typeof label !== 'string') {
throw illegalArgument('label');
}
this.label = label;
}
}
export enum ColorFormat {
RGB = 0,
HEX = 1,
HSL = 2
}
export enum TaskRevealKind {
Always = 1,
@@ -1208,10 +1249,16 @@ export class ShellExecution implements vscode.ShellExecution {
}
}
export enum TaskScope {
Global = 1,
Workspace = 2
}
export class Task implements vscode.Task {
private _definition: vscode.TaskDefinition;
private _definitionKey: string;
private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder;
private _name: string;
private _execution: ProcessExecution | ShellExecution;
private _problemMatchers: string[];
@@ -1221,11 +1268,29 @@ export class Task implements vscode.Task {
private _group: TaskGroup;
private _presentationOptions: vscode.TaskPresentationOptions;
constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]) {
constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]);
constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]);
constructor(definition: vscode.TaskDefinition, arg2: string | (vscode.TaskScope.Global | vscode.TaskScope.Workspace) | vscode.WorkspaceFolder, arg3: any, arg4?: any, arg5?: any, arg6?: any) {
this.definition = definition;
this.name = name;
this.source = source;
this.execution = execution;
let problemMatchers: string | string[];
if (typeof arg2 === 'string') {
this.name = arg2;
this.source = arg3;
this.execution = arg4;
problemMatchers = arg5;
} else if (arg2 === TaskScope.Global || arg2 === TaskScope.Workspace) {
this.target = arg2;
this.name = arg3;
this.source = arg4;
this.execution = arg5;
problemMatchers = arg6;
} else {
this.target = arg2;
this.name = arg3;
this.source = arg4;
this.execution = arg5;
problemMatchers = arg6;
}
if (typeof problemMatchers === 'string') {
this._problemMatchers = [problemMatchers];
this._hasDefinedMatchers = true;
@@ -1260,6 +1325,14 @@ export class Task implements vscode.Task {
return this._definitionKey;
}
get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder {
return this._scope;
}
set target(value: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder) {
this._scope = value;
}
get name(): string {
return this._name;
}
@@ -1383,3 +1456,23 @@ export enum ConfigurationTarget {
WorkspaceFolder = 3
}
export class RelativePattern implements IRelativePattern {
base: string;
pattern: string;
constructor(base: vscode.WorkspaceFolder | string, pattern: string) {
if (typeof base !== 'string') {
if (!base || !URI.isUri(base.uri)) {
throw illegalArgument('base');
}
}
if (typeof pattern !== 'string') {
throw illegalArgument('pattern');
}
this.base = typeof base === 'string' ? base : base.uri.fsPath;
this.pattern = pattern;
}
}

View File

@@ -8,19 +8,13 @@ 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 { relative, basename } from 'path';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { IResourceEdit } from 'vs/editor/common/services/bulkEdit';
import { TPromise } from 'vs/base/common/winjs.base';
import { fromRange, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
import { relative, dirname } from 'path';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol';
import * as vscode from 'vscode';
import { compare } from 'vs/base/common/strings';
import { asWinJsPromise } from 'vs/base/common/async';
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
import { TrieMap } from 'vs/base/common/map';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Progress } from 'vs/platform/progress/common/progress';
import { TernarySearchTree } from 'vs/base/common/map';
import { IRelativePattern } from 'vs/base/common/glob';
class Workspace2 extends Workspace {
@@ -28,42 +22,30 @@ class Workspace2 extends Workspace {
return data ? new Workspace2(data) : null;
}
private readonly _folder: vscode.WorkspaceFolder[] = [];
private readonly _structure = new TrieMap<vscode.WorkspaceFolder>(s => s.split('/'));
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
private constructor(data: IWorkspaceData) {
super(data.id, data.name, data.roots);
super(data.id, data.name, data.folders.map(folder => new WorkspaceFolder(folder)));
// setup the workspace folder data structure
this.roots.forEach((uri, index) => {
const folder = {
name: basename(uri.fsPath),
uri,
index
};
this._folder.push(folder);
this._structure.insert(folder.uri.toString(), folder);
this.folders.forEach(({ name, uri, index }) => {
const workspaceFolder = { name, uri, index };
this._workspaceFolders.push(workspaceFolder);
this._structure.set(workspaceFolder.uri.toString(), workspaceFolder);
});
}
get folders(): vscode.WorkspaceFolder[] {
return this._folder.slice(0);
get workspaceFolders(): vscode.WorkspaceFolder[] {
return this._workspaceFolders.slice(0);
}
getWorkspaceFolder(uri: URI): vscode.WorkspaceFolder {
let str = uri.toString();
let folder = this._structure.lookUp(str);
if (folder) {
// `uri` is a workspace folder so we
let parts = str.split('/');
while (parts.length) {
if (parts.pop()) {
break;
}
}
str = parts.join('/');
getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder {
if (resolveParent && this._structure.get(uri.toString())) {
// `uri` is a workspace folder so we check for its parent
uri = uri.with({ path: dirname(uri.path) });
}
return this._structure.findSubstr(str);
return this._structure.findSubstr(uri.toString());
}
}
@@ -92,15 +74,15 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
if (!this._workspace) {
return undefined;
} else {
return this._workspace.folders.slice(0);
return this._workspace.workspaceFolders.slice(0);
}
}
getWorkspaceFolder(uri: vscode.Uri): vscode.WorkspaceFolder {
getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder {
if (!this._workspace) {
return undefined;
}
return this._workspace.getWorkspaceFolder(<URI>uri);
return this._workspace.getWorkspaceFolder(uri, resolveParent);
}
getPath(): string {
@@ -110,11 +92,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
if (!this._workspace) {
return undefined;
}
const { roots } = this._workspace;
if (roots.length === 0) {
const { folders } = this._workspace;
if (folders.length === 0) {
return undefined;
}
return roots[0].fsPath;
return folders[0].uri.fsPath;
}
getRelativePath(pathOrUri: string | vscode.Uri, includeWorkspace?: boolean): string {
@@ -130,24 +112,24 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
return path;
}
const folder = this.getWorkspaceFolder(typeof pathOrUri === 'string'
? URI.file(pathOrUri)
: pathOrUri
const folder = this.getWorkspaceFolder(
typeof pathOrUri === 'string' ? URI.file(pathOrUri) : pathOrUri,
true
);
if (!folder) {
return normalize(path);
return path;
}
if (typeof includeWorkspace === 'undefined') {
includeWorkspace = this.workspace.roots.length > 1;
includeWorkspace = this.workspace.folders.length > 1;
}
let result = relative(folder.uri.fsPath, path);
if (includeWorkspace) {
result = `${folder.name}/${result}`;
}
return normalize(result);
return normalize(result, true);
}
$acceptWorkspaceData(data: IWorkspaceData): void {
@@ -155,13 +137,12 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
// 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.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
const oldRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
this._workspace = Workspace2.fromData(data);
const newRoots = this._workspace ? this._workspace.folders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
const newRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder);
// {{SQL CARBON EDIT}} - fix build break Argument of type 'Readonly<...
this._onDidChangeWorkspace.fire({
added: added,
@@ -175,7 +156,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
// --- search ---
findFiles(include: string, exclude: string, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
findFiles(include: string | IRelativePattern, exclude: string | IRelativePattern, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
const requestId = ExtHostWorkspace._requestIdPool++;
const result = this._proxy.$startSearch(include, exclude, maxResults, requestId);
if (token) {
@@ -187,73 +168,4 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
saveAll(includeUntitled?: boolean): Thenable<boolean> {
return this._proxy.$saveAll(includeUntitled);
}
appyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
let resourceEdits: IResourceEdit[] = [];
let entries = edit.entries();
for (let entry of entries) {
let [uri, edits] = entry;
for (let edit of edits) {
resourceEdits.push({
resource: <URI>uri,
newText: edit.newText,
newEol: EndOfLine.from(edit.newEol),
range: edit.range && fromRange(edit.range)
});
}
}
return this._proxy.$applyWorkspaceEdit(resourceEdits);
}
// --- EXPERIMENT: workspace resolver
private _handlePool = 0;
private readonly _fsProvider = new Map<number, vscode.FileSystemProvider>();
private readonly _searchSession = new Map<number, CancellationTokenSource>();
registerFileSystemProvider(authority: string, provider: vscode.FileSystemProvider): vscode.Disposable {
const handle = ++this._handlePool;
this._fsProvider.set(handle, provider);
const reg = provider.onDidChange(e => this._proxy.$onFileSystemChange(handle, <URI>e));
this._proxy.$registerFileSystemProvider(handle, authority);
return new Disposable(() => {
this._fsProvider.delete(handle);
reg.dispose();
});
}
$resolveFile(handle: number, resource: URI): TPromise<string> {
const provider = this._fsProvider.get(handle);
return asWinJsPromise(token => provider.resolveContents(resource));
}
$storeFile(handle: number, resource: URI, content: string): TPromise<any> {
const provider = this._fsProvider.get(handle);
return asWinJsPromise(token => provider.writeContents(resource, content));
}
$startSearch(handle: number, session: number, query: string): void {
const provider = this._fsProvider.get(handle);
const source = new CancellationTokenSource();
const progress = new Progress<any>(chunk => this._proxy.$updateSearchSession(session, chunk));
this._searchSession.set(session, source);
TPromise.wrap(provider.findFiles(query, progress, source.token)).then(() => {
this._proxy.$finishSearchSession(session);
}, err => {
this._proxy.$finishSearchSession(session, err);
});
}
$cancelSearch(handle: number, session: number): void {
if (this._searchSession.has(session)) {
this._searchSession.get(session).cancel();
this._searchSession.delete(session);
}
}
}