Merge VS Code 1.21 source code (#1067)

* Initial VS Code 1.21 file copy with patches

* A few more merges

* Post npm install

* Fix batch of build breaks

* Fix more build breaks

* Fix more build errors

* Fix more build breaks

* Runtime fixes 1

* Get connection dialog working with some todos

* Fix a few packaging issues

* Copy several node_modules to package build to fix loader issues

* Fix breaks from master

* A few more fixes

* Make tests pass

* First pass of license header updates

* Second pass of license header updates

* Fix restore dialog issues

* Remove add additional themes menu items

* fix select box issues where the list doesn't show up

* formatting

* Fix editor dispose issue

* Copy over node modules to correct location on all platforms
This commit is contained in:
Karl Burtram
2018-04-04 15:27:51 -07:00
committed by GitHub
parent 5fba3e31b4
commit dafb780987
9412 changed files with 141255 additions and 98813 deletions

View File

@@ -40,38 +40,45 @@ import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import URI from 'vs/base/common/uri';
import Severity from 'vs/base/common/severity';
import EditorCommon = require('vs/editor/common/editorCommon');
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { TPromise } from 'vs/base/common/winjs.base';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import * as vscode from 'vscode';
import * as paths from 'vs/base/common/paths';
import { MainContext, ExtHostContext, IInitData } from './extHost.protocol';
import { MainContext, ExtHostContext, IInitData, IExtHostContext } from './extHost.protocol';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
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 { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs';
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';
import { toGlobPattern, toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { OverviewRulerLane } from 'vs/editor/common/model';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';
export interface IExtensionApiFactory {
(extension: IExtensionDescription): typeof vscode;
}
export function checkProposedApiEnabled(extension: IExtensionDescription): void {
if (!extension.enableProposedApi) {
throwProposedApiError(extension);
}
}
function throwProposedApiError(extension: IExtensionDescription): never {
throw new Error(`[${extension.id}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.id}`);
}
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
if (extension.enableProposedApi) {
return fn;
} else {
return <any>(() => {
throw new Error(`[${extension.id}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${extension.id}`);
});
return <any>throwProposedApiError;
}
}
@@ -80,49 +87,51 @@ function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
*/
export function createApiFactory(
initData: IInitData,
threadService: ExtHostThreadService,
rpcProtocol: IExtHostContext,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
extensionService: ExtHostExtensionService,
logService: ILogService
extHostLogService: ExtHostLogService
): IExtensionApiFactory {
// Addressable instances
const extHostHeapService = threadService.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
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.MainThreadEditors)));
const extHostEditors = threadService.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(threadService, extHostDocumentsAndEditors));
const extHostCommands = threadService.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(threadService, extHostHeapService, logService));
const extHostTreeViews = threadService.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(threadService.get(MainContext.MainThreadTreeViews), extHostCommands));
threadService.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol));
const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol, extHostWebviews));
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors));
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors)));
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostHeapService, extHostLogService));
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands));
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
// {{SQL CARBON EDIT}}
//const extHostDebugService = threadService.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace));
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, extHostWorkspace, extHostCommands));
const extHostTerminalService = threadService.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(threadService));
const extHostSCM = threadService.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(threadService, extHostCommands, logService));
const extHostTask = threadService.set(ExtHostContext.ExtHostTask, new ExtHostTask(threadService, extHostWorkspace));
const extHostWindow = threadService.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(threadService));
threadService.set(ExtHostContext.ExtHostExtensionService, extensionService);
//const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(threadService, extHostWorkspace));
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService());
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace));
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
// Check that no named customers are missing
const expected: ProxyIdentifier<any>[] = Object.keys(ExtHostContext).map((key) => ExtHostContext[key]);
threadService.assertRegistered(expected);
rpcProtocol.assertRegistered(expected);
// Other instances
const extHostMessageService = new ExtHostMessageService(threadService);
const extHostDialogs = new ExtHostDialogs(threadService);
const extHostStatusBar = new ExtHostStatusBar(threadService);
const extHostProgress = new ExtHostProgress(threadService.get(MainContext.MainThreadProgress));
const extHostOutputService = new ExtHostOutputService(threadService);
const extHostLanguages = new ExtHostLanguages(threadService);
const extHostMessageService = new ExtHostMessageService(rpcProtocol);
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
const extHostProgress = new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress));
const extHostOutputService = new ExtHostOutputService(rpcProtocol);
const extHostLanguages = new ExtHostLanguages(rpcProtocol);
// Register API-ish commands
ExtHostApiCommands.register(extHostCommands);
@@ -232,61 +241,64 @@ export function createApiFactory(
return score(toLanguageSelector(selector), document.uri, document.languageId);
},
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
return languageFeatures.registerCodeActionProvider(selector, provider);
return extHostLanguageFeatures.registerCodeActionProvider(selector, provider);
},
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return languageFeatures.registerCodeLensProvider(selector, provider);
return extHostLanguageFeatures.registerCodeLensProvider(selector, provider);
},
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
return languageFeatures.registerDefinitionProvider(selector, provider);
return extHostLanguageFeatures.registerDefinitionProvider(selector, provider);
},
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
return languageFeatures.registerImplementationProvider(selector, provider);
return extHostLanguageFeatures.registerImplementationProvider(selector, provider);
},
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
return languageFeatures.registerTypeDefinitionProvider(selector, provider);
return extHostLanguageFeatures.registerTypeDefinitionProvider(selector, provider);
},
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
return languageFeatures.registerHoverProvider(selector, provider, extension.id);
return extHostLanguageFeatures.registerHoverProvider(selector, provider, extension.id);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return languageFeatures.registerDocumentHighlightProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentHighlightProvider(selector, provider);
},
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
return languageFeatures.registerReferenceProvider(selector, provider);
return extHostLanguageFeatures.registerReferenceProvider(selector, provider);
},
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
return languageFeatures.registerRenameProvider(selector, provider);
return extHostLanguageFeatures.registerRenameProvider(selector, provider, extension.enableProposedApi);
},
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
return languageFeatures.registerDocumentSymbolProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentSymbolProvider(selector, provider);
},
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
return languageFeatures.registerWorkspaceSymbolProvider(provider);
return extHostLanguageFeatures.registerWorkspaceSymbolProvider(provider);
},
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
return languageFeatures.registerDocumentFormattingEditProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(selector, provider);
},
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
return languageFeatures.registerDocumentRangeFormattingEditProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(selector, provider);
},
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
},
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, ...triggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters);
return extHostLanguageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters);
},
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters);
return extHostLanguageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters);
},
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
return languageFeatures.registerDocumentLinkProvider(selector, provider);
return extHostLanguageFeatures.registerDocumentLinkProvider(selector, provider);
},
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
return languageFeatures.registerColorProvider(selector, provider);
return extHostLanguageFeatures.registerColorProvider(selector, provider);
},
registerFoldingProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable => {
return extHostLanguageFeatures.registerFoldingProvider(selector, provider);
}),
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
return languageFeatures.setLanguageConfiguration(language, configuration);
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
}
};
@@ -324,6 +336,9 @@ export function createApiFactory(
onDidChangeTextEditorOptions(listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables);
},
onDidChangeTextEditorVisibleRanges: proposedApiFunction(extension, (listener: (e: vscode.TextEditorVisibleRangesChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
return extHostEditors.onDidChangeTextEditorVisibleRanges(listener, thisArgs, disposables);
}),
onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) {
return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables);
},
@@ -382,8 +397,8 @@ export function createApiFactory(
}
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider);
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.TreeView<any> {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, (fn) => proposedApiFunction(extension, fn));
},
// proposed API
sampleFunction: proposedApiFunction(extension, () => {
@@ -391,6 +406,12 @@ export function createApiFactory(
}),
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => {
return extHostDecorations.registerDecorationProvider(provider, extension.id);
}),
createWebview: proposedApiFunction(extension, (uri: vscode.Uri, title: string, column: vscode.ViewColumn, options: vscode.WebviewOptions) => {
return extHostWebviews.createWebview(uri, title, column, options);
}),
onDidChangeActiveEditor: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
return extHostDocumentsAndEditors.onDidChangeActiveEditor(listener, thisArg, disposables);
})
};
@@ -414,6 +435,9 @@ export function createApiFactory(
set name(value) {
throw errors.readonly();
},
updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => {
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
},
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
},
@@ -421,7 +445,7 @@ export function createApiFactory(
return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
},
findFiles: (include, exclude, maxResults?, token?) => {
return extHostWorkspace.findFiles(toGlobPattern(include), toGlobPattern(exclude), maxResults, token);
return extHostWorkspace.findFiles(toGlobPattern(include), toGlobPattern(exclude), maxResults, extension.id, token);
},
saveAll: (includeUntitled?) => {
return extHostWorkspace.saveAll(includeUntitled);
@@ -472,7 +496,7 @@ export function createApiFactory(
return extHostDocuments.onDidSaveDocument(listener, thisArgs, disposables);
},
onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocumentSaveParticipant.onWillSaveTextDocumentEvent(listener, thisArgs, disposables);
return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables);
},
onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
return extHostConfiguration.onDidChangeConfiguration(listener, thisArgs, disposables);
@@ -521,6 +545,7 @@ export function createApiFactory(
Breakpoint: extHostTypes.Breakpoint,
CancellationTokenSource: CancellationTokenSource,
CodeAction: extHostTypes.CodeAction,
CodeActionKind: extHostTypes.CodeActionKind,
CodeLens: extHostTypes.CodeLens,
Color: extHostTypes.Color,
ColorPresentation: extHostTypes.ColorPresentation,
@@ -530,6 +555,8 @@ export function createApiFactory(
CompletionItemKind: extHostTypes.CompletionItemKind,
CompletionList: extHostTypes.CompletionList,
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
// {{SQL CARBON EDIT}}
// DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
Diagnostic: extHostTypes.Diagnostic,
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
Disposable: extHostTypes.Disposable,
@@ -541,8 +568,9 @@ export function createApiFactory(
Hover: extHostTypes.Hover,
IndentAction: languageConfiguration.IndentAction,
Location: extHostTypes.Location,
LogLevel: extHostTypes.LogLevel,
MarkdownString: extHostTypes.MarkdownString,
OverviewRulerLane: EditorCommon.OverviewRulerLane,
OverviewRulerLane: OverviewRulerLane,
ParameterInformation: extHostTypes.ParameterInformation,
Position: extHostTypes.Position,
Range: extHostTypes.Range,
@@ -554,6 +582,7 @@ export function createApiFactory(
StatusBarAlignment: extHostTypes.StatusBarAlignment,
SymbolInformation: extHostTypes.SymbolInformation,
SymbolKind: extHostTypes.SymbolKind,
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
TextEdit: extHostTypes.TextEdit,
TextEditorCursorStyle: TextEditorCursorStyle,
@@ -566,6 +595,7 @@ export function createApiFactory(
WorkspaceEdit: extHostTypes.WorkspaceEdit,
ProgressLocation: extHostTypes.ProgressLocation,
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
ThemeIcon: extHostTypes.ThemeIcon,
TreeItem: extHostTypes.TreeItem,
ThemeColor: extHostTypes.ThemeColor,
// functions
@@ -579,9 +609,11 @@ export function createApiFactory(
ConfigurationTarget: extHostTypes.ConfigurationTarget,
RelativePattern: extHostTypes.RelativePattern,
// TODO@JOH,remote
FileChangeType: <any>FileChangeType,
FileType: <any>FileType
FileChangeType: extHostTypes.FileChangeType,
FileType: extHostTypes.FileType,
FoldingRangeList: extHostTypes.FoldingRangeList,
FoldingRange: extHostTypes.FoldingRange,
FoldingRangeType: extHostTypes.FoldingRangeType
};
};
}

View File

@@ -4,21 +4,17 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {
createMainContextProxyIdentifier as createMainId,
createExtHostContextProxyIdentifier as createExtId,
ProxyIdentifier
} from 'vs/workbench/services/thread/common/threadService';
import { createMainContextProxyIdentifier as createMainId, createExtHostContextProxyIdentifier as createExtId, ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { IMarkerData } from 'vs/platform/markers/common/markers';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
@@ -26,9 +22,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 { ITextSource } from 'vs/editor/common/model/textSource';
import { IConfigurationData, ConfigurationTarget, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IConfig, IAdapterExecutable } from 'vs/workbench/parts/debug/common/debug';
import { IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
@@ -37,7 +33,7 @@ import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/ext
import { TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorModel';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
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';
@@ -46,10 +42,13 @@ 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 { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
import { IStat, IFileChange } from 'vs/platform/files/common/files';
import { IStat, FileChangeType } from 'vs/platform/files/common/files';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { CommentRule, CharacterPair, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { ILineMatch, IPatternInfo } from 'vs/platform/search/common/search';
import { LogLevel } from 'vs/platform/log/common/log';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -66,7 +65,8 @@ export interface IEnvironment {
export interface IWorkspaceData {
id: string;
name: string;
folders: IWorkspaceFolderData[];
folders: { uri: UriComponents, name: string, index: number }[];
configuration?: UriComponents;
}
export interface IInitData {
@@ -79,10 +79,11 @@ export interface IInitData {
windowId: number;
args: ParsedArgs;
execPath: string;
logLevel: LogLevel;
}
export interface IConfigurationInitData extends IConfigurationData {
configurationScopes: ConfigurationScope[];
configurationScopes: { [key: string]: ConfigurationScope };
}
export interface IWorkspaceConfigurationChangeEventData {
@@ -90,46 +91,33 @@ export interface IWorkspaceConfigurationChangeEventData {
changedConfigurationByResource: { [folder: string]: IConfigurationModel };
}
export interface IExtHostContext {
/**
* Returns a proxy to an object addressable/named in the extension host process.
*/
get<T>(identifier: ProxyIdentifier<T>): T;
/**
* Register manually created instance.
*/
set<T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R;
export interface IExtHostContext extends IRPCProtocol {
}
export interface IMainContext {
/**
* Returns a proxy to an object addressable/named in the main/renderer process.
*/
get<T>(identifier: ProxyIdentifier<T>): T;
export interface IMainContext extends IRPCProtocol {
}
// --- main thread
export interface MainThreadCommandsShape extends IDisposable {
$registerCommand(id: string): TPromise<any>;
$unregisterCommand(id: string): TPromise<any>;
$registerCommand(id: string): void;
$unregisterCommand(id: string): void;
$executeCommand<T>(id: string, args: any[]): Thenable<T>;
$getCommands(): Thenable<string[]>;
}
export interface MainThreadConfigurationShape extends IDisposable {
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise<void>;
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: URI): TPromise<void>;
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: UriComponents): TPromise<void>;
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: UriComponents): TPromise<void>;
}
export interface MainThreadDiagnosticsShape extends IDisposable {
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any>;
$clear(owner: string): TPromise<any>;
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void;
$clear(owner: string): void;
}
export interface MainThreadDialogOpenOptions {
defaultUri?: URI;
defaultUri?: UriComponents;
openLabel?: string;
canSelectFiles?: boolean;
canSelectFolders?: boolean;
@@ -138,37 +126,32 @@ export interface MainThreadDialogOpenOptions {
}
export interface MainThreadDialogSaveOptions {
defaultUri?: URI;
defaultUri?: UriComponents;
saveLabel?: string;
filters?: { [name: string]: string[] };
}
export interface MainThreadDiaglogsShape extends IDisposable {
$showOpenDialog(options: MainThreadDialogOpenOptions): TPromise<string[]>;
$showSaveDialog(options: MainThreadDialogSaveOptions): TPromise<string>;
$showOpenDialog(options: MainThreadDialogOpenOptions): Thenable<string[]>;
$showSaveDialog(options: MainThreadDialogSaveOptions): Thenable<string>;
}
export interface MainThreadDecorationsShape extends IDisposable {
$registerDecorationProvider(handle: number, label: string): void;
$unregisterDecorationProvider(handle: number): void;
$onDidChange(handle: number, resources: URI[]): void;
$onDidChange(handle: number, resources: UriComponents[]): void;
}
export interface MainThreadDocumentContentProvidersShape extends IDisposable {
$registerTextContentProvider(handle: number, scheme: string): void;
$unregisterTextContentProvider(handle: number): void;
$onVirtualDocumentChange(uri: URI, value: ITextSource): void;
$onVirtualDocumentChange(uri: UriComponents, value: string): void;
}
export interface MainThreadDocumentsShape extends IDisposable {
$tryCreateDocument(options?: { language?: string; content?: string; }): TPromise<any>;
$tryOpenDocument(uri: URI): TPromise<any>;
$trySaveDocument(uri: URI): TPromise<boolean>;
}
export interface ISelectionChangeEvent {
selections: Selection[];
source?: string;
$tryCreateDocument(options?: { language?: string; content?: string; }): TPromise<UriComponents>;
$tryOpenDocument(uri: UriComponents): TPromise<void>;
$trySaveDocument(uri: UriComponents): TPromise<boolean>;
}
export interface ITextEditorConfigurationUpdate {
@@ -201,8 +184,6 @@ export interface IApplyEditsOptions extends IUndoStopOptions {
setEndOfLine: EndOfLine;
}
export interface ITextDocumentShowOptions {
position?: EditorPosition;
preserveFocus?: boolean;
@@ -210,64 +191,95 @@ 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>;
export interface MainThreadTextEditorsShape extends IDisposable {
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string>;
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
$removeTextEditorDecorationType(key: string): void;
$tryShowEditor(id: string, position: EditorPosition): TPromise<void>;
$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>;
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<void>;
$trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): TPromise<void>;
$trySetDecorationsFast(id: string, key: string, ranges: number[]): TPromise<void>;
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void>;
$trySetSelections(id: string, selections: ISelection[]): TPromise<void>;
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean>;
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto): TPromise<boolean>;
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise<boolean>;
$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]>;
}
export interface MainThreadTreeViewsShape extends IDisposable {
$registerView(treeViewId: string): void;
$registerTreeViewDataProvider(treeViewId: string): void;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): void;
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise<void>;
}
export interface MainThreadErrorsShape extends IDisposable {
$onUnexpectedError(err: any | SerializedError): void;
}
export interface ISerializedRegExp {
pattern: string;
flags?: string;
}
export interface ISerializedIndentationRule {
decreaseIndentPattern: ISerializedRegExp;
increaseIndentPattern: ISerializedRegExp;
indentNextLinePattern?: ISerializedRegExp;
unIndentedLinePattern?: ISerializedRegExp;
}
export interface ISerializedOnEnterRule {
beforeText: ISerializedRegExp;
afterText?: ISerializedRegExp;
action: EnterAction;
}
export interface ISerializedLanguageConfiguration {
comments?: CommentRule;
brackets?: CharacterPair[];
wordPattern?: ISerializedRegExp;
indentationRules?: ISerializedIndentationRule;
onEnterRules?: ISerializedOnEnterRule[];
__electricCharacterSupport?: {
brackets?: any;
docComment?: {
scope: string;
open: string;
lineStart: string;
close?: string;
};
};
__characterPairSupport?: {
autoClosingPairs: {
open: string;
close: string;
notIn?: string[];
}[];
};
}
export interface MainThreadLanguageFeaturesShape extends IDisposable {
$unregister(handle: number): TPromise<any>;
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise<any>;
$emitCodeLensEvent(eventHandle: number, event?: any): TPromise<any>;
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$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[], supportsResolveDetails: boolean): TPromise<any>;
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise<any>;
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any>;
$setLanguageConfiguration(handle: number, languageId: string, configuration: vscode.LanguageConfiguration): TPromise<any>;
$unregister(handle: number): void;
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): void;
$emitCodeLensEvent(eventHandle: number, event?: any): void;
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): void;
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): void;
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): void;
$registerNavigateTypeSupport(handle: number): void;
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector, supportsResolveInitialValues: boolean): void;
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): void;
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): void;
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): void;
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): void;
$registerFoldingProvider(handle: number, selector: vscode.DocumentSelector): void;
$setLanguageConfiguration(handle: number, languageId: string, configuration: ISerializedLanguageConfiguration): void;
}
export interface MainThreadLanguagesShape extends IDisposable {
@@ -299,7 +311,7 @@ export interface MainThreadProgressShape extends IDisposable {
}
export interface MainThreadTerminalServiceShape extends IDisposable {
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number>;
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: 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;
@@ -323,33 +335,56 @@ export interface MainThreadStatusBarShape extends IDisposable {
export interface MainThreadStorageShape extends IDisposable {
$getValue<T>(shared: boolean, key: string): TPromise<T>;
$setValue(shared: boolean, key: string, value: any): TPromise<any>;
$setValue(shared: boolean, key: string, value: any): TPromise<void>;
}
export interface MainThreadTelemetryShape extends IDisposable {
$publicLog(eventName: string, data?: any): void;
}
export type WebviewHandle = number;
export interface MainThreadWebviewsShape extends IDisposable {
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: EditorPosition, options: vscode.WebviewOptions): void;
$disposeWebview(handle: WebviewHandle): void;
$show(handle: WebviewHandle, column: EditorPosition): void;
$setTitle(handle: WebviewHandle, value: string): void;
$setHtml(handle: WebviewHandle, value: string): void;
$sendMessage(handle: WebviewHandle, value: any): Thenable<boolean>;
}
export interface ExtHostWebviewsShape {
$onMessage(handle: WebviewHandle, message: any): void;
$onDidChangeActiveWeview(handle: WebviewHandle | undefined): void;
$onDidDisposeWeview(handle: WebviewHandle): Thenable<void>;
$onDidChangePosition(handle: WebviewHandle, newPosition: EditorPosition): void;
}
export interface MainThreadWorkspaceShape extends IDisposable {
$startSearch(includePattern: string, includeFolder: string, excludePattern: string, maxResults: number, requestId: number): Thenable<URI[]>;
$startSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<UriComponents[]>;
$cancelSearch(requestId: number): Thenable<boolean>;
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void>;
}
export interface IFileChangeDto {
resource: UriComponents;
type: FileChangeType;
}
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;
$onDidAddFileSystemRoot(root: UriComponents): void;
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
$reportFileChunk(handle: number, session: number, chunk: number[] | null): void;
$handleSearchProgress(handle: number, session: number, resource: URI): void;
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void;
}
export interface MainThreadTaskShape extends IDisposable {
$registerTaskProvider(handle: number): TPromise<any>;
$unregisterTaskProvider(handle: number): TPromise<any>;
$registerTaskProvider(handle: number): TPromise<void>;
$unregisterTaskProvider(handle: number): TPromise<void>;
}
export interface MainThreadExtensionServiceShape extends IDisposable {
@@ -374,7 +409,7 @@ export interface SCMGroupFeatures {
export type SCMRawResource = [
number /*handle*/,
string /*resourceUri*/,
UriComponents /*resourceUri*/,
string[] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
@@ -397,7 +432,7 @@ export type SCMRawResourceSplices = [
];
export interface MainThreadSCMShape extends IDisposable {
$registerSourceControl(handle: number, id: string, label: string, rootUri: string | undefined): void;
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void;
$updateSourceControl(handle: number, features: SCMProviderFeatures): void;
$unregisterSourceControl(handle: number): void;
@@ -410,6 +445,7 @@ export interface MainThreadSCMShape extends IDisposable {
$setInputBoxValue(sourceControlHandle: number, value: string): void;
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
}
@@ -418,12 +454,14 @@ export interface MainThreadSCMShape extends IDisposable {
export type DebugSessionUUID = string;
export interface MainThreadDebugServiceShape extends IDisposable {
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, handle: number): TPromise<any>;
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<any>;
$unregisterDebugConfigurationProvider(handle: number): TPromise<any>;
$startDebugging(folder: URI | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean>;
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean>;
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): TPromise<any>;
$appendDebugConsole(value: string): TPromise<any>;
$startBreakpointEvents(): TPromise<any>;
$registerBreakpoints(breakpoints: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise<void>;
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise<void>;
}
// {{SQL CARBON EDIT}}
*/
@@ -436,7 +474,7 @@ export interface MainThreadWindowShape extends IDisposable {
export interface ExtHostCommandsShape {
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T>;
$getContributedCommandHandlerDescriptions(): TPromise<{ [id: string]: string | ICommandHandlerDescription }>;
$getContributedCommandHandlerDescriptions(): Thenable<{ [id: string]: string | ICommandHandlerDescription }>;
}
export interface ExtHostConfigurationShape {
@@ -448,11 +486,11 @@ export interface ExtHostDiagnosticsShape {
}
export interface ExtHostDocumentContentProvidersShape {
$provideTextDocumentContent(handle: number, uri: URI): TPromise<string>;
$provideTextDocumentContent(handle: number, uri: UriComponents): TPromise<string>;
}
export interface IModelAddedData {
url: URI;
uri: UriComponents;
versionId: number;
lines: string[];
EOL: string;
@@ -460,34 +498,44 @@ export interface IModelAddedData {
isDirty: boolean;
}
export interface ExtHostDocumentsShape {
$acceptModelModeChanged(strURL: string, oldModeId: string, newModeId: string): void;
$acceptModelSaved(strURL: string): void;
$acceptDirtyStateChanged(strURL: string, isDirty: boolean): void;
$acceptModelChanged(strURL: string, e: IModelChangedEvent, isDirty: boolean): void;
$acceptModelModeChanged(strURL: UriComponents, oldModeId: string, newModeId: string): void;
$acceptModelSaved(strURL: UriComponents): void;
$acceptDirtyStateChanged(strURL: UriComponents, isDirty: boolean): void;
$acceptModelChanged(strURL: UriComponents, e: IModelChangedEvent, isDirty: boolean): void;
}
export interface ExtHostDocumentSaveParticipantShape {
$participateInSave(resource: URI, reason: SaveReason): TPromise<boolean[]>;
$participateInSave(resource: UriComponents, reason: SaveReason): Thenable<boolean[]>;
}
export interface ITextEditorAddData {
id: string;
document: URI;
documentUri: UriComponents;
options: IResolvedTextEditorConfiguration;
selections: ISelection[];
visibleRanges: IRange[];
editorPosition: EditorPosition;
}
export interface ITextEditorPositionData {
[id: string]: EditorPosition;
}
export interface IEditorPropertiesChangeData {
options: IResolvedTextEditorConfiguration | null;
selections: ISelectionChangeEvent | null;
visibleRanges: IRange[] | null;
}
export interface ISelectionChangeEvent {
selections: Selection[];
source?: string;
}
export interface ExtHostEditorsShape {
$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void;
$acceptSelectionsChanged(id: string, event: ISelectionChangeEvent): void;
$acceptEditorPropertiesChanged(id: string, props: IEditorPropertiesChangeData): void;
$acceptEditorPositionData(data: ITextEditorPositionData): void;
}
export interface IDocumentsAndEditorsDelta {
removedDocuments?: string[];
removedDocuments?: UriComponents[];
addedDocuments?: IModelAddedData[];
removedEditors?: string[];
addedEditors?: ITextEditorAddData[];
@@ -499,8 +547,7 @@ export interface ExtHostDocumentsAndEditorsShape {
}
export interface ExtHostTreeViewsShape {
$getElements(treeViewId: string): TPromise<ITreeItem[]>;
$getChildren(treeViewId: string, treeItemHandle: string): TPromise<ITreeItem[]>;
$getChildren(treeViewId: string, treeItemHandle?: string): TPromise<ITreeItem[]>;
}
export interface ExtHostWorkspaceShape {
@@ -508,16 +555,17 @@ export interface ExtHostWorkspaceShape {
}
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>;
$utimes(handle: number, resource: UriComponents, mtime: number, atime: number): TPromise<IStat>;
$stat(handle: number, resource: UriComponents): TPromise<IStat>;
$read(handle: number, session: number, offset: number, count: number, resource: UriComponents): TPromise<number>;
$write(handle: number, resource: UriComponents, content: number[]): TPromise<void>;
$unlink(handle: number, resource: UriComponents): TPromise<void>;
$move(handle: number, resource: UriComponents, target: UriComponents): TPromise<IStat>;
$mkdir(handle: number, resource: UriComponents): TPromise<IStat>;
$readdir(handle: number, resource: UriComponents): TPromise<[UriComponents, IStat][]>;
$rmdir(handle: number, resource: UriComponents): TPromise<void>;
$findFiles(handle: number, session: number, query: string): TPromise<void>;
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void>;
}
export interface ExtHostExtensionServiceShape {
@@ -525,9 +573,9 @@ export interface ExtHostExtensionServiceShape {
}
export interface FileSystemEvents {
created: URI[];
changed: URI[];
deleted: URI[];
created: UriComponents[];
changed: UriComponents[];
deleted: UriComponents[];
}
export interface ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents): void;
@@ -556,58 +604,109 @@ export interface IRawColorInfo {
range: IRange;
}
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++;
export class IdObject {
_id?: number;
private static _n = 0;
static mixin<T extends object>(object: T): T & IdObject {
(<any>object)._id = IdObject._n++;
return <any>object;
}
}
export type IWorkspaceSymbol = IdObject & modes.SymbolInformation;
export interface IWorkspaceSymbols extends IdObject { symbols: IWorkspaceSymbol[]; }
export interface SuggestionDto extends modes.ISuggestion {
_id: number;
_parentId: number;
}
export interface SuggestResultDto extends IdObject {
suggestions: SuggestionDto[];
incomplete?: boolean;
}
export interface LocationDto {
uri: UriComponents;
range: IRange;
}
export interface SymbolInformationDto extends IdObject {
name: string;
containerName?: string;
kind: modes.SymbolKind;
location: LocationDto;
}
export interface WorkspaceSymbolsDto extends IdObject {
symbols: SymbolInformationDto[];
}
export interface ResourceFileEditDto {
oldUri: UriComponents;
newUri: UriComponents;
}
export interface ResourceTextEditDto {
resource: UriComponents;
modelVersionId?: number;
edits: modes.TextEdit[];
}
export interface WorkspaceEditDto {
edits: (ResourceFileEditDto | ResourceTextEditDto)[];
// todo@joh reject should go into rename
rejectReason?: string;
}
export function reviveWorkspaceEditDto(data: WorkspaceEditDto): modes.WorkspaceEdit {
if (data && data.edits) {
for (const edit of data.edits) {
if (typeof (<ResourceTextEditDto>edit).resource === 'object') {
(<ResourceTextEditDto>edit).resource = URI.revive((<ResourceTextEditDto>edit).resource);
} else {
(<ResourceFileEditDto>edit).newUri = URI.revive((<ResourceFileEditDto>edit).newUri);
(<ResourceFileEditDto>edit).oldUri = URI.revive((<ResourceFileEditDto>edit).oldUri);
}
}
}
return <modes.WorkspaceEdit>data;
}
export interface CodeActionDto {
title: string;
edit?: WorkspaceEditDto;
diagnostics?: IMarkerData[];
command?: modes.Command;
kind?: string;
}
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]>;
$provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]>;
$resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol>;
$provideDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition>;
$provideImplementation(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition>;
$provideTypeDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition>;
$provideHover(handle: number, resource: URI, position: IPosition): TPromise<modes.Hover>;
$provideDocumentHighlights(handle: number, resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]>;
$provideReferences(handle: number, resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]>;
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<modes.CodeAction[]>;
$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<IWorkspaceSymbols>;
$resolveWorkspaceSymbol(handle: number, symbol: modes.SymbolInformation): TPromise<IWorkspaceSymbol>;
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<SymbolInformationDto[]>;
$provideCodeLenses(handle: number, resource: UriComponents): TPromise<modes.ICodeLensSymbol[]>;
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol>;
$provideDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<LocationDto | LocationDto[]>;
$provideImplementation(handle: number, resource: UriComponents, position: IPosition): TPromise<LocationDto | LocationDto[]>;
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<LocationDto | LocationDto[]>;
$provideHover(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Hover>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DocumentHighlight[]>;
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext): TPromise<LocationDto[]>;
$provideCodeActions(handle: number, resource: UriComponents, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]>;
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]>;
$provideWorkspaceSymbols(handle: number, search: string): TPromise<WorkspaceSymbolsDto>;
$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto>;
$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, context: modes.SuggestContext): TPromise<IExtHostSuggestResult>;
$resolveCompletionItem(handle: number, resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion>;
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<WorkspaceEditDto>;
$resolveInitialRenameValue(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.RenameInitialValue>;
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto>;
$resolveCompletionItem(handle: number, resource: UriComponents, 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[]>;
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.SignatureHelp>;
$provideDocumentLinks(handle: number, resource: UriComponents): TPromise<modes.ILink[]>;
$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[]>;
$provideDocumentColors(handle: number, resource: UriComponents): TPromise<IRawColorInfo[]>;
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]>;
$provideFoldingRanges(handle: number, resource: UriComponents): TPromise<modes.IFoldingRangeList>;
}
export interface ExtHostQuickOpenShape {
@@ -621,69 +720,95 @@ export interface ExtHostTerminalServiceShape {
}
export interface ExtHostSCMShape {
$provideOriginalResource(sourceControlHandle: number, uri: URI): TPromise<URI>;
$provideOriginalResource(sourceControlHandle: number, uri: UriComponents): TPromise<UriComponents>;
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void>;
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void>;
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): TPromise<[string, number] | undefined>;
}
export interface ExtHostTaskShape {
$provideTasks(handle: number): TPromise<TaskSet>;
}
export interface IBreakpointData {
type: 'source' | 'function';
id: string;
export interface IFunctionBreakpointDto {
type: 'function';
id?: string;
enabled: boolean;
condition?: string;
hitCondition?: string;
functionName: string;
}
export interface ISourceBreakpointData extends IBreakpointData {
export interface ISourceBreakpointDto {
type: 'source';
uri: URI;
id?: string;
enabled: boolean;
condition?: string;
hitCondition?: string;
uri: UriComponents;
line: number;
character: number;
}
export interface IFunctionBreakpointData extends IBreakpointData {
type: 'function';
functionName: string;
export interface IBreakpointsDeltaDto {
added?: (ISourceBreakpointDto | IFunctionBreakpointDto)[];
removed?: string[];
changed?: (ISourceBreakpointDto | IFunctionBreakpointDto)[];
}
export interface IBreakpointsDelta {
added?: (ISourceBreakpointData | IFunctionBreakpointData)[];
removed?: string[];
changed?: (ISourceBreakpointData | IFunctionBreakpointData)[];
export interface ISourceMultiBreakpointDto {
type: 'sourceMulti';
uri: UriComponents;
lines: {
id: string;
enabled: boolean;
condition?: string;
hitCondition?: string;
line: number;
character: number;
}[];
}
// {{SQL CARBON EDIT}}
/*
export interface ExtHostDebugServiceShape {
$resolveDebugConfiguration(handle: number, folder: URI | undefined, debugConfiguration: any): TPromise<any>;
$provideDebugConfigurations(handle: number, folder: URI | undefined): TPromise<any[]>;
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): TPromise<IConfig>;
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined): TPromise<IConfig[]>;
$debugAdapterExecutable(handle: number, folder: UriComponents | undefined): TPromise<IAdapterExecutable>;
$acceptDebugSessionStarted(id: DebugSessionUUID, type: string, name: string): void;
$acceptDebugSessionTerminated(id: DebugSessionUUID, type: string, name: string): void;
$acceptDebugSessionActiveChanged(id: DebugSessionUUID | undefined, type?: string, name?: string): void;
$acceptDebugSessionCustomEvent(id: DebugSessionUUID, type: string, name: string, event: any): void;
$acceptBreakpointsDelta(delat: IBreakpointsDelta): void;
$acceptBreakpointsDelta(delat: IBreakpointsDeltaDto): void;
}
// {{SQL CARBON EDIT}}
*/
export interface DecorationRequest {
readonly id: number;
readonly handle: number;
readonly uri: UriComponents;
}
export type DecorationData = [number, boolean, string, string, ThemeColor, string];
export type DecorationReply = { [id: number]: DecorationData };
export interface ExtHostDecorationsShape {
$providerDecorations(handle: number, uri: URI): TPromise<DecorationData>;
$provideDecorations(requests: DecorationRequest[]): TPromise<DecorationReply>;
}
export interface ExtHostWindowShape {
$onDidChangeWindowFocus(value: boolean): void;
}
export interface ExtHostLogServiceShape {
$setLevel(level: LogLevel);
}
// --- proxy identifiers
export const MainContext = {
MainThreadCommands: createMainId<MainThreadCommandsShape>('MainThreadCommands'),
MainThreadCommands: <ProxyIdentifier<MainThreadCommandsShape>>createMainId<MainThreadCommandsShape>('MainThreadCommands'),
MainThreadConfiguration: createMainId<MainThreadConfigurationShape>('MainThreadConfiguration'),
// {{SQL CARBON EDIT}}
// MainThreadDebugService: createMainId<MainThreadDebugServiceShape>('MainThreadDebugService'),
@@ -692,7 +817,7 @@ export const MainContext = {
MainThreadDialogs: createMainId<MainThreadDiaglogsShape>('MainThreadDiaglogs'),
MainThreadDocuments: createMainId<MainThreadDocumentsShape>('MainThreadDocuments'),
MainThreadDocumentContentProviders: createMainId<MainThreadDocumentContentProvidersShape>('MainThreadDocumentContentProviders'),
MainThreadEditors: createMainId<MainThreadEditorsShape>('MainThreadEditors'),
MainThreadTextEditors: createMainId<MainThreadTextEditorsShape>('MainThreadTextEditors'),
MainThreadErrors: createMainId<MainThreadErrorsShape>('MainThreadErrors'),
MainThreadTreeViews: createMainId<MainThreadTreeViewsShape>('MainThreadTreeViews'),
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
@@ -705,6 +830,7 @@ export const MainContext = {
MainThreadStorage: createMainId<MainThreadStorageShape>('MainThreadStorage'),
MainThreadTelemetry: createMainId<MainThreadTelemetryShape>('MainThreadTelemetry'),
MainThreadTerminalService: createMainId<MainThreadTerminalServiceShape>('MainThreadTerminalService'),
MainThreadWebviews: createMainId<MainThreadWebviewsShape>('MainThreadWebviews'),
MainThreadWorkspace: createMainId<MainThreadWorkspaceShape>('MainThreadWorkspace'),
MainThreadFileSystem: createMainId<MainThreadFileSystemShape>('MainThreadFileSystem'),
MainThreadExtensionService: createMainId<MainThreadExtensionServiceShape>('MainThreadExtensionService'),
@@ -732,9 +858,11 @@ export const ExtHostContext = {
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),
ExtHostExtensionService: createExtId<ExtHostExtensionServiceShape>('ExtHostExtensionService'),
ExtHostLogService: createExtId<ExtHostLogServiceShape>('ExtHostLogService'),
ExtHostTerminalService: createExtId<ExtHostTerminalServiceShape>('ExtHostTerminalService'),
ExtHostSCM: createExtId<ExtHostSCMShape>('ExtHostSCM'),
ExtHostTask: createExtId<ExtHostTaskShape>('ExtHostTask'),
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews')
};

View File

@@ -10,7 +10,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
@@ -189,10 +189,10 @@ export class ExtHostApiCommands {
return this._commands.executeCommand('_files.windowOpen', [uri.fsPath], forceNewWindow);
}, {
description: 'Open a folder in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder unless the newWindow parameter is set to true.',
description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.',
args: [
{ name: 'uri', description: '(optional) Uri of the folder to open. If not provided, a native dialog will ask the user for the folder', constraint: value => value === void 0 || value instanceof URI },
{ name: 'newWindow', description: '(optional) Whether to open the folder in a new window or the same. Defaults to opening in the same window.', constraint: value => value === void 0 || typeof value === 'boolean' }
{ name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: value => value === void 0 || value instanceof URI },
{ name: 'newWindow', description: '(optional) Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window.', constraint: value => value === void 0 || typeof value === 'boolean' }
]
});
@@ -239,6 +239,15 @@ export class ExtHostApiCommands {
{ name: 'columnOrOptions', description: '(optional) Either the column in which to open or editor options, see vscode.TextDocumentShowOptions', constraint: v => v === void 0 || typeof v === 'number' || typeof v === 'object' }
]
});
this._register('vscode.removeFromRecentlyOpened', (path: string) => {
return this._commands.executeCommand('_workbench.removeFromRecentlyOpened', path);
}, {
description: 'Removes an entry with the given path from the recently opened list.',
args: [
{ name: 'path', description: 'Path to remove from recently opened.', constraint: value => typeof value === 'string' }
]
});
}
// --- command impl
@@ -344,11 +353,7 @@ export class ExtHostApiCommands {
if (value.rejectReason) {
return TPromise.wrapError<types.WorkspaceEdit>(new Error(value.rejectReason));
}
let workspaceEdit = new types.WorkspaceEdit();
for (let edit of value.edits) {
workspaceEdit.replace(edit.resource, typeConverters.toRange(edit.range), edit.newText);
}
return workspaceEdit;
return typeConverters.WorkspaceEdit.to(value);
});
}
@@ -409,8 +414,14 @@ export class ExtHostApiCommands {
} else {
const ret = new types.CodeAction(
codeAction.title,
typeConverters.WorkspaceEdit.to(codeAction.edits)
codeAction.kind ? new types.CodeActionKind(codeAction.kind) : undefined
);
if (codeAction.edit) {
ret.edit = typeConverters.WorkspaceEdit.to(codeAction.edit);
}
if (codeAction.command) {
ret.command = this._commands.converter.fromInternal(codeAction.command);
}
return ret;
}
});

View File

@@ -6,7 +6,6 @@
import { validateConstraint } from 'vs/base/common/types';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { TPromise } from 'vs/base/common/winjs.base';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
import { cloneAndChange } from 'vs/base/common/objects';
@@ -16,6 +15,7 @@ import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import * as modes from 'vs/editor/common/modes';
import * as vscode from 'vscode';
import { ILogService } from 'vs/platform/log/common/log';
import { revive } from 'vs/base/common/marshalling';
interface CommandHandler {
callback: Function;
@@ -29,18 +29,21 @@ export interface ArgumentProcessor {
export class ExtHostCommands implements ExtHostCommandsShape {
private _commands = new Map<string, CommandHandler>();
private _proxy: MainThreadCommandsShape;
private _converter: CommandsConverter;
private _argumentProcessors: ArgumentProcessor[] = [];
private readonly _commands = new Map<string, CommandHandler>();
private readonly _proxy: MainThreadCommandsShape;
private readonly _converter: CommandsConverter;
private readonly _logService: ILogService;
private readonly _argumentProcessors: ArgumentProcessor[];
constructor(
mainContext: IMainContext,
heapService: ExtHostHeapService,
private logService: ILogService
logService: ILogService
) {
this._proxy = mainContext.get(MainContext.MainThreadCommands);
this._proxy = mainContext.getProxy(MainContext.MainThreadCommands);
this._logService = logService;
this._converter = new CommandsConverter(this, heapService);
this._argumentProcessors = [{ processArgument(a) { return revive(a, 0); } }];
}
get converter(): CommandsConverter {
@@ -52,7 +55,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
registerCommand(id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, description?: ICommandHandlerDescription): extHostTypes.Disposable {
this.logService.trace('ExtHostCommands#registerCommand', id);
this._logService.trace('ExtHostCommands#registerCommand', id);
if (!id.trim().length) {
throw new Error('invalid id');
@@ -73,12 +76,12 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
this.logService.trace('ExtHostCommands#executeCommand', id);
this._logService.trace('ExtHostCommands#executeCommand', id);
if (this._commands.has(id)) {
// we stay inside the extension host and support
// to pass any kind of parameters around
return this.$executeContributedCommand<T>(id, ...args);
return this._executeContributedCommand<T>(id, args);
} else {
// automagically convert some argument types
@@ -98,47 +101,42 @@ export class ExtHostCommands implements ExtHostCommandsShape {
}
});
return this._proxy.$executeCommand<T>(id, args);
return this._proxy.$executeCommand<T>(id, args).then(result => revive(result, 0));
}
}
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T> {
let command = this._commands.get(id);
if (!command) {
return TPromise.wrapError<T>(new Error(`Contributed command '${id}' does not exist.`));
}
let { callback, thisArg, description } = command;
private _executeContributedCommand<T>(id: string, args: any[]): Thenable<T> {
let { callback, thisArg, description } = this._commands.get(id);
if (description) {
for (let i = 0; i < description.args.length; i++) {
try {
validateConstraint(args[i], description.args[i].constraint);
} catch (err) {
return TPromise.wrapError<T>(new Error(`Running the contributed command:'${id}' failed. Illegal argument '${description.args[i].name}' - ${description.args[i].description}`));
return <any>Promise.reject(new Error(`Running the contributed command:'${id}' failed. Illegal argument '${description.args[i].name}' - ${description.args[i].description}`));
}
}
}
args = args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg));
try {
let result = callback.apply(thisArg, args);
return TPromise.as(result);
return Promise.resolve(result);
} catch (err) {
// console.log(err);
// try {
// console.log(toErrorMessage(err));
// } catch (err) {
// //
// }
return TPromise.wrapError<T>(new Error(`Running the contributed command:'${id}' failed.`));
this._logService.error(err, id);
return <any>Promise.reject(new Error(`Running the contributed command:'${id}' failed.`));
}
}
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T> {
if (!this._commands.has(id)) {
return <any>Promise.reject(new Error(`Contributed command '${id}' does not exist.`));
} else {
args = args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg));
return this._executeContributedCommand(id, args);
}
}
getCommands(filterUnderscoreCommands: boolean = false): Thenable<string[]> {
this.logService.trace('ExtHostCommands#getCommands', filterUnderscoreCommands);
this._logService.trace('ExtHostCommands#getCommands', filterUnderscoreCommands);
return this._proxy.$getCommands().then(result => {
if (filterUnderscoreCommands) {
@@ -148,7 +146,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
});
}
$getContributedCommandHandlerDescriptions(): TPromise<{ [id: string]: string | ICommandHandlerDescription }> {
$getContributedCommandHandlerDescriptions(): Thenable<{ [id: string]: string | ICommandHandlerDescription }> {
const result: { [id: string]: string | ICommandHandlerDescription } = Object.create(null);
this._commands.forEach((command, id) => {
let { description } = command;
@@ -156,7 +154,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
result[id] = description;
}
});
return TPromise.as(result);
return Promise.resolve(result);
}
}

View File

@@ -41,14 +41,14 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
private readonly _onDidChangeConfiguration = new Emitter<vscode.ConfigurationChangeEvent>();
private readonly _proxy: MainThreadConfigurationShape;
private readonly _extHostWorkspace: ExtHostWorkspace;
private _configurationScopes: Map<string, ConfigurationScope>;
private _configurationScopes: { [key: string]: ConfigurationScope };
private _configuration: Configuration;
constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) {
this._proxy = proxy;
this._extHostWorkspace = extHostWorkspace;
this._configuration = Configuration.parse(data);
this._readConfigurationScopes(data.configurationScopes);
this._configurationScopes = data.configurationScopes;
}
get onDidChangeConfiguration(): Event<vscode.ConfigurationChangeEvent> {
@@ -129,7 +129,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
}
private _validateConfigurationAccess(key: string, resource: URI, extensionId: string): void {
const scope = this._configurationScopes.get(key);
const scope = this._configurationScopes[key];
const extensionIdText = extensionId ? `[${extensionId}] ` : '';
if (ConfigurationScope.RESOURCE === scope) {
if (resource === void 0) {
@@ -145,18 +145,6 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape {
}
}
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>();

View File

@@ -9,12 +9,16 @@
import { TPromise } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID, IMainContext, IBreakpointsDelta, ISourceBreakpointData, IFunctionBreakpointData } from 'vs/workbench/api/node/extHost.protocol';
import {
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto
} from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint } from 'vs/workbench/api/node/extHostTypes';
import { generateUuid } from 'vs/base/common/uuid';
export class ExtHostDebugService implements ExtHostDebugServiceShape {
@@ -63,7 +67,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
this._onDidChangeActiveDebugSession = new Emitter<vscode.DebugSession>();
this._onDidReceiveDebugSessionCustomEvent = new Emitter<vscode.DebugSessionCustomEvent>();
this._debugServiceProxy = mainContext.get(MainContext.MainThreadDebugService);
this._debugServiceProxy = mainContext.getProxy(MainContext.MainThreadDebugService);
this._onDidChangeBreakpoints = new Emitter<vscode.BreakpointsChangeEvent>({
onFirstListenerAdd: () => {
@@ -97,50 +101,161 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
return result;
}
public $acceptBreakpointsDelta(delta: IBreakpointsDelta): void {
public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {
let a: vscode.Breakpoint[] = [];
let r: vscode.Breakpoint[] = [];
let c: vscode.Breakpoint[] = [];
if (delta.added) {
a = delta.added.map(bpd => {
const bp = this.fromWire(bpd);
this._breakpoints.set(bpd.id, bp);
return bp;
});
for (const bpd of delta.added) {
if (!this._breakpoints.has(bpd.id)) {
let bp: vscode.Breakpoint;
if (bpd.type === 'function') {
bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition);
} else {
const uri = URI.revive(bpd.uri);
bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition);
}
bp['_id'] = bpd.id;
this._breakpoints.set(bpd.id, bp);
a.push(bp);
}
}
}
if (delta.removed) {
r = delta.removed.map(id => {
for (const id of delta.removed) {
const bp = this._breakpoints.get(id);
if (bp) {
this._breakpoints.delete(id);
r.push(bp);
}
return bp;
});
}
}
if (delta.changed) {
c = delta.changed.map(bpd => {
const bp = this.fromWire(bpd);
this._breakpoints.set(bpd.id, bp);
return bp;
});
for (const bpd of delta.changed) {
let bp = this._breakpoints.get(bpd.id);
if (bp) {
if (bpd.type === 'function') {
const fbp = <any>bp;
fbp.enabled = bpd.enabled;
fbp.condition = bpd.condition;
fbp.hitCondition = bpd.hitCondition;
fbp.functionName = bpd.functionName;
} else {
const sbp = <any>bp;
sbp.enabled = bpd.enabled;
sbp.condition = bpd.condition;
sbp.hitCondition = bpd.hitCondition;
}
c.push(bp);
}
}
}
this._onDidChangeBreakpoints.fire(Object.freeze({
added: Object.freeze<vscode.Breakpoint[]>(a || []),
removed: Object.freeze<vscode.Breakpoint[]>(r || []),
changed: Object.freeze<vscode.Breakpoint[]>(c || [])
}));
this.fireBreakpointChanges(a, r, c);
}
private fromWire(bp: ISourceBreakpointData | IFunctionBreakpointData): vscode.Breakpoint {
if (bp.type === 'function') {
return new FunctionBreakpoint(bp.enabled, bp.condition, bp.hitCondition, bp.functionName);
public addBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise<void> {
this.startBreakpoints();
// assign uuids for brand new breakpoints
const breakpoints: vscode.Breakpoint[] = [];
for (const bp of breakpoints0) {
let id = bp['_id'];
if (id) { // has already id
if (this._breakpoints.has(id)) {
// already there
} else {
breakpoints.push(bp);
}
} else {
id = generateUuid();
bp['_id'] = id;
this._breakpoints.set(id, bp);
breakpoints.push(bp);
}
}
// send notification for added breakpoints
this.fireBreakpointChanges(breakpoints, [], []);
// convert added breakpoints to DTOs
const dtos: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[] = [];
const map = new Map<string, ISourceMultiBreakpointDto>();
for (const bp of breakpoints) {
if (bp instanceof SourceBreakpoint) {
let dto = map.get(bp.location.uri.toString());
if (!dto) {
dto = <ISourceMultiBreakpointDto>{
type: 'sourceMulti',
uri: bp.location.uri,
lines: []
};
map.set(bp.location.uri.toString(), dto);
dtos.push(dto);
}
dto.lines.push({
id: bp['_id'],
enabled: bp.enabled,
condition: bp.condition,
hitCondition: bp.hitCondition,
line: bp.location.range.start.line,
character: bp.location.range.start.character
});
} else if (bp instanceof FunctionBreakpoint) {
dtos.push({
type: 'function',
id: bp['_id'],
enabled: bp.enabled,
functionName: bp.functionName,
hitCondition: bp.hitCondition,
condition: bp.condition
});
}
}
// send DTOs to VS Code
return this._debugServiceProxy.$registerBreakpoints(dtos);
}
public removeBreakpoints(breakpoints0: vscode.Breakpoint[]): TPromise<void> {
this.startBreakpoints();
// remove from array
const breakpoints: vscode.Breakpoint[] = [];
for (const b of breakpoints0) {
let id = b['_id'];
if (id && this._breakpoints.delete(id)) {
breakpoints.push(b);
}
}
// send notification
this.fireBreakpointChanges([], breakpoints, []);
// unregister with VS Code
const ids = breakpoints.filter(bp => bp instanceof SourceBreakpoint).map(bp => bp['_id']);
const fids = breakpoints.filter(bp => bp instanceof FunctionBreakpoint).map(bp => bp['_id']);
return this._debugServiceProxy.$unregisterBreakpoints(ids, fids);
}
private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) {
if (added.length > 0 || removed.length > 0 || changed.length > 0) {
this._onDidChangeBreakpoints.fire(Object.freeze({
added: Object.freeze<vscode.Breakpoint[]>(added),
removed: Object.freeze<vscode.Breakpoint[]>(removed),
changed: Object.freeze<vscode.Breakpoint[]>(changed)
}));
}
return new SourceBreakpoint(bp.enabled, bp.condition, bp.hitCondition, new Location(bp.uri, new Position(bp.line, bp.character)));
}
public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider): vscode.Disposable {
@@ -150,7 +265,10 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
let handle = this.nextHandle();
this._handlers.set(handle, provider);
this._debugServiceProxy.$registerDebugConfigurationProvider(type, !!provider.provideDebugConfigurations, !!provider.resolveDebugConfiguration, handle);
this._debugServiceProxy.$registerDebugConfigurationProvider(type,
!!provider.provideDebugConfigurations,
!!provider.resolveDebugConfiguration,
!!provider.debugAdapterExecutable, handle);
return new Disposable(() => {
this._handlers.delete(handle);
@@ -158,7 +276,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
});
}
public $provideDebugConfigurations(handle: number, folderUri: URI | undefined): TPromise<vscode.DebugConfiguration[]> {
public $provideDebugConfigurations(handle: number, folderUri: UriComponents | undefined): TPromise<vscode.DebugConfiguration[]> {
let handler = this._handlers.get(handle);
if (!handler) {
return TPromise.wrapError<vscode.DebugConfiguration[]>(new Error('no handler found'));
@@ -169,7 +287,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
return asWinJsPromise(token => handler.provideDebugConfigurations(this.getFolder(folderUri), token));
}
public $resolveDebugConfiguration(handle: number, folderUri: URI | undefined, debugConfiguration: vscode.DebugConfiguration): TPromise<vscode.DebugConfiguration> {
public $resolveDebugConfiguration(handle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): TPromise<vscode.DebugConfiguration> {
let handler = this._handlers.get(handle);
if (!handler) {
return TPromise.wrapError<vscode.DebugConfiguration>(new Error('no handler found'));
@@ -180,6 +298,17 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
return asWinJsPromise(token => handler.resolveDebugConfiguration(this.getFolder(folderUri), debugConfiguration, token));
}
public $debugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): TPromise<vscode.DebugAdapterExecutable> {
let handler = this._handlers.get(handle);
if (!handler) {
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('no handler found'));
}
if (!handler.debugAdapterExecutable) {
return TPromise.wrapError<vscode.DebugAdapterExecutable>(new Error('handler has no method debugAdapterExecutable'));
}
return asWinJsPromise(token => handler.debugAdapterExecutable(this.getFolder(folderUri), token));
}
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration): TPromise<boolean> {
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig);
}
@@ -234,10 +363,11 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
this._onDidReceiveDebugSessionCustomEvent.fire(ee);
}
private getFolder(folderUri: URI | undefined) {
if (folderUri) {
private getFolder(_folderUri: UriComponents | undefined) {
if (_folderUri) {
const folderUriString = URI.revive(_folderUri).toString();
const folders = this._workspace.getWorkspaceFolders();
const found = folders.filter(f => f.uri.toString() === folderUri.toString());
const found = folders.filter(f => f.uri.toString() === folderUriString);
if (found && found.length > 0) {
return found[0];
}

View File

@@ -6,7 +6,7 @@
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 { MainContext, IMainContext, ExtHostDecorationsShape, MainThreadDecorationsShape, DecorationData, DecorationRequest, DecorationReply } 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';
@@ -19,7 +19,7 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
private readonly _proxy: MainThreadDecorationsShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadDecorations);
this._proxy = mainContext.getProxy(MainContext.MainThreadDecorations);
}
registerDecorationProvider(provider: vscode.DecorationProvider, label: string): vscode.Disposable {
@@ -38,10 +38,19 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
});
}
$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];
$provideDecorations(requests: DecorationRequest[]): TPromise<DecorationReply> {
const result: DecorationReply = Object.create(null);
return TPromise.join(requests.map(request => {
const { handle, uri, id } = request;
const provider = this._provider.get(handle);
return asWinJsPromise(token => provider.provideDecoration(URI.revive(uri), token)).then(data => {
result[id] = data && <DecorationData>[data.priority, data.bubble, data.title, data.abbreviation, data.color, data.source];
}, err => {
console.error(err);
});
})).then(() => {
return result;
});
}
}

View File

@@ -224,7 +224,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
private _collections: DiagnosticCollection[];
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadDiagnostics);
this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics);
this._collections = [];
}
@@ -255,4 +255,3 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
this._collections.forEach(callback);
}
}

View File

@@ -13,7 +13,7 @@ export class ExtHostDialogs {
private readonly _proxy: MainThreadDiaglogsShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadDialogs);
this._proxy = mainContext.getProxy(MainContext.MainThreadDialogs);
}
showOpenDialog(options: vscode.OpenDialogOptions): Thenable<URI[]> {

View File

@@ -5,16 +5,15 @@
'use strict';
import { onUnexpectedError } from 'vs/base/common/errors';
import * as editorCommon from 'vs/editor/common/editorCommon';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
import { TPromise } from 'vs/base/common/winjs.base';
import * as vscode from 'vscode';
import { asWinJsPromise } from 'vs/base/common/async';
import { TextSource } from 'vs/editor/common/model/textSource';
import { MainContext, ExtHostDocumentContentProvidersShape, MainThreadDocumentContentProvidersShape, IMainContext } from './extHost.protocol';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { Schemas } from 'vs/base/common/network';
export class ExtHostDocumentContentProvider implements ExtHostDocumentContentProvidersShape {
@@ -25,7 +24,7 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors;
constructor(mainContext: IMainContext, documentsAndEditors: ExtHostDocumentsAndEditors) {
this._proxy = mainContext.get(MainContext.MainThreadDocumentContentProviders);
this._proxy = mainContext.getProxy(MainContext.MainThreadDocumentContentProviders);
this._documentsAndEditors = documentsAndEditors;
}
@@ -34,7 +33,9 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
}
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider): vscode.Disposable {
if (scheme === 'file' || scheme === 'untitled') {
// todo@remote
// check with scheme from fs-providers!
if (scheme === Schemas.file || scheme === Schemas.untitled) {
throw new Error(`scheme '${scheme}' already registered`);
}
@@ -56,11 +57,11 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
}
// create lines and compare
const textSource = TextSource.fromString(value, editorCommon.DefaultEndOfLine.CRLF);
const lines = value.split(/\r\n|\r|\n/);
// broadcast event when content changed
if (!document.equalLines(textSource)) {
return this._proxy.$onVirtualDocumentChange(uri, textSource);
if (!document.equalLines(lines)) {
return this._proxy.$onVirtualDocumentChange(uri, value);
}
}, onUnexpectedError);
@@ -78,11 +79,11 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
});
}
$provideTextDocumentContent(handle: number, uri: URI): TPromise<string> {
$provideTextDocumentContent(handle: number, uri: UriComponents): TPromise<string> {
const provider = this._documentContentProviders.get(handle);
if (!provider) {
return TPromise.wrapError<string>(new Error(`unsupported uri-scheme: ${uri.scheme}`));
}
return asWinJsPromise(token => provider.provideTextDocumentContent(uri, token));
return asWinJsPromise(token => provider.provideTextDocumentContent(URI.revive(uri), token));
}
}

View File

@@ -6,13 +6,12 @@
import { ok } from 'vs/base/common/assert';
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
import { MirrorModel } from 'vs/editor/common/model/mirrorModel';
import { MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel';
import URI from 'vs/base/common/uri';
import { Range, Position, EndOfLine } from 'vs/workbench/api/node/extHostTypes';
import * as vscode from 'vscode';
import { getWordAtText, ensureValidWordDefinition } from 'vs/editor/common/model/wordHelper';
import { MainThreadDocumentsShape } from './extHost.protocol';
import { ITextSource } from 'vs/editor/common/model/textSource';
import { TPromise } from 'vs/base/common/winjs.base';
const _modeId2WordDefinition = new Map<string, RegExp>();
@@ -23,7 +22,7 @@ export function getWordDefinitionFor(modeId: string): RegExp {
return _modeId2WordDefinition.get(modeId);
}
export class ExtHostDocumentData extends MirrorModel {
export class ExtHostDocumentData extends MirrorTextModel {
private _proxy: MainThreadDocumentsShape;
private _languageId: string;
@@ -50,7 +49,7 @@ export class ExtHostDocumentData extends MirrorModel {
this._isDirty = false;
}
equalLines({ lines }: ITextSource): boolean {
equalLines(lines: string[]): boolean {
const len = lines.length;
if (len !== this._lines.length) {
return false;
@@ -69,6 +68,8 @@ export class ExtHostDocumentData extends MirrorModel {
this._document = {
get uri() { return data._uri; },
get fileName() { return data._uri.fsPath; },
// todo@remote
// documents from other fs-provider must not be untitled
get isUntitled() { return data._uri.scheme !== 'file'; },
get languageId() { return data._languageId; },
get version() { return data._versionId; },

View File

@@ -5,39 +5,42 @@
'use strict';
import Event from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } 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 { ExtHostDocumentSaveParticipantShape, MainThreadEditorsShape, IWorkspaceResourceEdit } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, ResourceTextEditDto } from 'vs/workbench/api/node/extHost.protocol';
import { TextEdit } from 'vs/workbench/api/node/extHostTypes';
import { fromRange, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/node/extHostTypeConverters';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import * as vscode from 'vscode';
import { LinkedList } from 'vs/base/common/linkedList';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
type Listener = [Function, any, IExtensionDescription];
export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSaveParticipantShape {
private _documents: ExtHostDocuments;
private _mainThreadEditors: MainThreadEditorsShape;
private _callbacks = new LinkedList<[Function, any]>();
private _badListeners = new WeakMap<Function, number>();
private _thresholds: { timeout: number; errors: number; };
private readonly _callbacks = new LinkedList<Listener>();
private readonly _badListeners = new WeakMap<Function, number>();
constructor(documents: ExtHostDocuments, mainThreadEditors: MainThreadEditorsShape, thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }) {
this._documents = documents;
this._mainThreadEditors = mainThreadEditors;
this._thresholds = thresholds;
constructor(
private readonly _logService: ILogService,
private readonly _documents: ExtHostDocuments,
private readonly _mainThreadEditors: MainThreadTextEditorsShape,
private readonly _thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }
) {
//
}
dispose(): void {
this._callbacks.clear();
}
get onWillSaveTextDocumentEvent(): Event<vscode.TextDocumentWillSaveEvent> {
getOnWillSaveTextDocumentEvent(extension: IExtensionDescription): Event<vscode.TextDocumentWillSaveEvent> {
return (listener, thisArg, disposables) => {
const remove = this._callbacks.push([listener, thisArg]);
const remove = this._callbacks.push([listener, thisArg, extension]);
const result = { dispose: remove };
if (Array.isArray(disposables)) {
disposables.push(result);
@@ -46,13 +49,14 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
};
}
$participateInSave(resource: URI, reason: SaveReason): TPromise<boolean[]> {
$participateInSave(data: UriComponents, reason: SaveReason): Thenable<boolean[]> {
const resource = URI.revive(data);
const entries = this._callbacks.toArray();
let didTimeout = false;
let didTimeoutHandle = setTimeout(() => didTimeout = true, this._thresholds.timeout);
const promise = sequence(entries.map(([fn, thisArg]) => {
const promise = sequence(entries.map(listener => {
return () => {
if (didTimeout) {
@@ -61,18 +65,17 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}
const document = this._documents.getDocumentData(resource).document;
return this._deliverEventAsyncAndBlameBadListeners(fn, thisArg, <any>{ document, reason: TextDocumentSaveReason.to(reason) });
return this._deliverEventAsyncAndBlameBadListeners(listener, <any>{ document, reason: TextDocumentSaveReason.to(reason) });
};
}));
return always(promise, () => clearTimeout(didTimeoutHandle));
}
private _deliverEventAsyncAndBlameBadListeners(listener: Function, thisArg: any, stubEvent: vscode.TextDocumentWillSaveEvent): TPromise<any> {
private _deliverEventAsyncAndBlameBadListeners([listener, thisArg, extension]: Listener, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> {
const errors = this._badListeners.get(listener);
if (errors > this._thresholds.errors) {
// bad listener - ignore
return TPromise.wrap(false);
return Promise.resolve(false);
}
return this._deliverEventAsync(listener, thisArg, stubEvent).then(() => {
@@ -80,6 +83,10 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
return true;
}, err => {
this._logService.error('[onWillSaveTextDocument]', extension.id);
this._logService.error(err);
if (!(err instanceof Error) || (<Error>err).message !== 'concurrent_edits') {
const errors = this._badListeners.get(listener);
this._badListeners.set(listener, !errors ? 1 : errors + 1);
@@ -93,9 +100,9 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
});
}
private _deliverEventAsync(listener: Function, thisArg: any, stubEvent: vscode.TextDocumentWillSaveEvent): TPromise<any> {
private _deliverEventAsync(listener: Function, thisArg: any, stubEvent: vscode.TextDocumentWillSaveEvent): Promise<any> {
const promises: TPromise<vscode.TextEdit[]>[] = [];
const promises: Promise<vscode.TextEdit[]>[] = [];
const { document, reason } = stubEvent;
const { version } = document;
@@ -107,7 +114,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
if (Object.isFrozen(promises)) {
throw illegalState('waitUntil can not be called async');
}
promises.push(TPromise.wrap(p));
promises.push(Promise.resolve(p));
}
});
@@ -115,20 +122,27 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
// fire event
listener.apply(thisArg, [event]);
} catch (err) {
return TPromise.wrapError(err);
return Promise.reject(err);
}
// freeze promises after event call
Object.freeze(promises);
return new TPromise<vscode.TextEdit[][]>((resolve, reject) => {
return new Promise<vscode.TextEdit[][]>((resolve, reject) => {
// join on all listener promises, reject after timeout
const handle = setTimeout(() => reject(new Error('timeout')), this._thresholds.timeout);
return always(TPromise.join(promises), () => clearTimeout(handle)).then(resolve, reject);
return Promise.all(promises).then(edits => {
clearTimeout(handle);
resolve(edits);
}).catch(err => {
clearTimeout(handle);
reject(err);
});
}).then(values => {
let workspaceResourceEdit: IWorkspaceResourceEdit = {
const resourceEdit: ResourceTextEditDto = {
resource: document.uri,
edits: []
};
@@ -136,10 +150,10 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
for (const value of values) {
if (Array.isArray(value) && (<vscode.TextEdit[]>value).every(e => e instanceof TextEdit)) {
for (const { newText, newEol, range } of value) {
workspaceResourceEdit.edits.push({
resourceEdit.edits.push({
range: range && fromRange(range),
newText,
newEol: EndOfLine.from(newEol)
text: newText,
eol: EndOfLine.from(newEol)
});
}
}
@@ -147,16 +161,16 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
// apply edits if any and if document
// didn't change somehow in the meantime
if (workspaceResourceEdit.edits.length === 0) {
return undefined;
if (resourceEdit.edits.length === 0) {
return <any>undefined;
}
if (version === document.version) {
return this._mainThreadEditors.$tryApplyWorkspaceEdit([workspaceResourceEdit]);
return <any>this._mainThreadEditors.$tryApplyWorkspaceEdit({ edits: [resourceEdit] });
}
// TODO@joh bubble this to listener?
return TPromise.wrapError(new Error('concurrent_edits'));
return Promise.reject(new Error('concurrent_edits'));
});
}
}

View File

@@ -5,7 +5,7 @@
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import * as TypeConverters from './extHostTypeConverters';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -13,7 +13,7 @@ import * as vscode from 'vscode';
import { MainContext, MainThreadDocumentsShape, ExtHostDocumentsShape, IMainContext } from './extHost.protocol';
import { ExtHostDocumentData, setWordDefinitionFor } from './extHostDocumentData';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorModel';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
export class ExtHostDocuments implements ExtHostDocumentsShape {
@@ -33,7 +33,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
private _documentLoader = new Map<string, TPromise<ExtHostDocumentData>>();
constructor(mainContext: IMainContext, documentsAndEditors: ExtHostDocumentsAndEditors) {
this._proxy = mainContext.get(MainContext.MainThreadDocuments);
this._proxy = mainContext.getProxy(MainContext.MainThreadDocuments);
this._documentsAndEditors = documentsAndEditors;
this._toDispose = [
@@ -92,10 +92,12 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
}
public createDocumentData(options?: { language?: string; content?: string }): TPromise<URI> {
return this._proxy.$tryCreateDocument(options);
return this._proxy.$tryCreateDocument(options).then(data => URI.revive(data));
}
public $acceptModelModeChanged(strURL: string, oldModeId: string, newModeId: string): void {
public $acceptModelModeChanged(uriComponents: UriComponents, oldModeId: string, newModeId: string): void {
const uri = URI.revive(uriComponents);
const strURL = uri.toString();
let data = this._documentsAndEditors.getDocument(strURL);
// Treat a mode change as a remove + add
@@ -105,13 +107,17 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
this._onDidAddDocument.fire(data.document);
}
public $acceptModelSaved(strURL: string): void {
public $acceptModelSaved(uriComponents: UriComponents): void {
const uri = URI.revive(uriComponents);
const strURL = uri.toString();
let data = this._documentsAndEditors.getDocument(strURL);
this.$acceptDirtyStateChanged(strURL, false);
this.$acceptDirtyStateChanged(uriComponents, false);
this._onDidSaveDocument.fire(data.document);
}
public $acceptDirtyStateChanged(strURL: string, isDirty: boolean): void {
public $acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void {
const uri = URI.revive(uriComponents);
const strURL = uri.toString();
let data = this._documentsAndEditors.getDocument(strURL);
data._acceptIsDirty(isDirty);
this._onDidChangeDocument.fire({
@@ -120,7 +126,9 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
});
}
public $acceptModelChanged(strURL: string, events: IModelChangedEvent, isDirty: boolean): void {
public $acceptModelChanged(uriComponents: UriComponents, events: IModelChangedEvent, isDirty: boolean): void {
const uri = URI.revive(uriComponents);
const strURL = uri.toString();
let data = this._documentsAndEditors.getDocument(strURL);
data._acceptIsDirty(isDirty);
data.onEvents(events);

View File

@@ -11,10 +11,17 @@ import { ExtHostDocumentData } from './extHostDocumentData';
import { ExtHostTextEditor } from './extHostTextEditor';
import * as assert from 'assert';
import * as typeConverters from './extHostTypeConverters';
import URI from 'vs/base/common/uri';
import { ExtHostWebview, ExtHostWebviews } from './extHostWebview';
import { Disposable } from './extHostTypes';
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
private _disposables: Disposable[] = [];
private _activeEditorId: string;
private _activeWebview: ExtHostWebview;
private readonly _editors = new Map<string, ExtHostTextEditor>();
private readonly _documents = new Map<string, ExtHostDocumentData>();
@@ -22,15 +29,34 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
private readonly _onDidRemoveDocuments = new Emitter<ExtHostDocumentData[]>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<ExtHostTextEditor[]>();
private readonly _onDidChangeActiveTextEditor = new Emitter<ExtHostTextEditor>();
private readonly _onDidChangeActiveEditor = new Emitter<ExtHostTextEditor | ExtHostWebview>();
readonly onDidAddDocuments: Event<ExtHostDocumentData[]> = this._onDidAddDocuments.event;
readonly onDidRemoveDocuments: Event<ExtHostDocumentData[]> = this._onDidRemoveDocuments.event;
readonly onDidChangeVisibleTextEditors: Event<ExtHostTextEditor[]> = this._onDidChangeVisibleTextEditors.event;
readonly onDidChangeActiveTextEditor: Event<ExtHostTextEditor> = this._onDidChangeActiveTextEditor.event;
readonly onDidChangeActiveEditor: Event<ExtHostTextEditor | ExtHostWebview> = this._onDidChangeActiveEditor.event;
constructor(
private readonly _mainContext: IMainContext
private readonly _mainContext: IMainContext,
_extHostWebviews?: ExtHostWebviews
) {
if (_extHostWebviews) {
_extHostWebviews.onDidChangeActiveWebview(webview => {
if (webview) {
if (webview !== this._activeWebview) {
this._onDidChangeActiveEditor.fire(webview);
this._activeWebview = webview;
}
} else {
this._activeWebview = webview;
}
}, this, this._disposables);
}
}
dispose() {
this._disposables = dispose(this._disposables);
}
$acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
@@ -40,7 +66,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
const removedEditors: ExtHostTextEditor[] = [];
if (delta.removedDocuments) {
for (const id of delta.removedDocuments) {
for (const uriComponent of delta.removedDocuments) {
const uri = URI.revive(uriComponent);
const id = uri.toString();
const data = this._documents.get(id);
this._documents.delete(id);
removedDocuments.push(data);
@@ -49,18 +77,19 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
if (delta.addedDocuments) {
for (const data of delta.addedDocuments) {
assert.ok(!this._documents.has(data.url.toString()), `document '${data.url} already exists!'`);
const resource = URI.revive(data.uri);
assert.ok(!this._documents.has(resource.toString()), `document '${resource} already exists!'`);
const documentData = new ExtHostDocumentData(
this._mainContext.get(MainContext.MainThreadDocuments),
data.url,
this._mainContext.getProxy(MainContext.MainThreadDocuments),
resource,
data.lines,
data.EOL,
data.modeId,
data.versionId,
data.isDirty
);
this._documents.set(data.url.toString(), documentData);
this._documents.set(resource.toString(), documentData);
addedDocuments.push(documentData);
}
}
@@ -75,16 +104,18 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
if (delta.addedEditors) {
for (const data of delta.addedEditors) {
assert.ok(this._documents.has(data.document.toString()), `document '${data.document}' does not exist`);
const resource = URI.revive(data.documentUri);
assert.ok(this._documents.has(resource.toString()), `document '${resource}' does not exist`);
assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`);
const documentData = this._documents.get(data.document.toString());
const documentData = this._documents.get(resource.toString());
const editor = new ExtHostTextEditor(
this._mainContext.get(MainContext.MainThreadEditors),
this._mainContext.getProxy(MainContext.MainThreadTextEditors),
data.id,
documentData,
data.selections.map(typeConverters.toSelection),
data.options,
data.visibleRanges.map(typeConverters.toRange),
typeConverters.toViewColumn(data.editorPosition)
);
this._editors.set(data.id, editor);
@@ -112,6 +143,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
}
if (delta.newActiveEditor !== undefined) {
this._onDidChangeActiveTextEditor.fire(this.activeEditor());
const activeEditor = this.activeEditor();
this._onDidChangeActiveEditor.fire(activeEditor || this._activeWebview);
}
}

View File

@@ -9,7 +9,8 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtHostLogger } from 'vs/workbench/api/node/extHostLogService';
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = TPromise.wrap<void>(void 0);
@@ -26,6 +27,7 @@ export interface IExtensionContext {
extensionPath: string;
storagePath: string;
asAbsolutePath(relativePath: string): string;
logger: ExtHostLogger;
}
/**
@@ -240,7 +242,7 @@ export class ExtensionsActivator {
if (!depDesc) {
// Error condition 1: unknown dependency
this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Extension `{1}` failed to activate. Reason: unknown dependency `{0}`.", depId, currentExtension.id));
this._host.showMessage(Severity.Error, nls.localize('unknownDep', "Extension '{1}' failed to activate. Reason: unknown dependency '{0}'.", depId, currentExtension.id));
this._activatedExtensions[currentExtension.id] = new FailedExtension(ExtensionActivationTimes.NONE);
return;
}
@@ -249,7 +251,7 @@ export class ExtensionsActivator {
let dep = this._activatedExtensions[depId];
if (dep.activationFailed) {
// Error condition 2: a dependency has already failed activation
this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Extension `{1}` failed to activate. Reason: dependency `{0}` failed to activate.", depId, currentExtension.id));
this._host.showMessage(Severity.Error, nls.localize('failedDep1', "Extension '{1}' failed to activate. Reason: dependency '{0}' failed to activate.", depId, currentExtension.id));
this._activatedExtensions[currentExtension.id] = new FailedExtension(ExtensionActivationTimes.NONE);
return;
}
@@ -282,7 +284,7 @@ export class ExtensionsActivator {
// More than 10 dependencies deep => most likely a dependency loop
for (let i = 0, len = extensionDescriptions.length; i < len; i++) {
// Error condition 3: dependency loop
this._host.showMessage(Severity.Error, nls.localize('failedDep2', "Extension `{0}` failed to activate. Reason: more than 10 levels of dependencies (most likely a dependency loop).", extensionDescriptions[i].id));
this._host.showMessage(Severity.Error, nls.localize('failedDep2', "Extension '{0}' failed to activate. Reason: more than 10 levels of dependencies (most likely a dependency loop).", extensionDescriptions[i].id));
this._activatedExtensions[extensionDescriptions[i].id] = new FailedExtension(ExtensionActivationTimes.NONE);
}
return TPromise.as(void 0);
@@ -327,7 +329,7 @@ export class ExtensionsActivator {
}
this._activatingExtensions[extensionDescription.id] = this._host.actualActivateExtension(extensionDescription, reason).then(null, (err) => {
this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension `{0}` failed: {1}.", extensionDescription.id, err.message));
this._host.showMessage(Severity.Error, nls.localize('activationError', "Activating extension '{0}' failed: {1}.", extensionDescription.id, err.message));
console.error('Activating extension `' + extensionDescription.id + '` failed: ', err.message);
console.log('Here is the error stack: ', err.stack);
// Treat the extension as being empty

View File

@@ -6,31 +6,33 @@
import { dispose } from 'vs/base/common/lifecycle';
import { join } from 'path';
import { mkdirp, dirExists } from 'vs/base/node/pfs';
import { mkdirp, dirExists, realpath, writeFile } from 'vs/base/node/pfs';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
// {{SQL CARBON EDIT}}
import { createApiFactory, initializeExtensionApi } from 'sql/workbench/api/node/sqlExtHost.api.impl';
import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData, ExtHostExtensionServiceShape, MainThreadTelemetryShape } from './extHost.protocol';
import { checkProposedApiEnabled } from 'vs/workbench/api/node/extHost.api.impl';
import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData, ExtHostExtensionServiceShape, MainThreadTelemetryShape, IExtHostContext } from './extHost.protocol';
import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionAPI, IExtensionContext, EmptyExtension, IExtensionModule, ExtensionActivationTimesBuilder, ExtensionActivationTimes, ExtensionActivationReason, ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
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 { TernarySearchTree } from 'vs/base/common/map';
import { Barrier } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import URI from 'vs/base/common/uri';
class ExtensionMemento implements IExtensionMemento {
private _id: string;
private _shared: boolean;
private _storage: ExtHostStorage;
private readonly _id: string;
private readonly _shared: boolean;
private readonly _storage: ExtHostStorage;
private _init: TPromise<ExtensionMemento>;
private readonly _init: TPromise<ExtensionMemento>;
private _value: { [n: string]: any; };
constructor(id: string, global: boolean, storage: ExtHostStorage) {
@@ -89,24 +91,36 @@ class ExtensionStoragePath {
return undefined;
}
private _getOrCreateWorkspaceStoragePath(): TPromise<string> {
private async _getOrCreateWorkspaceStoragePath(): TPromise<string> {
if (!this._workspace) {
return TPromise.as(undefined);
}
const storageName = this._workspace.id;
const storagePath = join(this._environment.appSettingsHome, 'workspaceStorage', storageName);
return dirExists(storagePath).then(exists => {
if (exists) {
return storagePath;
}
const exists = await dirExists(storagePath);
return mkdirp(storagePath).then(success => {
return storagePath;
}, err => {
return undefined;
});
});
if (exists) {
return storagePath;
}
try {
await mkdirp(storagePath);
await writeFile(
join(storagePath, 'meta.json'),
JSON.stringify({
id: this._workspace.id,
configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(),
name: this._workspace.name
}, undefined, 2)
);
return storagePath;
} catch (e) {
console.error(e);
return undefined;
}
}
}
@@ -114,35 +128,34 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
private readonly _barrier: Barrier;
private readonly _registry: ExtensionDescriptionRegistry;
private readonly _threadService: ExtHostThreadService;
private readonly _mainThreadTelemetry: MainThreadTelemetryShape;
private readonly _storage: ExtHostStorage;
private readonly _storagePath: ExtensionStoragePath;
private readonly _proxy: MainThreadExtensionServiceShape;
private readonly _logService: ILogService;
private readonly _extHostLogService: ExtHostLogService;
private _activator: ExtensionsActivator;
private _extensionPathIndex: TPromise<TernarySearchTree<IExtensionDescription>>;
/**
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
*/
constructor(initData: IInitData,
threadService: ExtHostThreadService,
extHostContext: IExtHostContext,
extHostWorkspace: ExtHostWorkspace,
extHostConfiguration: ExtHostConfiguration,
logService: ILogService
extHostLogService: ExtHostLogService,
environmentService: IEnvironmentService
) {
this._barrier = new Barrier();
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
this._threadService = threadService;
this._logService = logService;
this._mainThreadTelemetry = threadService.get(MainContext.MainThreadTelemetry);
this._storage = new ExtHostStorage(threadService);
this._extHostLogService = extHostLogService;
this._mainThreadTelemetry = extHostContext.getProxy(MainContext.MainThreadTelemetry);
this._storage = new ExtHostStorage(extHostContext);
this._storagePath = new ExtensionStoragePath(initData.workspace, initData.environment);
this._proxy = this._threadService.get(MainContext.MainThreadExtensionService);
this._proxy = extHostContext.getProxy(MainContext.MainThreadExtensionService);
this._activator = null;
// initialize API first (i.e. do not release barrier until the API is initialized)
const apiFactory = createApiFactory(initData, threadService, extHostWorkspace, extHostConfiguration, this, logService);
const apiFactory = createApiFactory(initData, extHostContext, extHostWorkspace, extHostConfiguration, this, this._extHostLogService);
initializeExtensionApi(this, apiFactory).then(() => {
@@ -223,16 +236,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
if (!ext.main) {
return undefined;
}
return new TPromise((resolve, reject) => {
realpath(ext.extensionFolderPath, (err, path) => {
if (err) {
reject(err);
} else {
tree.set(path, ext);
resolve(void 0);
}
});
});
return realpath(ext.extensionFolderPath).then(value => tree.set(value, ext));
});
this._extensionPathIndex = TPromise.join(extensions).then(() => tree);
}
@@ -311,14 +316,14 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
return TPromise.as(new EmptyExtension(ExtensionActivationTimes.NONE));
}
this._logService.info(`ExtensionService#_doActivateExtension ${extensionDescription.id} ${JSON.stringify(reason)}`);
this._extHostLogService.info(`ExtensionService#_doActivateExtension ${extensionDescription.id} ${JSON.stringify(reason)}`);
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
return TPromise.join<any>([
loadCommonJSModule(this._logService, extensionDescription.main, activationTimesBuilder),
loadCommonJSModule(this._extHostLogService, extensionDescription.main, activationTimesBuilder),
this._loadExtensionContext(extensionDescription)
]).then(values => {
return ExtHostExtensionService._callActivate(this._logService, extensionDescription.id, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
return ExtHostExtensionService._callActivate(this._extHostLogService, extensionDescription.id, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
}, (errors: any[]) => {
// Avoid failing with an array of errors, fail with a single error
if (errors[0]) {
@@ -336,19 +341,24 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
let globalState = new ExtensionMemento(extensionDescription.id, true, this._storage);
let workspaceState = new ExtensionMemento(extensionDescription.id, false, this._storage);
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.id}`);
this._extHostLogService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.id}`);
return TPromise.join([
globalState.whenReady,
workspaceState.whenReady,
this._storagePath.whenReady
]).then(() => {
const that = this;
return Object.freeze(<IExtensionContext>{
globalState,
workspaceState,
subscriptions: [],
get extensionPath() { return extensionDescription.extensionFolderPath; },
storagePath: this._storagePath.value(extensionDescription),
asAbsolutePath: (relativePath: string) => { return join(extensionDescription.extensionFolderPath, relativePath); }
asAbsolutePath: (relativePath: string) => { return join(extensionDescription.extensionFolderPath, relativePath); },
get logger() {
checkProposedApiEnabled(extensionDescription);
return that._extHostLogService.getExtLogger(extensionDescription.id);
}
});
});
}

View File

@@ -4,29 +4,79 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } 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';
import { IPatternInfo } from 'vs/platform/search/common/search';
import { values } from 'vs/base/common/map';
import { Range } from 'vs/workbench/api/node/extHostTypes';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
class FsLinkProvider implements vscode.DocumentLinkProvider {
private _schemes = new Set<string>();
private _regex: RegExp;
add(scheme: string): void {
this._regex = undefined;
this._schemes.add(scheme);
}
delete(scheme: string): void {
if (this._schemes.delete(scheme)) {
this._regex = undefined;
}
}
provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult<vscode.DocumentLink[]> {
if (this._schemes.size === 0) {
return undefined;
}
if (!this._regex) {
this._regex = new RegExp(`(${(values(this._schemes).join('|'))}):[^\\s]+`, 'gi');
}
let result: vscode.DocumentLink[] = [];
let max = Math.min(document.lineCount, 2500);
for (let line = 0; line < max; line++) {
this._regex.lastIndex = 0;
let textLine = document.lineAt(line);
let m: RegExpMatchArray;
while (m = this._regex.exec(textLine.text)) {
const target = URI.parse(m[0]);
const range = new Range(line, this._regex.lastIndex - m[0].length, line, this._regex.lastIndex);
result.push({ target, range });
}
}
return result;
}
}
export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
private readonly _provider = new Map<number, vscode.FileSystemProvider>();
private readonly _linkProvider = new FsLinkProvider();
private _handlePool: number = 0;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadFileSystem);
constructor(mainContext: IMainContext, extHostLanguageFeatures: ExtHostLanguageFeatures) {
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
extHostLanguageFeatures.registerDocumentLinkProvider('*', this._linkProvider);
}
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider) {
const handle = this._handlePool++;
this._linkProvider.add(scheme);
this._provider.set(handle, provider);
this._proxy.$registerFileSystemProvider(handle, scheme);
this._proxy.$onDidAddFileSystemRoot(<any>provider.root);
if (provider.root) {
// todo@remote
this._proxy.$onDidAddFileSystemRoot(provider.root);
}
let reg: IDisposable;
if (provider.onDidChange) {
reg = provider.onDidChange(event => this._proxy.$onFileSystemChange(handle, <any>event));
@@ -36,50 +86,71 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
if (reg) {
reg.dispose();
}
this._linkProvider.delete(scheme);
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));
$utimes(handle: number, resource: UriComponents, mtime: number, atime: number): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).utimes(URI.revive(resource), mtime, atime));
}
$stat(handle: number, resource: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).stat(resource));
$stat(handle: number, resource: UriComponents): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).stat(URI.revive(resource)));
}
$read(handle: number, offset: number, count: number, resource: URI): TPromise<number> {
$read(handle: number, session: number, offset: number, count: number, resource: UriComponents): TPromise<number> {
const progress = {
report: chunk => {
this._proxy.$reportFileChunk(handle, resource, [].slice.call(chunk));
this._proxy.$reportFileChunk(handle, session, [].slice.call(chunk));
}
};
return asWinJsPromise(token => this._provider.get(handle).read(resource, offset, count, progress));
return asWinJsPromise(token => this._provider.get(handle).read(URI.revive(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)));
$write(handle: number, resource: UriComponents, content: number[]): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).write(URI.revive(resource), Buffer.from(content)));
}
$unlink(handle: number, resource: URI): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).unlink(resource));
$unlink(handle: number, resource: UriComponents): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).unlink(URI.revive(resource)));
}
$move(handle: number, resource: URI, target: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).move(resource, target));
$move(handle: number, resource: UriComponents, target: UriComponents): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).move(URI.revive(resource), URI.revive(target)));
}
$mkdir(handle: number, resource: URI): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).mkdir(resource));
$mkdir(handle: number, resource: UriComponents): TPromise<IStat, any> {
return asWinJsPromise(token => this._provider.get(handle).mkdir(URI.revive(resource)));
}
$readdir(handle: number, resource: URI): TPromise<[URI, IStat][], any> {
return asWinJsPromise(token => this._provider.get(handle).readdir(resource));
$readdir(handle: number, resource: UriComponents): TPromise<[UriComponents, IStat][], any> {
return asWinJsPromise(token => this._provider.get(handle).readdir(URI.revive(resource)));
}
$rmdir(handle: number, resource: URI): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).rmdir(resource));
$rmdir(handle: number, resource: UriComponents): TPromise<void, any> {
return asWinJsPromise(token => this._provider.get(handle).rmdir(URI.revive(resource)));
}
$fileFiles(handle: number, session: number, query: string): TPromise<void> {
$findFiles(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) };
const progress = {
report: (uri) => {
this._proxy.$handleFindMatch(handle, session, uri);
}
};
return asWinJsPromise(token => provider.findFiles(query, progress, token));
}
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, options: { includes: string[], excludes: string[] }): TPromise<void> {
const provider = this._provider.get(handle);
if (!provider.provideTextSearchResults) {
return TPromise.as(undefined);
}
const progress = {
report: (data: vscode.TextSearchResult) => {
this._proxy.$handleFindMatch(handle, session, [data.uri, {
lineNumber: 1 + data.range.start.line,
preview: data.preview.leading + data.preview.matching + data.preview.trailing,
offsetAndLengths: [[data.preview.leading.length, data.preview.matching.length]]
}]);
}
};
return asWinJsPromise(token => provider.provideTextSearchResults(pattern, options, progress, token));
}
}

View File

@@ -9,6 +9,7 @@ import { Disposable } from './extHostTypes';
import { parse, IRelativePattern } from 'vs/base/common/glob';
import { Uri, FileSystemWatcher as _FileSystemWatcher } from 'vscode';
import { FileSystemEvents, ExtHostFileSystemEventServiceShape } from './extHost.protocol';
import URI from 'vs/base/common/uri';
class FileSystemWatcher implements _FileSystemWatcher {
@@ -48,22 +49,25 @@ class FileSystemWatcher implements _FileSystemWatcher {
let subscription = dispatcher(events => {
if (!ignoreCreateEvents) {
for (let created of events.created) {
if (parsedPattern(created.fsPath)) {
this._onDidCreate.fire(created);
let uri = URI.revive(created);
if (parsedPattern(uri.fsPath)) {
this._onDidCreate.fire(uri);
}
}
}
if (!ignoreChangeEvents) {
for (let changed of events.changed) {
if (parsedPattern(changed.fsPath)) {
this._onDidChange.fire(changed);
let uri = URI.revive(changed);
if (parsedPattern(uri.fsPath)) {
this._onDidChange.fire(uri);
}
}
}
if (!ignoreDeleteEvents) {
for (let deleted of events.deleted) {
if (parsedPattern(deleted.fsPath)) {
this._onDidDelete.fire(deleted);
let uri = URI.revive(deleted);
if (parsedPattern(uri.fsPath)) {
this._onDidDelete.fire(uri);
}
}
}

View File

@@ -4,20 +4,20 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { mixin } from 'vs/base/common/objects';
import * as vscode from 'vscode';
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, Color } from 'vs/workbench/api/node/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/editorCommon';
import { Range, Disposable, CompletionList, SnippetString, Color, CodeActionKind } from 'vs/workbench/api/node/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { ExtHostDiagnostics, DiagnosticCollection } from 'vs/workbench/api/node/extHostDiagnostics';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IExtHostSuggestResult, IExtHostSuggestion, IWorkspaceSymbols, IWorkspaceSymbol, IdObject } from './extHost.protocol';
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, SymbolInformationDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto } from './extHost.protocol';
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
@@ -35,11 +35,11 @@ class OutlineAdapter {
this._provider = provider;
}
provideDocumentSymbols(resource: URI): TPromise<modes.SymbolInformation[]> {
provideDocumentSymbols(resource: URI): TPromise<SymbolInformationDto[]> {
let doc = this._documents.getDocumentData(resource).document;
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
if (Array.isArray(value)) {
return value.map(TypeConverters.fromSymbolInformation);
return value.map(symbol => IdObject.mixin(TypeConverters.fromSymbolInformation(symbol)));
}
return undefined;
});
@@ -255,7 +255,7 @@ class ReferenceAdapter {
}
}
export interface CustomCodeAction extends modes.CodeAction {
export interface CustomCodeAction extends CodeActionDto {
_isSynthetic?: boolean;
}
@@ -273,7 +273,8 @@ class CodeActionAdapter {
this._provider = provider;
}
provideCodeActions(resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
provideCodeActions(resource: URI, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
const doc = this._documents.getDocumentData(resource).document;
const ran = <vscode.Range>TypeConverters.toRange(range);
@@ -289,9 +290,12 @@ class CodeActionAdapter {
}
});
return asWinJsPromise(token => this._provider.provideCodeActions2
? this._provider.provideCodeActions2(doc, ran, { diagnostics: allDiagnostics }, token)
: this._provider.provideCodeActions(doc, ran, { diagnostics: allDiagnostics }, token)
const codeActionContext: vscode.CodeActionContext = {
diagnostics: allDiagnostics,
only: context.only ? new CodeActionKind(context.only) : undefined
};
return asWinJsPromise(token =>
this._provider.provideCodeActions(doc, ran, codeActionContext, token)
).then(commandsOrActions => {
if (isFalsyOrEmpty(commandsOrActions)) {
return undefined;
@@ -314,9 +318,8 @@ class CodeActionAdapter {
title: candidate.title,
command: candidate.command && this._commands.toInternal(candidate.command),
diagnostics: candidate.diagnostics && candidate.diagnostics.map(DiagnosticCollection.toMarkerData),
edits: Array.isArray(candidate.edits)
? TypeConverters.WorkspaceEdit.fromTextEdits(resource, candidate.edits)
: candidate.edits && TypeConverters.WorkspaceEdit.from(candidate.edits),
edit: candidate.edit && TypeConverters.WorkspaceEdit.from(candidate.edit),
kind: candidate.kind && candidate.kind.value
});
}
}
@@ -413,8 +416,8 @@ class NavigateTypeAdapter {
this._provider = provider;
}
provideWorkspaceSymbols(search: string): TPromise<IWorkspaceSymbols> {
const result: IWorkspaceSymbols = IdObject.mixin({ symbols: [] });
provideWorkspaceSymbols(search: string): TPromise<WorkspaceSymbolsDto> {
const result: WorkspaceSymbolsDto = IdObject.mixin({ symbols: [] });
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (!isFalsyOrEmpty(value)) {
for (const item of value) {
@@ -439,7 +442,7 @@ class NavigateTypeAdapter {
});
}
resolveWorkspaceSymbol(symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
resolveWorkspaceSymbol(symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
return TPromise.as(symbol);
@@ -465,12 +468,20 @@ class NavigateTypeAdapter {
}
}
interface RenameProvider2 extends vscode.RenameProvider {
resolveInitialRenameValue?(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult<any>;
}
class RenameAdapter {
private _documents: ExtHostDocuments;
private _provider: vscode.RenameProvider;
static supportsResolving(provider: RenameProvider2): boolean {
return typeof provider.resolveInitialRenameValue === 'function';
}
constructor(documents: ExtHostDocuments, provider: vscode.RenameProvider) {
private _documents: ExtHostDocuments;
private _provider: RenameProvider2;
constructor(documents: ExtHostDocuments, provider: RenameProvider2) {
this._documents = documents;
this._provider = provider;
}
@@ -502,6 +513,22 @@ class RenameAdapter {
}
});
}
resolveInitialRenameValue(resource: URI, position: IPosition): TPromise<modes.RenameInitialValue> {
if (typeof this._provider.resolveInitialRenameValue !== 'function') {
return TPromise.as(undefined);
}
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.resolveInitialRenameValue(doc, pos, token)).then((value) => {
return <modes.RenameInitialValue>{
range: TypeConverters.fromRange(value.range),
text: value.text
};
});
}
}
@@ -524,7 +551,7 @@ class SuggestAdapter {
this._provider = provider;
}
provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<IExtHostSuggestResult> {
provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto> {
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
@@ -535,7 +562,7 @@ class SuggestAdapter {
const _id = this._idPool++;
const result: IExtHostSuggestResult = {
const result: SuggestResultDto = {
_id,
suggestions: [],
};
@@ -554,7 +581,7 @@ class SuggestAdapter {
}
// the default text edit range
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) || new Range(pos, pos))
const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos))
.with({ end: pos });
for (let i = 0; i < list.items.length; i++) {
@@ -577,7 +604,7 @@ class SuggestAdapter {
return TPromise.as(suggestion);
}
const { _parentId, _id } = (<IExtHostSuggestion>suggestion);
const { _parentId, _id } = (<SuggestionDto>suggestion);
const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id];
if (!item) {
return TPromise.as(suggestion);
@@ -591,7 +618,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 wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)).with({ end: pos });
const newSuggestion = this._convertCompletionItem(resolvedItem, pos, wordRangeBeforePos, _id, _parentId);
if (newSuggestion) {
mixin(suggestion, newSuggestion, true);
@@ -605,13 +632,13 @@ class SuggestAdapter {
this._cache.delete(id);
}
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): IExtHostSuggestion {
private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, defaultRange: vscode.Range, _id: number, _parentId: number): SuggestionDto {
if (typeof item.label !== 'string' || item.label.length === 0) {
console.warn('INVALID text edit -> must have at least a label');
return undefined;
}
const result: IExtHostSuggestion = {
const result: SuggestionDto = {
//
_id,
_parentId,
@@ -777,10 +804,29 @@ class ColorProviderAdapter {
}
}
class FoldingProviderAdapter {
constructor(
private _documents: ExtHostDocuments,
private _provider: vscode.FoldingProvider
) { }
provideFoldingRanges(resource: URI): TPromise<modes.IFoldingRangeList> {
const doc = this._documents.getDocumentData(resource).document;
return asWinJsPromise(token => this._provider.provideFoldingRanges(doc, token)).then(list => {
if (!Array.isArray(list.ranges)) {
return void 0;
}
return TypeConverters.FoldingRangeList.from(list);
});
}
}
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter;
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
| ColorProviderAdapter | FoldingProviderAdapter;
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
@@ -800,7 +846,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
heapMonitor: ExtHostHeapService,
diagnostics: ExtHostDiagnostics
) {
this._proxy = mainContext.get(MainContext.MainThreadLanguageFeatures);
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures);
this._documents = documents;
this._commands = commands;
this._heapService = heapMonitor;
@@ -826,17 +872,22 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return callback(<any>adapter);
}
private _addNewAdapter(adapter: Adapter): number {
const handle = this._nextHandle();
this._adapter.set(handle, adapter);
return handle;
}
// --- outline
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new OutlineAdapter(this._documents, provider));
const handle = this._addNewAdapter(new OutlineAdapter(this._documents, provider));
this._proxy.$registerOutlineSupport(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentSymbols(handle: number, resource: URI): TPromise<modes.SymbolInformation[]> {
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(resource));
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<SymbolInformationDto[]> {
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource)));
}
// --- code lens
@@ -857,150 +908,140 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return result;
}
$provideCodeLenses(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(resource));
$provideCodeLenses(handle: number, resource: UriComponents): TPromise<modes.ICodeLensSymbol[]> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource)));
}
$resolveCodeLens(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(resource, symbol));
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol));
}
// --- declaration
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new DefinitionAdapter(this._documents, provider));
const handle = this._addNewAdapter(new DefinitionAdapter(this._documents, provider));
this._proxy.$registerDeclaractionSupport(handle, selector);
return this._createDisposable(handle);
}
$provideDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(resource, position));
$provideDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(URI.revive(resource), position));
}
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new ImplementationAdapter(this._documents, provider));
const handle = this._addNewAdapter(new ImplementationAdapter(this._documents, provider));
this._proxy.$registerImplementationSupport(handle, selector);
return this._createDisposable(handle);
}
$provideImplementation(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(resource, position));
$provideImplementation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(URI.revive(resource), position));
}
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new TypeDefinitionAdapter(this._documents, provider));
const handle = this._addNewAdapter(new TypeDefinitionAdapter(this._documents, provider));
this._proxy.$registerTypeDefinitionSupport(handle, selector);
return this._createDisposable(handle);
}
$provideTypeDefinition(handle: number, resource: URI, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(resource, position));
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Definition> {
return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(URI.revive(resource), position));
}
// --- extra info
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new HoverAdapter(this._documents, provider));
const handle = this._addNewAdapter(new HoverAdapter(this._documents, provider));
this._proxy.$registerHoverProvider(handle, selector);
return this._createDisposable(handle);
}
$provideHover(handle: number, resource: URI, position: IPosition): TPromise<modes.Hover> {
return this._withAdapter(handle, HoverAdapter, adpater => adpater.provideHover(resource, position));
$provideHover(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Hover> {
return this._withAdapter(handle, HoverAdapter, adpater => adpater.provideHover(URI.revive(resource), position));
}
// --- occurrences
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new DocumentHighlightAdapter(this._documents, provider));
const handle = this._addNewAdapter(new DocumentHighlightAdapter(this._documents, provider));
this._proxy.$registerDocumentHighlightProvider(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentHighlights(handle: number, resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]> {
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(resource, position));
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DocumentHighlight[]> {
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position));
}
// --- references
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new ReferenceAdapter(this._documents, provider));
const handle = this._addNewAdapter(new ReferenceAdapter(this._documents, provider));
this._proxy.$registerReferenceSupport(handle, selector);
return this._createDisposable(handle);
}
$provideReferences(handle: number, resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(resource, position, context));
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(URI.revive(resource), position, context));
}
// --- quick fix
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
this._proxy.$registerQuickFixSupport(handle, selector);
return this._createDisposable(handle);
}
$provideCodeActions(handle: number, resource: URI, range: IRange): TPromise<modes.CodeAction[]> {
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(resource, range));
$provideCodeActions(handle: number, resource: UriComponents, range: IRange, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), range, context));
}
// --- formatting
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new DocumentFormattingAdapter(this._documents, provider));
const handle = this._addNewAdapter(new DocumentFormattingAdapter(this._documents, provider));
this._proxy.$registerDocumentFormattingSupport(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentFormattingEdits(handle: number, resource: URI, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(resource, options));
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options));
}
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new RangeFormattingAdapter(this._documents, provider));
const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider));
this._proxy.$registerRangeFormattingSupport(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentRangeFormattingEdits(handle: number, resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(resource, range, options));
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(URI.revive(resource), range, options));
}
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new OnTypeFormattingAdapter(this._documents, provider));
const handle = this._addNewAdapter(new OnTypeFormattingAdapter(this._documents, provider));
this._proxy.$registerOnTypeFormattingSupport(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
$provideOnTypeFormattingEdits(handle: number, resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(resource, position, ch, options));
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(URI.revive(resource), position, ch, options));
}
// --- navigate types
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new NavigateTypeAdapter(provider));
const handle = this._addNewAdapter(new NavigateTypeAdapter(provider));
this._proxy.$registerNavigateTypeSupport(handle);
return this._createDisposable(handle);
}
$provideWorkspaceSymbols(handle: number, search: string): TPromise<IWorkspaceSymbols> {
$provideWorkspaceSymbols(handle: number, search: string): TPromise<WorkspaceSymbolsDto> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
}
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbol): TPromise<IWorkspaceSymbol> {
$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto> {
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
}
@@ -1010,32 +1051,34 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
// --- rename
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new RenameAdapter(this._documents, provider));
this._proxy.$registerRenameSupport(handle, selector);
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider, canUseProposedApi = false): vscode.Disposable {
const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider));
this._proxy.$registerRenameSupport(handle, selector, canUseProposedApi && RenameAdapter.supportsResolving(provider));
return this._createDisposable(handle);
}
$provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(resource, position, newName));
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<modes.WorkspaceEdit> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName));
}
$resolveInitialRenameValue(handle: number, resource: URI, position: IPosition): TPromise<modes.RenameInitialValue> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveInitialRenameValue(resource, position));
}
// --- suggestion
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, provider));
const handle = this._addNewAdapter(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, context: modes.SuggestContext): TPromise<IExtHostSuggestResult> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(resource, position, context));
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(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));
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, suggestion));
}
$releaseCompletionItems(handle: number, id: number): void {
@@ -1045,27 +1088,25 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
// --- parameter hints
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new SignatureHelpAdapter(this._documents, provider));
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider));
this._proxy.$registerSignatureHelpProvider(handle, selector, triggerCharacters);
return this._createDisposable(handle);
}
$provideSignatureHelp(handle: number, resource: URI, position: IPosition): TPromise<modes.SignatureHelp> {
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(resource, position));
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.SignatureHelp> {
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position));
}
// --- links
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new LinkProviderAdapter(this._documents, this._heapService, provider));
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, this._heapService, provider));
this._proxy.$registerDocumentLinkProvider(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentLinks(handle: number, resource: URI): TPromise<modes.ILink[]> {
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(resource));
$provideDocumentLinks(handle: number, resource: UriComponents): TPromise<modes.ILink[]> {
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource)));
}
$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink> {
@@ -1073,22 +1114,77 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
}
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter.set(handle, new ColorProviderAdapter(this._documents, provider));
const handle = this._addNewAdapter(new ColorProviderAdapter(this._documents, provider));
this._proxy.$registerDocumentColorProvider(handle, selector);
return this._createDisposable(handle);
}
$provideDocumentColors(handle: number, resource: URI): TPromise<IRawColorInfo[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(resource));
$provideDocumentColors(handle: number, resource: UriComponents): TPromise<IRawColorInfo[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource)));
}
$provideColorPresentations(handle: number, resource: URI, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(resource, colorInfo));
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo));
}
registerFoldingProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable {
const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider));
this._proxy.$registerFoldingProvider(handle, selector);
return this._createDisposable(handle);
}
$provideFoldingRanges(handle: number, resource: UriComponents): TPromise<modes.IFoldingRangeList> {
return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource)));
}
// --- configuration
private static _serializeRegExp(regExp: RegExp): ISerializedRegExp {
if (typeof regExp === 'undefined') {
return undefined;
}
if (regExp === null) {
return null;
}
return {
pattern: regExp.source,
flags: (regExp.global ? 'g' : '') + (regExp.ignoreCase ? 'i' : '') + (regExp.multiline ? 'm' : ''),
};
}
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): ISerializedIndentationRule {
if (typeof indentationRule === 'undefined') {
return undefined;
}
if (indentationRule === null) {
return null;
}
return {
decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern),
increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern),
indentNextLinePattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.indentNextLinePattern),
unIndentedLinePattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.unIndentedLinePattern),
};
}
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): ISerializedOnEnterRule {
return {
beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
afterText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText),
action: onEnterRule.action
};
}
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): ISerializedOnEnterRule[] {
if (typeof onEnterRules === 'undefined') {
return undefined;
}
if (onEnterRules === null) {
return null;
}
return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule);
}
setLanguageConfiguration(languageId: string, configuration: vscode.LanguageConfiguration): vscode.Disposable {
let { wordPattern } = configuration;
@@ -1105,7 +1201,16 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
}
const handle = this._nextHandle();
this._proxy.$setLanguageConfiguration(handle, languageId, configuration);
const serializedConfiguration: ISerializedLanguageConfiguration = {
comments: configuration.comments,
brackets: configuration.brackets,
wordPattern: ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern),
indentationRules: ExtHostLanguageFeatures._serializeIndentationRule(configuration.indentationRules),
onEnterRules: ExtHostLanguageFeatures._serializeOnEnterRules(configuration.onEnterRules),
__electricCharacterSupport: configuration.__electricCharacterSupport,
__characterPairSupport: configuration.__characterPairSupport,
};
this._proxy.$setLanguageConfiguration(handle, languageId, serializedConfiguration);
return this._createDisposable(handle);
}
}

View File

@@ -14,11 +14,10 @@ export class ExtHostLanguages {
constructor(
mainContext: IMainContext
) {
this._proxy = mainContext.get(MainContext.MainThreadLanguages);
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguages);
}
getLanguages(): TPromise<string[]> {
return this._proxy.$getLanguages();
}
}

View File

@@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
* 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 { TPromise } from 'vs/base/common/winjs.base';
import { join } from 'vs/base/common/paths';
import { mkdirp, dirExists } from 'vs/base/node/pfs';
import Event from 'vs/base/common/event';
import { LogLevel } from 'vs/workbench/api/node/extHostTypes';
import { ILogService, DelegatedLogService } from 'vs/platform/log/common/log';
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { memoize } from 'vs/base/common/decorators';
import { ExtHostLogServiceShape } from 'vs/workbench/api/node/extHost.protocol';
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
private _loggers: Map<string, ExtHostLogger> = new Map();
constructor(
private _windowId: number,
logLevel: LogLevel,
private _environmentService: IEnvironmentService
) {
super(createSpdLogService(`exthost${_windowId}`, logLevel, _environmentService.logsPath));
}
$setLevel(level: LogLevel): void {
this.setLevel(level);
}
getExtLogger(extensionID: string): ExtHostLogger {
let logger = this._loggers.get(extensionID);
if (!logger) {
logger = this.createLogger(extensionID);
this._loggers.set(extensionID, logger);
}
return logger;
}
private createLogger(extensionID: string): ExtHostLogger {
const logsDirPath = join(this._environmentService.logsPath, `${extensionID}_${this._windowId}`);
const logService = createSpdLogService(extensionID, this.getLevel(), logsDirPath);
this._register(this.onDidChangeLogLevel(level => logService.setLevel(level)));
return new ExtHostLogger(logService, logsDirPath);
}
}
export class ExtHostLogger implements vscode.Logger {
constructor(
private readonly _logService: ILogService,
private readonly _logDirectory: string
) {
}
get onDidChangeLogLevel(): Event<LogLevel> {
return this._logService.onDidChangeLogLevel;
}
get currentLevel(): LogLevel { return this._logService.getLevel(); }
@memoize
get logDirectory(): TPromise<string> {
return dirExists(this._logDirectory).then(exists => {
if (exists) {
return TPromise.wrap(null);
} else {
return mkdirp(this._logDirectory);
}
}).then(() => {
return this._logDirectory;
});
}
trace(message: string, ...args: any[]): void {
return this._logService.trace(message, ...args);
}
debug(message: string, ...args: any[]): void {
return this._logService.debug(message, ...args);
}
info(message: string, ...args: any[]): void {
return this._logService.info(message, ...args);
}
warn(message: string, ...args: any[]): void {
return this._logService.warn(message, ...args);
}
error(message: string | Error, ...args: any[]): void {
return this._logService.error(message, ...args);
}
critical(message: string | Error, ...args: any[]): void {
return this._logService.critical(message, ...args);
}
}

View File

@@ -7,7 +7,7 @@
import Severity from 'vs/base/common/severity';
import vscode = require('vscode');
import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
function isMessageItem(item: any): item is vscode.MessageItem {
return item && item.title;
@@ -18,7 +18,7 @@ export class ExtHostMessageService {
private _proxy: MainThreadMessageServiceShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadMessageService);
this._proxy = mainContext.getProxy(MainContext.MainThreadMessageService);
}
showMessage(extension: IExtensionDescription, severity: Severity, message: string, optionsOrFirstItem: vscode.MessageOptions | string, rest: string[]): Thenable<string | undefined>;

View File

@@ -35,18 +35,22 @@ export class ExtHostOutputChannel implements vscode.OutputChannel {
}
append(value: string): void {
this.validate();
this._proxy.$append(this._id, this._name, value);
}
appendLine(value: string): void {
this.validate();
this.append(value + '\n');
}
clear(): void {
this.validate();
this._proxy.$clear(this._id, this._name);
}
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
this.validate();
if (typeof columnOrPreserveFocus === 'boolean') {
preserveFocus = columnOrPreserveFocus;
}
@@ -55,8 +59,15 @@ export class ExtHostOutputChannel implements vscode.OutputChannel {
}
hide(): void {
this.validate();
this._proxy.$close(this._id);
}
private validate(): void {
if (this._disposed) {
throw new Error('Channel has been closed');
}
}
}
export class ExtHostOutputService {
@@ -64,7 +75,7 @@ export class ExtHostOutputService {
private _proxy: MainThreadOutputServiceShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadOutputService);
this._proxy = mainContext.getProxy(MainContext.MainThreadOutputService);
}
createOutputChannel(name: string): vscode.OutputChannel {

View File

@@ -7,7 +7,7 @@
import { Progress, ProgressOptions, CancellationToken } from 'vscode';
import { MainThreadProgressShape } from './extHost.protocol';
import { ProgressLocation } from './extHostTypeConverters';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { IProgressStep } from 'vs/platform/progress/common/progress';
export class ExtHostProgress {

View File

@@ -24,7 +24,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
private _validateInput: (input: string) => string | Thenable<string>;
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) {
this._proxy = mainContext.get(MainContext.MainThreadQuickOpen);
this._proxy = mainContext.getProxy(MainContext.MainThreadQuickOpen);
this._workspace = workspace;
this._commands = commands;
}

View File

@@ -4,15 +4,15 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
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 { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext } from './extHost.protocol';
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape } from './extHost.protocol';
import { sortedDiff } from 'vs/base/common/arrays';
import { comparePaths } from 'vs/base/common/comparers';
import * as vscode from 'vscode';
@@ -93,7 +93,7 @@ function compareResourceStatesDecorations(a: vscode.SourceControlResourceDecorat
}
function compareResourceStates(a: vscode.SourceControlResourceState, b: vscode.SourceControlResourceState): number {
let result = comparePaths(a.resourceUri.fsPath, b.resourceUri.fsPath);
let result = comparePaths(a.resourceUri.fsPath, b.resourceUri.fsPath, true);
if (result !== 0) {
return result;
@@ -110,7 +110,11 @@ function compareResourceStates(a: vscode.SourceControlResourceState, b: vscode.S
return result;
}
export class ExtHostSCMInputBox {
export interface IValidateInput {
(value: string, cursorPosition: number): vscode.ProviderResult<vscode.SourceControlInputBoxValidation | undefined | null>;
}
export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
private _value: string = '';
@@ -140,7 +144,31 @@ export class ExtHostSCMInputBox {
this._placeholder = placeholder;
}
constructor(private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) {
private _validateInput: IValidateInput;
get validateInput(): IValidateInput {
if (!this._extension.enableProposedApi) {
throw new Error(`[${this._extension.id}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${this._extension.id}`);
}
return this._validateInput;
}
set validateInput(fn: IValidateInput) {
if (!this._extension.enableProposedApi) {
throw new Error(`[${this._extension.id}]: Proposed API is only available when running out of dev or with the following command line switch: --enable-proposed-api ${this._extension.id}`);
}
if (fn && typeof fn !== 'function') {
console.warn('Invalid SCM input box validation function');
return;
}
this._validateInput = fn;
this._proxy.$setValidationProviderIsEnabled(this._sourceControlHandle, !!fn);
}
constructor(private _extension: IExtensionDescription, private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) {
// noop
}
@@ -228,7 +256,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const handle = this._resourceHandlePool++;
this._resourceStatesMap.set(handle, r);
const sourceUri = r.resourceUri.toString();
const sourceUri = r.resourceUri;
const iconPath = getIconPath(r.decorations);
const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath;
const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath;
@@ -254,7 +282,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const letter = r.decorations && r.decorations.letter || undefined;
const color = r.decorations && r.decorations.color || undefined;
const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource;
const rawResource = [handle, <UriComponents>sourceUri, icons, tooltip, strikeThrough, faded, source, letter, color] as SCMRawResource;
return { rawResource, handle };
});
@@ -370,14 +398,15 @@ class ExtHostSourceControl implements vscode.SourceControl {
private handle: number = ExtHostSourceControl._handlePool++;
constructor(
_extension: IExtensionDescription,
private _proxy: MainThreadSCMShape,
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, _rootUri && _rootUri.toString());
this._inputBox = new ExtHostSCMInputBox(_extension, this._proxy, this.handle);
this._proxy.$registerSourceControl(this.handle, _id, _label, _rootUri);
}
private updatedResourceGroups = new Set<ExtHostSourceControlResourceGroup>();
@@ -431,7 +460,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
}
}
export class ExtHostSCM {
export class ExtHostSCM implements ExtHostSCMShape {
private static _handlePool: number = 0;
@@ -447,7 +476,7 @@ export class ExtHostSCM {
private _commands: ExtHostCommands,
@ILogService private logService: ILogService
) {
this._proxy = mainContext.get(MainContext.MainThreadSCM);
this._proxy = mainContext.getProxy(MainContext.MainThreadSCM);
_commands.registerArgumentProcessor({
processArgument: arg => {
@@ -492,7 +521,7 @@ export class ExtHostSCM {
this.logService.trace('ExtHostSCM#createSourceControl', extension.id, id, label, rootUri);
const handle = ExtHostSCM._handlePool++;
const sourceControl = new ExtHostSourceControl(this._proxy, this._commands, id, label, rootUri);
const sourceControl = new ExtHostSourceControl(extension, this._proxy, this._commands, id, label, rootUri);
this._sourceControls.set(handle, sourceControl);
const sourceControls = this._sourceControlsByExtension.get(extension.id) || [];
@@ -513,8 +542,9 @@ export class ExtHostSCM {
return inputBox;
}
$provideOriginalResource(sourceControlHandle: number, uri: URI): TPromise<URI> {
this.logService.trace('ExtHostSCM#$provideOriginalResource', sourceControlHandle, uri);
$provideOriginalResource(sourceControlHandle: number, uriComponents: UriComponents): TPromise<UriComponents> {
const uri = URI.revive(uriComponents);
this.logService.trace('ExtHostSCM#$provideOriginalResource', sourceControlHandle, uri.toString());
const sourceControl = this._sourceControls.get(sourceControlHandle);
@@ -522,10 +552,7 @@ export class ExtHostSCM {
return TPromise.as(null);
}
return asWinJsPromise(token => {
const result = sourceControl.quickDiffProvider.provideOriginalResource(uri, token);
return result && URI.parse(result.toString());
});
return asWinJsPromise(token => sourceControl.quickDiffProvider.provideOriginalResource(uri, token));
}
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void> {
@@ -558,4 +585,26 @@ export class ExtHostSCM {
await group.$executeResourceCommand(handle);
}
async $validateInput(sourceControlHandle: number, value: string, cursorPosition: number): TPromise<[string, number] | undefined> {
this.logService.trace('ExtHostSCM#$validateInput', sourceControlHandle);
const sourceControl = this._sourceControls.get(sourceControlHandle);
if (!sourceControl) {
return TPromise.as(undefined);
}
if (!sourceControl.inputBox.validateInput) {
return TPromise.as(undefined);
}
const result = await sourceControl.inputBox.validateInput(value, cursorPosition);
if (!result) {
return TPromise.as(undefined);
}
return [result.message, result.type];
}
}

View File

@@ -163,7 +163,7 @@ export class ExtHostStatusBar {
private _statusMessage: StatusBarMessage;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadStatusBar);
this._proxy = mainContext.getProxy(MainContext.MainThreadStatusBar);
this._statusMessage = new StatusBarMessage(this);
}

View File

@@ -12,7 +12,7 @@ export class ExtHostStorage {
private _proxy: MainThreadStorageShape;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.get(MainContext.MainThreadStorage);
this._proxy = mainContext.getProxy(MainContext.MainThreadStorage);
}
getValue<T>(shared: boolean, key: string, defaultValue?: T): TPromise<T> {
@@ -22,4 +22,4 @@ export class ExtHostStorage {
setValue(shared: boolean, key: string, value: any): TPromise<void> {
return this._proxy.$setValue(shared, key, value);
}
}
}

View File

@@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import * as Objects from 'vs/base/common/objects';
import { asWinJsPromise } from 'vs/base/common/async';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import * as TaskSystem from 'vs/workbench/parts/tasks/common/tasks';
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
@@ -294,11 +294,11 @@ namespace ShellConfiguration {
namespace Tasks {
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.Task[] {
export function from(tasks: vscode.Task[], rootFolder: vscode.WorkspaceFolder, extension: IExtensionDescription): TaskSystem.ContributedTask[] {
if (tasks === void 0 || tasks === null) {
return [];
}
let result: TaskSystem.Task[] = [];
let result: TaskSystem.ContributedTask[] = [];
for (let task of tasks) {
let converted = fromSingle(task, rootFolder, extension);
if (converted) {
@@ -351,7 +351,7 @@ namespace Tasks {
// We can't transfer a workspace folder object from the extension host to main since they differ
// in shape and we don't have backwards converting function. So transfer the URI and resolve the
// workspace folder on the main side.
(source as any).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
(source as any as TaskSystem.ExtensionTaskSourceTransfer).__workspaceFolder = workspaceFolder ? workspaceFolder.uri as URI : undefined;
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let key = (task as types.Task).definitionKey;
let kind = (task as types.Task).definition;
@@ -424,7 +424,7 @@ export class ExtHostTask implements ExtHostTaskShape {
private _handlers: Map<number, HandlerData>;
constructor(mainContext: IMainContext, extHostWorkspace: ExtHostWorkspace) {
this._proxy = mainContext.get(MainContext.MainThreadTask);
this._proxy = mainContext.getProxy(MainContext.MainThreadTask);
this._extHostWorkspace = extHostWorkspace;
this._handleCounter = 0;
this._handlers = new Map<number, HandlerData>();

View File

@@ -5,7 +5,6 @@
'use strict';
import vscode = require('vscode');
import { TPromise, TValueCallback } from 'vs/base/common/winjs.base';
import Event, { Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext } from './extHost.protocol';
@@ -16,24 +15,26 @@ export class ExtHostTerminal implements vscode.Terminal {
private _proxy: MainThreadTerminalServiceShape;
private _disposed: boolean;
private _queuedRequests: ApiRequest[];
private _pidPromise: TPromise<number>;
private _pidPromiseComplete: TValueCallback<number>;
private _pidPromise: Promise<number>;
private _pidPromiseComplete: (value: number) => any;
constructor(
proxy: MainThreadTerminalServiceShape,
name?: string,
shellPath?: string,
shellArgs?: string[],
cwd?: string,
env?: { [key: string]: string },
waitOnExit?: boolean
) {
this._name = name;
this._queuedRequests = [];
this._proxy = proxy;
this._pidPromise = new TPromise<number>(c => {
this._pidPromise = new Promise<number>(c => {
this._pidPromiseComplete = c;
});
this._proxy.$createTerminal(name, shellPath, shellArgs, env, waitOnExit).then((id) => {
this._proxy.$createTerminal(name, shellPath, shellArgs, cwd, env, waitOnExit).then((id) => {
this._id = id;
this._queuedRequests.forEach((r) => {
r.run(this._proxy, this._id);
@@ -103,7 +104,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
constructor(mainContext: IMainContext) {
this._onDidCloseTerminal = new Emitter<vscode.Terminal>();
this._proxy = mainContext.get(MainContext.MainThreadTerminalService);
this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService);
this._terminals = [];
}
@@ -114,7 +115,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.env/*, options.waitOnExit*/);
let terminal = new ExtHostTerminal(this._proxy, options.name, options.shellPath, options.shellArgs, options.cwd, options.env /*, options.waitOnExit*/);
this._terminals.push(terminal);
return terminal;
}
@@ -172,4 +173,4 @@ class ApiRequest {
public run(proxy: MainThreadTerminalServiceShape, id: number) {
this._callback.apply(proxy, [id].concat(this._args));
}
}
}

View File

@@ -11,9 +11,9 @@ 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 { ISingleEditOperation } from 'vs/editor/common/model';
import * as TypeConverters from './extHostTypeConverters';
import { MainThreadEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from './extHost.protocol';
import { MainThreadTextEditorsShape, 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';
@@ -22,10 +22,10 @@ export class TextEditorDecorationType implements vscode.TextEditorDecorationType
private static readonly _Keys = new IdGenerator('TextEditorDecorationType');
private _proxy: MainThreadEditorsShape;
private _proxy: MainThreadTextEditorsShape;
public key: string;
constructor(proxy: MainThreadEditorsShape, options: vscode.DecorationRenderOptions) {
constructor(proxy: MainThreadTextEditorsShape, options: vscode.DecorationRenderOptions) {
this.key = TextEditorDecorationType._Keys.nextId();
this._proxy = proxy;
this._proxy.$registerTextEditorDecorationType(this.key, <any>/* URI vs Uri */ options);
@@ -141,7 +141,7 @@ function deprecated(name: string, message: string = 'Refer to the documentation
export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
private _proxy: MainThreadEditorsShape;
private _proxy: MainThreadTextEditorsShape;
private _id: string;
private _tabSize: number;
@@ -149,7 +149,7 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
private _cursorStyle: TextEditorCursorStyle;
private _lineNumbers: TextEditorLineNumbersStyle;
constructor(proxy: MainThreadEditorsShape, id: string, source: IResolvedTextEditorConfiguration) {
constructor(proxy: MainThreadTextEditorsShape, id: string, source: IResolvedTextEditorConfiguration) {
this._proxy = proxy;
this._id = id;
this._accept(source);
@@ -313,23 +313,31 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
export class ExtHostTextEditor implements vscode.TextEditor {
private readonly _proxy: MainThreadEditorsShape;
public readonly editorType = 'texteditor';
private readonly _proxy: MainThreadTextEditorsShape;
private readonly _id: string;
private readonly _documentData: ExtHostDocumentData;
private _selections: Selection[];
private _options: ExtHostTextEditorOptions;
private _visibleRanges: Range[];
private _viewColumn: vscode.ViewColumn;
private _disposed: boolean = false;
get id(): string { return this._id; }
constructor(proxy: MainThreadEditorsShape, id: string, document: ExtHostDocumentData, selections: Selection[], options: IResolvedTextEditorConfiguration, viewColumn: vscode.ViewColumn) {
constructor(
proxy: MainThreadTextEditorsShape, id: string, document: ExtHostDocumentData,
selections: Selection[], options: IResolvedTextEditorConfiguration,
visibleRanges: Range[], viewColumn: vscode.ViewColumn
) {
this._proxy = proxy;
this._id = id;
this._documentData = document;
this._selections = selections;
this._options = new ExtHostTextEditorOptions(this._proxy, this._id, options);
this._visibleRanges = visibleRanges;
this._viewColumn = viewColumn;
}
@@ -373,6 +381,21 @@ export class ExtHostTextEditor implements vscode.TextEditor {
this._options._accept(options);
}
// ---- visible ranges
get visibleRanges(): Range[] {
return this._visibleRanges;
}
set visibleRanges(value: Range[]) {
throw readonly('visibleRanges');
}
_acceptVisibleRanges(value: Range[]): void {
ok(!this._disposed);
this._visibleRanges = value;
}
// ---- view column
get viewColumn(): vscode.ViewColumn {
@@ -435,7 +458,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
return this._proxy.$trySetDecorationsFast(
this._id,
decorationType.key,
/*TODO: marshaller is too slow*/JSON.stringify(_ranges)
_ranges
);
}
}

View File

@@ -12,32 +12,34 @@ import * as TypeConverters from './extHostTypeConverters';
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
import { MainContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IResolvedTextEditorConfiguration, ISelectionChangeEvent, IMainContext, IWorkspaceResourceEdit } from './extHost.protocol';
import { MainContext, MainThreadTextEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IMainContext, WorkspaceEditDto, IEditorPropertiesChangeData } from './extHost.protocol';
import * as vscode from 'vscode';
export class ExtHostEditors implements ExtHostEditorsShape {
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>();
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>();
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<vscode.TextEditor[]>();
readonly onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
readonly onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent> = this._onDidChangeTextEditorOptions.event;
readonly onDidChangeTextEditorVisibleRanges: Event<vscode.TextEditorVisibleRangesChangeEvent> = this._onDidChangeTextEditorVisibleRanges.event;
readonly onDidChangeTextEditorViewColumn: Event<vscode.TextEditorViewColumnChangeEvent> = this._onDidChangeTextEditorViewColumn.event;
readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
readonly onDidChangeVisibleTextEditors: Event<vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
private _proxy: MainThreadEditorsShape;
private _proxy: MainThreadTextEditorsShape;
private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
constructor(
mainContext: IMainContext,
extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
) {
this._proxy = mainContext.get(MainContext.MainThreadEditors);
this._proxy = mainContext.getProxy(MainContext.MainThreadTextEditors);
this._extHostDocumentsAndEditors = extHostDocumentsAndEditors;
this._extHostDocumentsAndEditors.onDidChangeVisibleTextEditors(e => this._onDidChangeVisibleTextEditors.fire(e));
@@ -92,59 +94,66 @@ export class ExtHostEditors implements ExtHostEditorsShape {
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
let workspaceResourceEdits: IWorkspaceResourceEdit[] = [];
const dto: WorkspaceEditDto = { edits: [] };
let entries = edit.entries();
for (let entry of entries) {
let [uri, edits] = entry;
let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString());
let docVersion: number = undefined;
if (doc) {
docVersion = doc.version;
}
let workspaceResourceEdit: IWorkspaceResourceEdit = {
resource: uri,
modelVersionId: docVersion,
edits: []
};
for (let edit of edits) {
workspaceResourceEdit.edits.push({
newText: edit.newText,
newEol: TypeConverters.EndOfLine.from(edit.newEol),
range: edit.range && TypeConverters.fromRange(edit.range)
for (let entry of edit.entries()) {
let [uri, uriOrEdits] = entry;
if (Array.isArray(uriOrEdits)) {
let doc = this._extHostDocumentsAndEditors.getDocument(uri.toString());
dto.edits.push({
resource: uri,
modelVersionId: doc && doc.version,
edits: uriOrEdits.map(TypeConverters.TextEdit.from)
});
// } else {
// dto.edits.push({ oldUri: uri, newUri: uriOrEdits });
}
workspaceResourceEdits.push(workspaceResourceEdit);
}
return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits);
return this._proxy.$tryApplyWorkspaceEdit(dto);
}
// --- called from main thread
$acceptOptionsChanged(id: string, opts: IResolvedTextEditorConfiguration): void {
let editor = this._extHostDocumentsAndEditors.getEditor(id);
editor._acceptOptions(opts);
this._onDidChangeTextEditorOptions.fire({
textEditor: editor,
options: opts
});
}
$acceptSelectionsChanged(id: string, event: ISelectionChangeEvent): void {
const kind = TextEditorSelectionChangeKind.fromValue(event.source);
const selections = event.selections.map(TypeConverters.toSelection);
$acceptEditorPropertiesChanged(id: string, data: IEditorPropertiesChangeData): void {
const textEditor = this._extHostDocumentsAndEditors.getEditor(id);
textEditor._acceptSelections(selections);
this._onDidChangeTextEditorSelection.fire({
textEditor,
selections,
kind
});
// (1) set all properties
if (data.options) {
textEditor._acceptOptions(data.options);
}
if (data.selections) {
const selections = data.selections.selections.map(TypeConverters.toSelection);
textEditor._acceptSelections(selections);
}
if (data.visibleRanges) {
const visibleRanges = data.visibleRanges.map(TypeConverters.toRange);
textEditor._acceptVisibleRanges(visibleRanges);
}
// (2) fire change events
if (data.options) {
this._onDidChangeTextEditorOptions.fire({
textEditor: textEditor,
options: data.options
});
}
if (data.selections) {
const kind = TextEditorSelectionChangeKind.fromValue(data.selections.source);
const selections = data.selections.selections.map(TypeConverters.toSelection);
this._onDidChangeTextEditorSelection.fire({
textEditor,
selections,
kind
});
}
if (data.visibleRanges) {
const visibleRanges = data.visibleRanges.map(TypeConverters.toRange);
this._onDidChangeTextEditorVisibleRanges.fire({
textEditor,
visibleRanges
});
}
}
$acceptEditorPositionData(data: ITextEditorPositionData): void {

View File

@@ -6,6 +6,7 @@
import { localize } from 'vs/nls';
import * as vscode from 'vscode';
import { basename } from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { debounceEvent } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -14,6 +15,8 @@ import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.proto
import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
import { TreeItemCollapsibleState, ThemeIcon } from 'vs/workbench/api/node/extHostTypes';
import { isUndefinedOrNull } from 'vs/base/common/types';
type TreeItemHandle = string;
@@ -35,10 +38,12 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
});
}
registerTreeDataProvider<T>(id: string, treeDataProvider: vscode.TreeDataProvider<T>): vscode.Disposable {
const treeView = new ExtHostTreeView<T>(id, treeDataProvider, this._proxy, this.commands.converter);
this.treeViews.set(id, treeView);
registerTreeDataProvider<T>(id: string, dataProvider: vscode.TreeDataProvider<T>, proposedApiFunction: <U>(fn: U) => U): vscode.TreeView<T> {
const treeView = this.createExtHostTreeViewer(id, dataProvider);
return {
reveal: proposedApiFunction((element: T, options?: { select?: boolean }): Thenable<void> => {
return treeView.reveal(element, options);
}),
dispose: () => {
this.treeViews.delete(id);
treeView.dispose();
@@ -46,14 +51,6 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
};
}
$getElements(treeViewId: string): TPromise<ITreeItem[]> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
return TPromise.wrapError<ITreeItem[]>(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
}
return treeView.getTreeItems();
}
$getChildren(treeViewId: string, treeItemHandle?: string): TPromise<ITreeItem[]> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
@@ -62,6 +59,12 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
return treeView.getChildren(treeItemHandle);
}
private createExtHostTreeViewer<T>(id: string, dataProvider: vscode.TreeDataProvider<T>): ExtHostTreeView<T> {
const treeView = new ExtHostTreeView<T>(id, dataProvider, this._proxy, this.commands.converter);
this.treeViews.set(id, treeView);
return treeView;
}
private convertArgument(arg: TreeViewItemHandleArg): any {
const treeView = this.treeViews.get(arg.$treeViewId);
return treeView ? treeView.getExtensionElement(arg.$treeItemHandle) : null;
@@ -69,124 +72,254 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
}
interface TreeNode {
index: number;
handle: TreeItemHandle;
parent: TreeItemHandle;
children: TreeItemHandle[];
item: ITreeItem;
parent: TreeNode;
children: TreeNode[];
}
class ExtHostTreeView<T> extends Disposable {
private static ROOT_HANDLE = '0';
private static LABEL_HANDLE_PREFIX = '0';
private static ID_HANDLE_PREFIX = '1';
private roots: TreeNode[] = null;
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
private nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter) {
super();
this.proxy.$registerView(viewId);
if (dataProvider.onDidChangeTreeData) {
this._register(debounceEvent<T, T[]>(dataProvider.onDidChangeTreeData, (last, current) => last ? [...last, current] : [current], 200)(elements => this._refresh(elements)));
this.proxy.$registerTreeViewDataProvider(viewId);
if (this.dataProvider.onDidChangeTreeData) {
this._register(debounceEvent<T, T[]>(this.dataProvider.onDidChangeTreeData, (last, current) => last ? [...last, current] : [current], 200)(elements => this.refresh(elements)));
}
}
getTreeItems(): TPromise<ITreeItem[]> {
this.clearAll();
return asWinJsPromise(() => this.dataProvider.getChildren())
.then(elements => this.resolveElements(elements));
}
getChildren(treeItemHandle: TreeItemHandle): TPromise<ITreeItem[]> {
let extElement = this.getExtensionElement(treeItemHandle);
if (extElement) {
this.clearChildren(extElement);
} else {
return TPromise.wrapError<ITreeItem[]>(new Error(localize('treeItem.notFound', 'No tree item with id \'{0}\' found.', treeItemHandle)));
getChildren(parentHandle?: TreeItemHandle): TPromise<ITreeItem[]> {
const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : void 0;
if (parentHandle && !parentElement) {
console.error(`No tree item with id \'${parentHandle}\' found.`);
return TPromise.as([]);
}
return asWinJsPromise(() => this.dataProvider.getChildren(extElement))
.then(childrenElements => this.resolveElements(childrenElements, treeItemHandle))
.then(childrenItems => {
this.nodes.get(extElement).children = childrenItems.map(c => c.handle);
return childrenItems;
});
const childrenNodes = this.getChildrenNodes(parentHandle); // Get it from cache
return (childrenNodes ? TPromise.as(childrenNodes) : this.fetchChildrenNodes(parentElement))
.then(nodes => nodes.map(n => n.item));
}
getExtensionElement(treeItemHandle: TreeItemHandle): T {
return this.elements.get(treeItemHandle);
}
private _refresh(elements: T[]): void {
reveal(element: T, options?: { select?: boolean }): TPromise<void> {
if (typeof this.dataProvider.getParent !== 'function') {
return TPromise.wrapError(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' mehtod`));
}
return this.resolveUnknownParentChain(element)
.then(parentChain => this.resolveTreeNode(element, parentChain[parentChain.length - 1])
.then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), options)));
}
private resolveUnknownParentChain(element: T): TPromise<TreeNode[]> {
return this.resolveParent(element)
.then((parent) => {
if (!parent) {
return TPromise.as([]);
}
return this.resolveUnknownParentChain(parent)
.then(result => this.resolveTreeNode(parent, result[result.length - 1])
.then(parentNode => {
result.push(parentNode);
return result;
}));
});
}
private resolveParent(element: T): TPromise<T> {
const node = this.nodes.get(element);
if (node) {
return TPromise.as(node.parent ? this.elements.get(node.parent.item.handle) : null);
}
return asWinJsPromise(() => this.dataProvider.getParent(element));
}
private resolveTreeNode(element: T, parent?: TreeNode): TPromise<TreeNode> {
return asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => this.createHandle(element, extTreeItem, parent))
.then(handle => this.getChildren(parent ? parent.item.handle : null)
.then(() => {
const cachedElement = this.getExtensionElement(handle);
if (cachedElement) {
const node = this.nodes.get(cachedElement);
if (node) {
return TPromise.as(node);
}
}
throw new Error(`Cannot resolve tree item for element ${handle}`);
}));
}
private getChildrenNodes(parentNodeOrHandle?: TreeNode | TreeItemHandle): TreeNode[] {
if (parentNodeOrHandle) {
let parentNode: TreeNode;
if (typeof parentNodeOrHandle === 'string') {
const parentElement = this.getExtensionElement(parentNodeOrHandle);
parentNode = parentElement ? this.nodes.get(parentElement) : null;
} else {
parentNode = parentNodeOrHandle;
}
return parentNode ? parentNode.children : null;
}
return this.roots;
}
private fetchChildrenNodes(parentElement?: T): TPromise<TreeNode[]> {
// clear children cache
this.clearChildren(parentElement);
const parentNode = parentElement ? this.nodes.get(parentElement) : void 0;
return asWinJsPromise(() => this.dataProvider.getChildren(parentElement))
.then(elements => TPromise.join(
(elements || [])
.filter(element => !!element)
.map(element => asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => extTreeItem ? this.createAndRegisterTreeNode(element, extTreeItem, parentNode) : null))))
.then(nodes => nodes.filter(n => !!n));
}
private refresh(elements: T[]): void {
const hasRoot = elements.some(element => !element);
if (hasRoot) {
this.clearAll(); // clear cache
this.proxy.$refresh(this.viewId);
} else {
const handlesToUpdate = this.getHandlesToUpdate(elements);
if (handlesToUpdate.length) {
this._refreshHandles(handlesToUpdate);
const handlesToRefresh = this.getHandlesToRefresh(elements);
if (handlesToRefresh.length) {
this.refreshHandles(handlesToRefresh);
}
}
}
private resolveElements(elements: T[], parentHandle?: TreeItemHandle): TPromise<ITreeItem[]> {
if (elements && elements.length) {
return TPromise.join(
elements.filter(element => !!element)
.map((element, index) => {
return this.resolveElement(element, index, parentHandle)
.then(treeItem => {
if (treeItem) {
this.nodes.set(element, {
index,
handle: treeItem.handle,
parent: parentHandle,
children: void 0
});
if (this.elements.has(treeItem.handle)) {
return TPromise.wrapError<ITreeItem>(new Error(localize('treeView.duplicateElement', 'Element {0} is already registered', element)));
}
this.elements.set(treeItem.handle, element);
}
return treeItem;
});
}))
.then(treeItems => treeItems.filter(treeItem => !!treeItem));
private getHandlesToRefresh(elements: T[]): TreeItemHandle[] {
const elementsToUpdate = new Set<TreeItemHandle>();
for (const element of elements) {
let elementNode = this.nodes.get(element);
if (elementNode && !elementsToUpdate.has(elementNode.item.handle)) {
// check if an ancestor of extElement is already in the elements to update list
let currentNode = elementNode;
while (currentNode && currentNode.parent && !elementsToUpdate.has(currentNode.parent.item.handle)) {
const parentElement = this.elements.get(currentNode.parent.item.handle);
currentNode = this.nodes.get(parentElement);
}
if (!currentNode.parent) {
elementsToUpdate.add(elementNode.item.handle);
}
}
}
return TPromise.as([]);
const handlesToUpdate: TreeItemHandle[] = [];
// Take only top level elements
elementsToUpdate.forEach((handle) => {
const element = this.elements.get(handle);
let node = this.nodes.get(element);
if (node && (!node.parent || !elementsToUpdate.has(node.parent.item.handle))) {
handlesToUpdate.push(handle);
}
});
return handlesToUpdate;
}
private resolveElement(element: T, index: number, parentHandle?: TreeItemHandle): TPromise<ITreeItem> {
return asWinJsPromise(() => this.dataProvider.getTreeItem(element))
.then(extTreeItem => this.massageTreeItem(element, extTreeItem, index, parentHandle));
private refreshHandles(itemHandles: TreeItemHandle[]): TPromise<void> {
const itemsToRefresh: { [treeItemHandle: string]: ITreeItem } = {};
return TPromise.join(itemHandles.map(treeItemHandle =>
this.refreshNode(treeItemHandle)
.then(node => {
if (node) {
itemsToRefresh[treeItemHandle] = node.item;
}
})))
.then(() => Object.keys(itemsToRefresh).length ? this.proxy.$refresh(this.viewId, itemsToRefresh) : null);
}
private massageTreeItem(element: T, extensionTreeItem: vscode.TreeItem, index: number, parentHandle: TreeItemHandle): ITreeItem {
if (!extensionTreeItem) {
return null;
private refreshNode(treeItemHandle: TreeItemHandle): TPromise<TreeNode> {
const extElement = this.getExtensionElement(treeItemHandle);
const existing = this.nodes.get(extElement);
this.clearChildren(extElement); // clear children cache
return asWinJsPromise(() => this.dataProvider.getTreeItem(extElement))
.then(extTreeItem => {
if (extTreeItem) {
const newNode = this.createTreeNode(extElement, extTreeItem, existing.parent);
this.updateNodeCache(extElement, newNode, existing, existing.parent);
return newNode;
}
return null;
});
}
private createAndRegisterTreeNode(element: T, extTreeItem: vscode.TreeItem, parentNode: TreeNode): TreeNode {
const node = this.createTreeNode(element, extTreeItem, parentNode);
if (extTreeItem.id && this.elements.has(node.item.handle)) {
throw new Error(localize('treeView.duplicateElement', 'Element with id {0} is already registered', extTreeItem.id));
}
const icon = this.getLightIconPath(extensionTreeItem);
const label = extensionTreeItem.label;
const handle = typeof element === 'string' ? element : this.generateHandle(label, index, parentHandle);
this.addNodeToCache(element, node);
this.addNodeToParentCache(node, parentNode);
return node;
}
private createTreeNode(element: T, extensionTreeItem: vscode.TreeItem, parent: TreeNode): TreeNode {
return {
item: this.createTreeItem(element, extensionTreeItem, parent),
parent,
children: void 0
};
}
private createTreeItem(element: T, extensionTreeItem: vscode.TreeItem, parent?: TreeNode): ITreeItem {
const handle = this.createHandle(element, extensionTreeItem, parent);
const icon = this.getLightIconPath(extensionTreeItem);
const item = {
handle,
parentHandle,
label,
parentHandle: parent ? parent.item.handle : void 0,
label: extensionTreeItem.label,
resourceUri: extensionTreeItem.resourceUri,
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : void 0,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
collapsibleState: extensionTreeItem.collapsibleState
themeIcon: extensionTreeItem.iconPath instanceof ThemeIcon ? { id: extensionTreeItem.iconPath.id } : void 0,
collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState
};
return item;
}
private generateHandle(label: string, index: number, parentHandle: TreeItemHandle): TreeItemHandle {
parentHandle = parentHandle ? parentHandle : ExtHostTreeView.ROOT_HANDLE;
label = label.indexOf('/') !== -1 ? label.replace('/', '//') : label;
return `${parentHandle}/${index}:${label}`;
private createHandle(element: T, { id, label, resourceUri }: vscode.TreeItem, parent?: TreeNode): TreeItemHandle {
if (id) {
return `${ExtHostTreeView.ID_HANDLE_PREFIX}/${id}`;
}
const prefix: string = parent ? parent.item.handle : ExtHostTreeView.LABEL_HANDLE_PREFIX;
let elementId = label ? label : resourceUri ? basename(resourceUri.path) : '';
elementId = elementId.indexOf('/') !== -1 ? elementId.replace('/', '//') : elementId;
const existingHandle = this.nodes.has(element) ? this.nodes.get(element).item.handle : void 0;
const childrenNodes = (this.getChildrenNodes(parent) || []);
for (let counter = 0; counter <= childrenNodes.length; counter++) {
const handle = `${prefix}/${counter}:${elementId}`;
if (!this.elements.has(handle) || existingHandle === handle) {
return handle;
}
}
throw new Error('This should not be reached');
}
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon)) {
if (typeof extensionTreeItem.iconPath === 'string'
|| extensionTreeItem.iconPath instanceof URI) {
return this.getIconPath(extensionTreeItem.iconPath);
}
return this.getIconPath(extensionTreeItem.iconPath['light']);
@@ -195,7 +328,7 @@ class ExtHostTreeView<T> extends Disposable {
}
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon) && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}
return void 0;
@@ -208,102 +341,77 @@ class ExtHostTreeView<T> extends Disposable {
return URI.file(iconPath).toString();
}
private getHandlesToUpdate(elements: T[]): TreeItemHandle[] {
const elementsToUpdate = new Set<TreeItemHandle>();
for (const element of elements) {
let elementNode = this.nodes.get(element);
if (elementNode && !elementsToUpdate.has(elementNode.handle)) {
// check if an ancestor of extElement is already in the elements to update list
let currentNode = elementNode;
while (currentNode && currentNode.parent && !elementsToUpdate.has(currentNode.parent)) {
const parentElement = this.elements.get(currentNode.parent);
currentNode = this.nodes.get(parentElement);
}
if (!currentNode.parent) {
elementsToUpdate.add(elementNode.handle);
}
}
}
const handlesToUpdate: TreeItemHandle[] = [];
// Take only top level elements
elementsToUpdate.forEach((handle) => {
const element = this.elements.get(handle);
let node = this.nodes.get(element);
if (node && !elementsToUpdate.has(node.parent)) {
handlesToUpdate.push(handle);
}
});
return handlesToUpdate;
private addNodeToCache(element: T, node: TreeNode): void {
this.elements.set(node.item.handle, element);
this.nodes.set(element, node);
}
private _refreshHandles(itemHandles: TreeItemHandle[]): TPromise<void> {
const itemsToRefresh: { [handle: string]: ITreeItem } = {};
const promises: TPromise<void>[] = [];
itemHandles.forEach(treeItemHandle => {
const extElement = this.getExtensionElement(treeItemHandle);
const node = this.nodes.get(extElement);
const promise = this.resolveElement(extElement, node.index, node.parent)
.then(treeItem => {
if (treeItemHandle !== treeItem.handle) {
// Update caches if handle changes
this.updateCaches(node, treeItem, extElement);
private updateNodeCache(element: T, newNode: TreeNode, existing: TreeNode, parentNode: TreeNode): void {
// Remove from the cache
this.elements.delete(newNode.item.handle);
this.nodes.delete(element);
if (newNode.item.handle !== existing.item.handle) {
this.elements.delete(existing.item.handle);
}
// Add the new node to the cache
this.addNodeToCache(element, newNode);
// Replace the node in parent's children nodes
const childrenNodes = (this.getChildrenNodes(parentNode) || []);
const childNode = childrenNodes.filter(c => c.item.handle === existing.item.handle)[0];
if (childNode) {
childrenNodes.splice(childrenNodes.indexOf(childNode), 1, newNode);
}
}
private addNodeToParentCache(node: TreeNode, parentNode: TreeNode): void {
if (parentNode) {
if (!parentNode.children) {
parentNode.children = [];
}
parentNode.children.push(node);
} else {
if (!this.roots) {
this.roots = [];
}
this.roots.push(node);
}
}
private clearChildren(parentElement?: T): void {
if (parentElement) {
let node = this.nodes.get(parentElement);
if (node.children) {
for (const child of node.children) {
const childEleement = this.elements.get(child.item.handle);
if (childEleement) {
this.clear(childEleement);
}
itemsToRefresh[treeItemHandle] = treeItem;
});
promises.push(promise);
});
return TPromise.join(promises)
.then(treeItems => {
this.proxy.$refresh(this.viewId, itemsToRefresh);
});
}
private updateCaches(node: TreeNode, treeItem: ITreeItem, element: T): void {
if (node.parent) {
// Update parent's children handles
const parentElement = this.getExtensionElement(node.parent);
const parentNode = this.nodes.get(parentElement);
parentNode.children[node.index] = treeItem.handle;
}
// Update elements map
this.elements.delete(node.handle);
this.elements.set(treeItem.handle, element);
// Update node
node.handle = treeItem.handle;
}
private clearChildren(element: T): void {
let node = this.nodes.get(element);
if (node.children) {
for (const childHandle of node.children) {
const childEleement = this.elements.get(childHandle);
if (childEleement) {
this.clear(childEleement);
}
}
node.children = [];
} else {
this.clearAll();
}
node.children = void 0;
}
private clear(element: T): void {
let node = this.nodes.get(element);
if (node.children) {
for (const childHandle of node.children) {
const childEleement = this.elements.get(childHandle);
for (const child of node.children) {
const childEleement = this.elements.get(child.item.handle);
if (childEleement) {
this.clear(childEleement);
}
}
}
this.nodes.delete(element);
this.elements.delete(node.handle);
this.elements.delete(node.item.handle);
}
private clearAll(): void {
this.roots = null;
this.elements.clear();
this.nodes.clear();
}

View File

@@ -8,7 +8,8 @@ import Severity from 'vs/base/common/severity';
import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IDecorationOptions, EndOfLineSequence } from 'vs/editor/common/editorCommon';
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
import { EndOfLineSequence } from 'vs/editor/common/model';
import * as vscode from 'vscode';
import URI from 'vs/base/common/uri';
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
@@ -19,6 +20,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
import * as htmlContent from 'vs/base/common/htmlContent';
import { IRelativePattern } from 'vs/base/common/glob';
import { LanguageSelector, LanguageFilter } from 'vs/editor/common/modes/languageSelector';
import { WorkspaceEditDto, ResourceTextEditDto } from 'vs/workbench/api/node/extHost.protocol';
export interface PositionLike {
line: number;
@@ -227,36 +229,36 @@ export const TextEdit = {
export namespace WorkspaceEdit {
export function from(value: vscode.WorkspaceEdit): modes.WorkspaceEdit {
const result: modes.WorkspaceEdit = { edits: [] };
for (let entry of value.entries()) {
let [uri, textEdits] = entry;
for (let textEdit of textEdits) {
result.edits.push({
resource: uri,
newText: textEdit.newText,
range: fromRange(textEdit.range)
});
const result: modes.WorkspaceEdit = {
edits: []
};
for (const entry of value.entries()) {
const [uri, uriOrEdits] = entry;
if (Array.isArray(uriOrEdits)) {
// text edits
result.edits.push({ resource: uri, edits: uriOrEdits.map(TextEdit.from) });
} else {
// resource edits
result.edits.push({ oldUri: uri, newUri: uriOrEdits });
}
}
return result;
}
export function fromTextEdits(uri: vscode.Uri, textEdits: vscode.TextEdit[]): modes.WorkspaceEdit {
const result: modes.WorkspaceEdit = { edits: [] };
for (let textEdit of textEdits) {
result.edits.push({
resource: uri,
newText: textEdit.newText,
range: fromRange(textEdit.range)
});
}
return result;
}
export function to(value: modes.WorkspaceEdit) {
export function to(value: WorkspaceEditDto) {
const result = new types.WorkspaceEdit();
for (const edit of value.edits) {
result.replace(edit.resource, toRange(edit.range), edit.newText);
if (Array.isArray((<ResourceTextEditDto>edit).edits)) {
result.set(
URI.revive((<ResourceTextEditDto>edit).resource),
<types.TextEdit[]>(<ResourceTextEditDto>edit).edits.map(TextEdit.to)
);
// } else {
// result.renameResource(
// URI.revive((<ResourceFileEditDto>edit).oldUri),
// URI.revive((<ResourceFileEditDto>edit).newUri)
// );
}
}
return result;
}
@@ -358,7 +360,8 @@ export namespace CompletionTriggerKind {
switch (kind) {
case modes.SuggestTriggerKind.TriggerCharacter:
return types.CompletionTriggerKind.TriggerCharacter;
case modes.SuggestTriggerKind.TriggerForIncompleteCompletions:
return types.CompletionTriggerKind.TriggerForIncompleteCompletions;
case modes.SuggestTriggerKind.Invoke:
default:
return types.CompletionTriggerKind.Invoke;
@@ -424,8 +427,7 @@ export namespace Suggest {
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.type);
result.detail = suggestion.detail;
// {{SQL CARBON EDIT}}
result.documentation = <string>suggestion.documentation;
result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation;
result.sortText = suggestion.sortText;
result.filterText = suggestion.filterText;
@@ -584,6 +586,14 @@ export namespace ProgressLocation {
}
}
export namespace FoldingRangeList {
export function from(rangeList: vscode.FoldingRangeList): modes.IFoldingRangeList {
return {
ranges: rangeList.ranges.map(r => ({ startLineNumber: r.startLine + 1, endLineNumber: r.endLine + 1, type: r.type }))
};
}
}
export function toTextEditorOptions(options?: vscode.TextDocumentShowOptions): ITextEditorOptions {
if (options) {
return {
@@ -601,11 +611,11 @@ export function toGlobPattern(pattern: vscode.GlobPattern): string | IRelativePa
return pattern;
}
if (!isRelativePattern(pattern)) {
return undefined;
if (isRelativePattern(pattern)) {
return new types.RelativePattern(pattern.base, pattern.pattern);
}
return new types.RelativePattern(pattern.base, pattern.pattern);
return pattern; // preserve `undefined` and `null`
}
function isRelativePattern(obj: any): obj is vscode.RelativePattern {
@@ -627,9 +637,13 @@ function doToLanguageSelector(selector: string | vscode.DocumentFilter): string
return selector;
}
return {
language: selector.language,
scheme: selector.scheme,
pattern: toGlobPattern(selector.pattern)
};
if (selector) {
return {
language: selector.language,
scheme: selector.scheme,
pattern: toGlobPattern(selector.pattern)
};
}
return undefined;
}

View File

@@ -12,6 +12,7 @@ import * as vscode from 'vscode';
import { isMarkdownString } from 'vs/base/common/htmlContent';
import { IRelativePattern } from 'vs/base/common/glob';
import { relative } from 'path';
import { startsWith } from 'vs/base/common/strings';
export class Disposable {
@@ -91,10 +92,10 @@ export class Position {
constructor(line: number, character: number) {
if (line < 0) {
throw illegalArgument('line must be positive');
throw illegalArgument('line must be non-negative');
}
if (character < 0) {
throw illegalArgument('character must be positive');
throw illegalArgument('character must be non-negative');
}
this._line = line;
this._character = character;
@@ -491,10 +492,28 @@ export class TextEdit {
}
}
export class WorkspaceEdit {
export class WorkspaceEdit implements vscode.WorkspaceEdit {
private _values: [URI, TextEdit[]][] = [];
private _index = new Map<string, number>();
private _seqPool: number = 0;
private _resourceEdits: { seq: number, from: URI, to: URI }[] = [];
private _textEdits = new Map<string, { seq: number, uri: URI, edits: TextEdit[] }>();
// createResource(uri: vscode.Uri): void {
// this.renameResource(undefined, uri);
// }
// deleteResource(uri: vscode.Uri): void {
// this.renameResource(uri, undefined);
// }
// renameResource(from: vscode.Uri, to: vscode.Uri): void {
// this._resourceEdits.push({ seq: this._seqPool++, from, to });
// }
// resourceEdits(): [vscode.Uri, vscode.Uri][] {
// return this._resourceEdits.map(({ from, to }) => (<[vscode.Uri, vscode.Uri]>[from, to]));
// }
replace(uri: URI, range: Range, newText: string): void {
let edit = new TextEdit(range, newText);
@@ -502,8 +521,9 @@ export class WorkspaceEdit {
if (array) {
array.push(edit);
} else {
this.set(uri, [edit]);
array = [edit];
}
this.set(uri, array);
}
insert(resource: URI, position: Position, newText: string): void {
@@ -515,34 +535,59 @@ export class WorkspaceEdit {
}
has(uri: URI): boolean {
return this._index.has(uri.toString());
return this._textEdits.has(uri.toString());
}
set(uri: URI, edits: TextEdit[]): void {
const idx = this._index.get(uri.toString());
if (typeof idx === 'undefined') {
let newLen = this._values.push([uri, edits]);
this._index.set(uri.toString(), newLen - 1);
let data = this._textEdits.get(uri.toString());
if (!data) {
data = { seq: this._seqPool++, uri, edits: [] };
this._textEdits.set(uri.toString(), data);
}
if (!edits) {
data.edits = undefined;
} else {
this._values[idx][1] = edits;
data.edits = edits.slice(0);
}
}
get(uri: URI): TextEdit[] {
let idx = this._index.get(uri.toString());
return typeof idx !== 'undefined' && this._values[idx][1];
if (!this._textEdits.has(uri.toString())) {
return undefined;
}
const { edits } = this._textEdits.get(uri.toString());
return edits ? edits.slice() : undefined;
}
entries(): [URI, TextEdit[]][] {
return this._values;
const res: [URI, TextEdit[]][] = [];
this._textEdits.forEach(value => res.push([value.uri, value.edits]));
return res.slice();
}
allEntries(): ([URI, TextEdit[]] | [URI, URI])[] {
return this.entries();
// // use the 'seq' the we have assigned when inserting
// // the operation and use that order in the resulting
// // array
// const res: ([URI, TextEdit[]] | [URI, URI])[] = [];
// this._textEdits.forEach(value => {
// const { seq, uri, edits } = value;
// res[seq] = [uri, edits];
// });
// this._resourceEdits.forEach(value => {
// const { seq, from, to } = value;
// res[seq] = [from, to];
// });
// return res;
}
get size(): number {
return this._values.length;
return this._textEdits.size + this._resourceEdits.length;
}
toJSON(): any {
return this._values;
return this.entries();
}
}
@@ -814,16 +859,43 @@ export class CodeAction {
command?: vscode.Command;
edits?: TextEdit[] | WorkspaceEdit;
edit?: WorkspaceEdit;
dianostics?: Diagnostic[];
constructor(title: string, edits?: TextEdit[] | WorkspaceEdit) {
kind?: CodeActionKind;
constructor(title: string, kind?: CodeActionKind) {
this.title = title;
this.edits = edits;
this.kind = kind;
}
}
export class CodeActionKind {
private static readonly sep = '.';
public static readonly Empty = new CodeActionKind('');
public static readonly QuickFix = CodeActionKind.Empty.append('quickfix');
public static readonly Refactor = CodeActionKind.Empty.append('refactor');
public static readonly RefactorExtract = CodeActionKind.Refactor.append('extract');
public static readonly RefactorInline = CodeActionKind.Refactor.append('inline');
public static readonly RefactorRewrite = CodeActionKind.Refactor.append('rewrite');
constructor(
public readonly value: string
) { }
public append(parts: string): CodeActionKind {
return new CodeActionKind(this.value ? this.value + CodeActionKind.sep + parts : parts);
}
public contains(other: CodeActionKind): boolean {
return this.value === other.value || startsWith(other.value, this.value + CodeActionKind.sep);
}
}
export class CodeLens {
range: Range;
@@ -905,14 +977,10 @@ export class SignatureHelp {
}
}
export enum CodeActionType {
QuickFix = 1,
Refactoring = 2
}
export enum CompletionTriggerKind {
Invoke = 0,
TriggerCharacter = 1
TriggerCharacter = 1,
TriggerForIncompleteCompletions = 2
}
export interface CompletionContext {
@@ -953,8 +1021,7 @@ export class CompletionItem {
label: string;
kind: CompletionItemKind;
detail: string;
// {{SQL CARBON EDIT}}
documentation: string;
documentation: string | MarkdownString;
sortText: string;
filterText: string;
insertText: string | SnippetString;
@@ -1134,6 +1201,12 @@ export enum ColorFormat {
HSL = 2
}
export enum SourceControlInputBoxValidationType {
Error = 0,
Warning = 1,
Information = 2
}
export enum TaskRevealKind {
Always = 1,
@@ -1446,11 +1519,21 @@ export enum ProgressLocation {
export class TreeItem {
label?: string;
resourceUri?: URI;
iconPath?: string | URI | { light: string | URI; dark: string | URI };
command?: vscode.Command;
contextValue?: string;
tooltip?: string;
constructor(public label: string, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
constructor(label: string, collapsibleState?: vscode.TreeItemCollapsibleState)
constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState)
constructor(arg1: string | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
if (arg1 instanceof URI) {
this.resourceUri = arg1;
} else {
this.label = arg1;
}
}
}
@@ -1461,6 +1544,18 @@ export enum TreeItemCollapsibleState {
Expanded = 2
}
export class ThemeIcon {
static readonly File = new ThemeIcon('file');
static readonly Folder = new ThemeIcon('folder');
readonly id: string;
private constructor(id: string) {
this.id = id;
}
}
export class ThemeColor {
id: string;
constructor(id: string) {
@@ -1506,20 +1601,25 @@ export class Breakpoint {
readonly condition?: string;
readonly hitCondition?: string;
protected constructor(enabled: boolean, condition: string, hitCondition: string) {
this.enabled = enabled;
this.condition = condition;
this.hitCondition = hitCondition;
this.condition = condition;
this.hitCondition = hitCondition;
protected constructor(enabled?: boolean, condition?: string, hitCondition?: string) {
this.enabled = typeof enabled === 'boolean' ? enabled : true;
if (typeof condition === 'string') {
this.condition = condition;
}
if (typeof hitCondition === 'string') {
this.hitCondition = hitCondition;
}
}
}
export class SourceBreakpoint extends Breakpoint {
readonly location: Location;
constructor(enabled: boolean, condition: string, hitCondition: string, location: Location) {
constructor(location: Location, enabled?: boolean, condition?: string, hitCondition?: string) {
super(enabled, condition, hitCondition);
if (location === null) {
throw illegalArgument('location');
}
this.location = location;
}
}
@@ -1527,8 +1627,93 @@ export class SourceBreakpoint extends Breakpoint {
export class FunctionBreakpoint extends Breakpoint {
readonly functionName: string;
constructor(enabled: boolean, condition: string, hitCondition: string, functionName: string) {
constructor(functionName: string, enabled?: boolean, condition?: string, hitCondition?: string) {
super(enabled, condition, hitCondition);
if (!functionName) {
throw illegalArgument('functionName');
}
this.functionName = functionName;
}
}
// {{SQL CARBON EDIT}}
/*
export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
readonly command: string;
readonly args: string[];
constructor(command: string, args?: string[]) {
this.command = command;
this.args = args;
}
}
*/
export enum LogLevel {
Trace = 1,
Debug = 2,
Info = 3,
Warning = 4,
Error = 5,
Critical = 6,
Off = 7
}
//#region file api
// todo@remote
export enum FileChangeType {
Updated = 0,
Added = 1,
Deleted = 2
}
export enum FileType {
File = 0,
Dir = 1,
Symlink = 2
}
//#endregion
//#region folding api
export class FoldingRangeList {
ranges: FoldingRange[];
constructor(ranges: FoldingRange[]) {
this.ranges = ranges;
}
}
export class FoldingRange {
startLine: number;
endLine: number;
type?: FoldingRangeType | string;
constructor(startLine: number, endLine: number, type?: FoldingRangeType | string) {
this.startLine = startLine;
this.endLine = endLine;
this.type = type;
}
}
export enum FoldingRangeType {
/**
* Folding range for a comment
*/
Comment = 'comment',
/**
* Folding range for a imports or includes
*/
Imports = 'imports',
/**
* Folding range for a region (e.g. `#region`)
*/
Region = 'region'
}
//#endregion

View File

@@ -0,0 +1,180 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainContext, MainThreadWebviewsShape, IMainContext, ExtHostWebviewsShape, WebviewHandle } from './extHost.protocol';
import * as vscode from 'vscode';
import Event, { Emitter } from 'vs/base/common/event';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import { Position } from 'vs/platform/editor/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
export class ExtHostWebview implements vscode.Webview {
public readonly editorType = 'webview';
private _title: string;
private _html: string;
private _options: vscode.WebviewOptions;
private _isDisposed: boolean = false;
private _viewColumn: vscode.ViewColumn;
public readonly onMessageEmitter = new Emitter<any>();
public readonly onDidReceiveMessage: Event<any> = this.onMessageEmitter.event;
public readonly onDisposeEmitter = new Emitter<void>();
public readonly onDidDispose: Event<void> = this.onDisposeEmitter.event;
public readonly onDidChangeViewColumnEmitter = new Emitter<vscode.ViewColumn>();
public readonly onDidChangeViewColumn: Event<vscode.ViewColumn> = this.onDidChangeViewColumnEmitter.event;
constructor(
private readonly _handle: WebviewHandle,
private readonly _proxy: MainThreadWebviewsShape,
private readonly _uri: vscode.Uri,
viewColumn: vscode.ViewColumn,
options: vscode.WebviewOptions
) {
this._viewColumn = viewColumn;
this._options = options;
}
public dispose() {
if (this._isDisposed) {
return;
}
this._isDisposed = true;
this._proxy.$disposeWebview(this._handle);
this.onDisposeEmitter.dispose();
this.onMessageEmitter.dispose();
this.onDidChangeViewColumnEmitter.dispose();
}
get uri(): vscode.Uri {
this.assertNotDisposed();
return this._uri;
}
get title(): string {
this.assertNotDisposed();
return this._title;
}
set title(value: string) {
this.assertNotDisposed();
if (this._title !== value) {
this._title = value;
this._proxy.$setTitle(this._handle, value);
}
}
get html(): string {
this.assertNotDisposed();
return this._html;
}
set html(value: string) {
this.assertNotDisposed();
if (this._html !== value) {
this._html = value;
this._proxy.$setHtml(this._handle, value);
}
}
get options(): vscode.WebviewOptions {
this.assertNotDisposed();
return this._options;
}
get viewColumn(): vscode.ViewColumn {
this.assertNotDisposed();
return this._viewColumn;
}
set viewColumn(value: vscode.ViewColumn) {
this.assertNotDisposed();
this._viewColumn = value;
}
public postMessage(message: any): Thenable<boolean> {
return this._proxy.$sendMessage(this._handle, message);
}
public show(viewColumn: vscode.ViewColumn): void {
this._proxy.$show(this._handle, typeConverters.fromViewColumn(viewColumn));
}
private assertNotDisposed() {
if (this._isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviews implements ExtHostWebviewsShape {
private static handlePool = 0;
private readonly _proxy: MainThreadWebviewsShape;
private readonly _webviews = new Map<WebviewHandle, ExtHostWebview>();
constructor(
mainContext: IMainContext
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWebviews);
}
createWebview(
uri: vscode.Uri,
title: string,
viewColumn: vscode.ViewColumn,
options: vscode.WebviewOptions
): vscode.Webview {
const handle = ExtHostWebviews.handlePool++;
this._proxy.$createWebview(handle, uri, title, typeConverters.fromViewColumn(viewColumn), options);
const webview = new ExtHostWebview(handle, this._proxy, uri, viewColumn, options);
this._webviews.set(handle, webview);
return webview;
}
$onMessage(handle: WebviewHandle, message: any): void {
const webview = this.getWebview(handle);
if (webview) {
webview.onMessageEmitter.fire(message);
}
}
$onDidChangeActiveWeview(handle: WebviewHandle | undefined): void {
this._onDidChangeActiveWebview.fire(this.getWebview(handle));
}
$onDidDisposeWeview(handle: WebviewHandle): Thenable<void> {
const webview = this.getWebview(handle);
if (webview) {
webview.onDisposeEmitter.fire();
this._webviews.delete(handle);
}
return TPromise.as(void 0);
}
$onDidChangePosition(handle: WebviewHandle, newPosition: Position): void {
const webview = this.getWebview(handle);
if (webview) {
const newViewColumn = typeConverters.toViewColumn(newPosition);
if (webview.viewColumn !== newViewColumn) {
webview.viewColumn = newViewColumn;
webview.onDidChangeViewColumnEmitter.fire(newViewColumn);
}
}
}
private readonly _onDidChangeActiveWebview = new Emitter<ExtHostWebview | undefined>();
public readonly onDidChangeActiveWebview = this._onDidChangeActiveWebview.event;
private getWebview(handle: WebviewHandle) {
return this._webviews.get(handle);
}
}

View File

@@ -5,8 +5,7 @@
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostWindowShape, MainContext, MainThreadWindowShape } from './extHost.protocol';
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext } from './extHost.protocol';
import { WindowState } from 'vscode';
export class ExtHostWindow implements ExtHostWindowShape {
@@ -23,8 +22,8 @@ export class ExtHostWindow implements ExtHostWindowShape {
private _state = ExtHostWindow.InitialState;
get state(): WindowState { return this._state; }
constructor(threadService: IThreadService) {
this._proxy = threadService.get(MainContext.MainThreadWindow);
constructor(mainContext: IMainContext) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWindow);
this._proxy.$getWindowVisibility().then(isFocused => this.$onDidChangeWindowFocus(isFocused));
}
@@ -36,4 +35,4 @@ export class ExtHostWindow implements ExtHostWindowShape {
this._state = { ...this._state, focused };
this._onDidChangeWindowState.fire(this._state);
}
}
}

View File

@@ -7,31 +7,110 @@
import URI from 'vs/base/common/uri';
import Event, { Emitter } from 'vs/base/common/event';
import { normalize } from 'vs/base/common/paths';
import { delta } from 'vs/base/common/arrays';
import { delta as arrayDelta } from 'vs/base/common/arrays';
import { relative, dirname } from 'path';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext } from './extHost.protocol';
import { IWorkspaceData, ExtHostWorkspaceShape, MainContext, MainThreadWorkspaceShape, IMainContext, MainThreadMessageServiceShape } from './extHost.protocol';
import * as vscode from 'vscode';
import { compare } from 'vs/base/common/strings';
import { TernarySearchTree } from 'vs/base/common/map';
import { basenameOrAuthority, isEqual } from 'vs/base/common/resources';
import { isLinux } from 'vs/base/common/platform';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { localize } from 'vs/nls';
import { Severity } from 'vs/platform/notification/common/notification';
import { ILogService } from 'vs/platform/log/common/log';
class Workspace2 extends Workspace {
function isFolderEqual(folderA: URI, folderB: URI): boolean {
return isEqual(folderA, folderB, !isLinux);
}
static fromData(data: IWorkspaceData) {
return data ? new Workspace2(data) : null;
function compareWorkspaceFolderByUri(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
return isFolderEqual(a.uri, b.uri) ? 0 : compare(a.uri.toString(), b.uri.toString());
}
function compareWorkspaceFolderByUriAndNameAndIndex(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
if (a.index !== b.index) {
return a.index < b.index ? -1 : 1;
}
return isFolderEqual(a.uri, b.uri) ? compare(a.name, b.name) : compare(a.uri.toString(), b.uri.toString());
}
function delta(oldFolders: vscode.WorkspaceFolder[], newFolders: vscode.WorkspaceFolder[], compare: (a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder) => number): { removed: vscode.WorkspaceFolder[], added: vscode.WorkspaceFolder[] } {
const oldSortedFolders = oldFolders.slice(0).sort(compare);
const newSortedFolders = newFolders.slice(0).sort(compare);
return arrayDelta(oldSortedFolders, newSortedFolders, compare);
}
interface MutableWorkspaceFolder extends vscode.WorkspaceFolder {
name: string;
index: number;
}
class ExtHostWorkspaceImpl extends Workspace {
static toExtHostWorkspace(data: IWorkspaceData, previousConfirmedWorkspace?: ExtHostWorkspaceImpl, previousUnconfirmedWorkspace?: ExtHostWorkspaceImpl): { workspace: ExtHostWorkspaceImpl, added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[] } {
if (!data) {
return { workspace: null, added: [], removed: [] };
}
const { id, name, folders } = data;
const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
// If we have an existing workspace, we try to find the folders that match our
// data and update their properties. It could be that an extension stored them
// for later use and we want to keep them "live" if they are still present.
const oldWorkspace = previousConfirmedWorkspace;
if (oldWorkspace) {
folders.forEach((folderData, index) => {
const folderUri = URI.revive(folderData.uri);
const existingFolder = ExtHostWorkspaceImpl._findFolder(previousUnconfirmedWorkspace || previousConfirmedWorkspace, folderUri);
if (existingFolder) {
existingFolder.name = folderData.name;
existingFolder.index = folderData.index;
newWorkspaceFolders.push(existingFolder);
} else {
newWorkspaceFolders.push({ uri: folderUri, name: folderData.name, index });
}
});
} else {
newWorkspaceFolders.push(...folders.map(({ uri, name, index }) => ({ uri: URI.revive(uri), name, index })));
}
// make sure to restore sort order based on index
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders);
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri);
return { workspace, added, removed };
}
private static _findFolder(workspace: ExtHostWorkspaceImpl, folderUriToFind: URI): MutableWorkspaceFolder {
for (let i = 0; i < workspace.folders.length; i++) {
const folder = workspace.workspaceFolders[i];
if (isFolderEqual(folder.uri, folderUriToFind)) {
return folder;
}
}
return undefined;
}
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
private constructor(data: IWorkspaceData) {
super(data.id, data.name, data.folders.map(folder => new WorkspaceFolder(folder)));
private constructor(id: string, name: string, folders: vscode.WorkspaceFolder[]) {
super(id, name, folders.map(f => new WorkspaceFolder(f)));
// setup the workspace folder data structure
this.folders.forEach(({ name, uri, index }) => {
const workspaceFolder = { name, uri, index };
this._workspaceFolders.push(workspaceFolder);
this._structure.set(workspaceFolder.uri.toString(), workspaceFolder);
folders.forEach(folder => {
this._workspaceFolders.push(folder);
this._structure.set(folder.uri.toString(), folder);
});
}
@@ -54,44 +133,122 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
private readonly _proxy: MainThreadWorkspaceShape;
private _workspace: Workspace2;
private _confirmedWorkspace: ExtHostWorkspaceImpl;
private _unconfirmedWorkspace: ExtHostWorkspaceImpl;
private _messageService: MainThreadMessageServiceShape;
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
constructor(mainContext: IMainContext, data: IWorkspaceData) {
this._proxy = mainContext.get(MainContext.MainThreadWorkspace);
this._workspace = Workspace2.fromData(data);
constructor(
mainContext: IMainContext,
data: IWorkspaceData,
private _logService: ILogService
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace);
this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService);
this._confirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace(data).workspace;
}
// --- workspace ---
get workspace(): Workspace {
return this._workspace;
return this._actualWorkspace;
}
private get _actualWorkspace(): ExtHostWorkspaceImpl {
return this._unconfirmedWorkspace || this._confirmedWorkspace;
}
getWorkspaceFolders(): vscode.WorkspaceFolder[] {
if (!this._workspace) {
if (!this._actualWorkspace) {
return undefined;
} else {
return this._workspace.workspaceFolders.slice(0);
}
return this._actualWorkspace.workspaceFolders.slice(0);
}
updateWorkspaceFolders(extension: IExtensionDescription, index: number, deleteCount: number, ...workspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[]): boolean {
const validatedDistinctWorkspaceFoldersToAdd: { uri: vscode.Uri, name?: string }[] = [];
if (Array.isArray(workspaceFoldersToAdd)) {
workspaceFoldersToAdd.forEach(folderToAdd => {
if (URI.isUri(folderToAdd.uri) && !validatedDistinctWorkspaceFoldersToAdd.some(f => isFolderEqual(f.uri, folderToAdd.uri))) {
validatedDistinctWorkspaceFoldersToAdd.push({ uri: folderToAdd.uri, name: folderToAdd.name || basenameOrAuthority(folderToAdd.uri) });
}
});
}
if (!!this._unconfirmedWorkspace) {
return false; // prevent accumulated calls without a confirmed workspace
}
if ([index, deleteCount].some(i => typeof i !== 'number' || i < 0)) {
return false; // validate numbers
}
if (deleteCount === 0 && validatedDistinctWorkspaceFoldersToAdd.length === 0) {
return false; // nothing to delete or add
}
const currentWorkspaceFolders: MutableWorkspaceFolder[] = this._actualWorkspace ? this._actualWorkspace.workspaceFolders : [];
if (index + deleteCount > currentWorkspaceFolders.length) {
return false; // cannot delete more than we have
}
// Simulate the updateWorkspaceFolders method on our data to do more validation
const newWorkspaceFolders = currentWorkspaceFolders.slice(0);
newWorkspaceFolders.splice(index, deleteCount, ...validatedDistinctWorkspaceFoldersToAdd.map(f => ({ uri: f.uri, name: f.name || basenameOrAuthority(f.uri), index: undefined })));
for (let i = 0; i < newWorkspaceFolders.length; i++) {
const folder = newWorkspaceFolders[i];
if (newWorkspaceFolders.some((otherFolder, index) => index !== i && isFolderEqual(folder.uri, otherFolder.uri))) {
return false; // cannot add the same folder multiple times
}
}
newWorkspaceFolders.forEach((f, index) => f.index = index); // fix index
const { added, removed } = delta(currentWorkspaceFolders, newWorkspaceFolders, compareWorkspaceFolderByUriAndNameAndIndex);
if (added.length === 0 && removed.length === 0) {
return false; // nothing actually changed
}
// Trigger on main side
if (this._proxy) {
const extName = extension.displayName || extension.name;
this._proxy.$updateWorkspaceFolders(extName, index, deleteCount, validatedDistinctWorkspaceFoldersToAdd).then(null, error => {
// in case of an error, make sure to clear out the unconfirmed workspace
// because we cannot expect the acknowledgement from the main side for this
this._unconfirmedWorkspace = undefined;
// show error to user
this._messageService.$showMessage(Severity.Error, localize('updateerror', "Extension '{0}' failed to update workspace folders: {1}", extName, error.toString()), { extension }, []);
});
}
// Try to accept directly
this.trySetWorkspaceFolders(newWorkspaceFolders);
return true;
}
getWorkspaceFolder(uri: vscode.Uri, resolveParent?: boolean): vscode.WorkspaceFolder {
if (!this._workspace) {
if (!this._actualWorkspace) {
return undefined;
}
return this._workspace.getWorkspaceFolder(uri, resolveParent);
return this._actualWorkspace.getWorkspaceFolder(uri, resolveParent);
}
getPath(): string {
// this is legacy from the days before having
// multi-root and we keep it only alive if there
// is just one workspace folder.
if (!this._workspace) {
if (!this._actualWorkspace) {
return undefined;
}
const { folders } = this._workspace;
const { folders } = this._actualWorkspace;
if (folders.length === 0) {
return undefined;
}
@@ -121,7 +278,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
}
if (typeof includeWorkspace === 'undefined') {
includeWorkspace = this.workspace.folders.length > 1;
includeWorkspace = this._actualWorkspace.folders.length > 1;
}
let result = relative(folder.uri.fsPath, path);
@@ -131,17 +288,30 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
return normalize(result, true);
}
private trySetWorkspaceFolders(folders: vscode.WorkspaceFolder[]): void {
// Update directly here. The workspace is unconfirmed as long as we did not get an
// acknowledgement from the main side (via $acceptWorkspaceData)
if (this._actualWorkspace) {
this._unconfirmedWorkspace = ExtHostWorkspaceImpl.toExtHostWorkspace({
id: this._actualWorkspace.id,
name: this._actualWorkspace.name,
configuration: this._actualWorkspace.configuration,
folders
} as IWorkspaceData, this._actualWorkspace).workspace;
}
}
$acceptWorkspaceData(data: IWorkspaceData): void {
// keep old workspace folder, build new workspace, and
// capture new workspace folders. Compute delta between
// them send that as event
const oldRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
const { workspace, added, removed } = ExtHostWorkspaceImpl.toExtHostWorkspace(data, this._confirmedWorkspace, this._unconfirmedWorkspace);
this._workspace = Workspace2.fromData(data);
const newRoots = this._workspace ? this._workspace.workspaceFolders.sort(ExtHostWorkspace._compareWorkspaceFolder) : [];
// Update our workspace object. We have a confirmed workspace, so we drop our
// unconfirmed workspace.
this._confirmedWorkspace = workspace;
this._unconfirmedWorkspace = undefined;
const { added, removed } = delta(oldRoots, newRoots, ExtHostWorkspace._compareWorkspaceFolder);
// Events
// {{SQL CARBON EDIT}} - fix build break Argument of type 'Readonly<...
this._onDidChangeWorkspace.fire({
added: added,
@@ -149,13 +319,11 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
});
}
private static _compareWorkspaceFolder(a: vscode.WorkspaceFolder, b: vscode.WorkspaceFolder): number {
return compare(a.uri.toString(), b.uri.toString());
}
// --- search ---
findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults?: number, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: string, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId}, entryPoint: findFiles`);
const requestId = ExtHostWorkspace._requestIdPool++;
let includePattern: string;
@@ -169,20 +337,22 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
}
}
let excludePattern: string;
if (exclude) {
let excludePatternOrDisregardExcludes: string | false;
if (exclude === null) {
excludePatternOrDisregardExcludes = false;
} else if (exclude) {
if (typeof exclude === 'string') {
excludePattern = exclude;
excludePatternOrDisregardExcludes = exclude;
} else {
excludePattern = exclude.pattern;
excludePatternOrDisregardExcludes = exclude.pattern;
}
}
const result = this._proxy.$startSearch(includePattern, includeFolder, excludePattern, maxResults, requestId);
const result = this._proxy.$startSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, requestId);
if (token) {
token.onCancellationRequested(() => this._proxy.$cancelSearch(requestId));
}
return result;
return result.then(data => data.map(URI.revive));
}
saveAll(includeUntitled?: boolean): Thenable<boolean> {