mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-26 01:25:38 -05:00
Merge from master
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isMalformedFileUri } from 'vs/base/common/resources';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
@@ -49,10 +49,11 @@ export class OpenFolderAPICommand {
|
||||
if (!uri) {
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', forceNewWindow);
|
||||
}
|
||||
if (!uri.scheme || isWindows && uri.scheme.match(/^[a-zA-Z]$/)) {
|
||||
let correctedUri = isMalformedFileUri(uri);
|
||||
if (correctedUri) {
|
||||
// workaround for #55916 and #55891, will be removed in 1.28
|
||||
console.warn(`'vscode.openFolder' command invoked with an invalid URI (file:// scheme missing): '${uri}'. Converted to a 'file://' URI.`);
|
||||
uri = URI.file((uri.scheme ? uri.scheme + ':' : '') + uri.path);
|
||||
console.warn(`'vscode.openFolder' command invoked with an invalid URI (file:// scheme missing): '${uri}'. Converted to a 'file://' URI: ${correctedUri}`);
|
||||
uri = correctedUri;
|
||||
}
|
||||
|
||||
return executor.executeCommand('_files.windowOpen', [uri], forceNewWindow);
|
||||
@@ -76,7 +77,7 @@ CommandsRegistry.registerCommand(DiffAPICommand.ID, adjustHandler(DiffAPICommand
|
||||
|
||||
export class OpenAPICommand {
|
||||
public static ID = 'vscode.open';
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions): Thenable<any> {
|
||||
public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, label?: string): Thenable<any> {
|
||||
let options: ITextEditorOptions;
|
||||
let position: EditorViewColumn;
|
||||
|
||||
@@ -92,7 +93,8 @@ export class OpenAPICommand {
|
||||
return executor.executeCommand('_workbench.open', [
|
||||
resource,
|
||||
options,
|
||||
position
|
||||
position,
|
||||
label
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,79 +2,71 @@
|
||||
* 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 { Emitter } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import product from 'vs/platform/node/product';
|
||||
import { Emitter, mapEvent } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import pkg from 'vs/platform/node/package';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import product from 'vs/platform/node/product';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/node/extHostClipboard';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostComments } from 'vs/workbench/api/node/extHostComments';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
// {{SQL CARBON EDIT}} - Remove ExtHostDebugService
|
||||
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { ExtHostDialogs } from 'vs/workbench/api/node/extHostDialogs';
|
||||
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/node/extHostDocumentContentProviders';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
|
||||
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/node/extHostSCM';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/node/extHostStatusBar';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostOutputService } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/node/extHostMessageService';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/node/extHostLanguages';
|
||||
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
// {{SQL CARBON EDIT}}
|
||||
//import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
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 { 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 * as files from 'vs/platform/files/common/files';
|
||||
import { MainContext, ExtHostContext, IInitData, IMainContext } from './extHost.protocol';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
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 { ExtHostDecorations } from 'vs/workbench/api/node/extHostDecorations';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtensionActivatedByAPI } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostFileSystem } from 'vs/workbench/api/node/extHostFileSystem';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/node/extHostLanguages';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/node/extHostMessageService';
|
||||
import { ExtHostOutputService } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { ExtHostProgress } from 'vs/workbench/api/node/extHostProgress';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/node/extHostQuickOpen';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/node/extHostSCM';
|
||||
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/node/extHostStatusBar';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/node/extHostTextEditors';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/node/extHostTreeViews';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostUrls } from 'vs/workbench/api/node/extHostUrls';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';
|
||||
import { ExtHostComments } from './extHostComments';
|
||||
import { ExtHostSearch } from './extHostSearch';
|
||||
import { ExtHostUrls } from './extHostUrls';
|
||||
import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { IExtensionDescription, throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
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}`);
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry): typeof vscode;
|
||||
}
|
||||
|
||||
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
|
||||
@@ -94,10 +86,11 @@ export function createApiFactory(
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extensionService: ExtHostExtensionService,
|
||||
extHostLogService: ExtHostLogService
|
||||
extHostLogService: ExtHostLogService,
|
||||
extHostStorage: ExtHostStorage
|
||||
): IExtensionApiFactory {
|
||||
|
||||
let schemeTransformer: ISchemeTransformer = null;
|
||||
let schemeTransformer: ISchemeTransformer | null = null;
|
||||
|
||||
// Addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
|
||||
@@ -121,37 +114,43 @@ export function createApiFactory(
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostLogService));
|
||||
// {{SQL CARBON EDIT}}
|
||||
//const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService));
|
||||
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands));
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer));
|
||||
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer, extHostLogService, extHostConfiguration));
|
||||
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace, extHostDocumentsAndEditors, extHostConfiguration));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const exthostCommentProviders = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands.converter, extHostDocuments));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
|
||||
// Check that no named customers are missing
|
||||
const expected: ProxyIdentifier<any>[] = Object.keys(ExtHostContext).map((key) => (<any>ExtHostContext)[key]);
|
||||
rpcProtocol.assertRegistered(expected);
|
||||
|
||||
// Other instances
|
||||
const extHostClipboard = new ExtHostClipboard(rpcProtocol);
|
||||
const extHostMessageService = new ExtHostMessageService(rpcProtocol);
|
||||
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
|
||||
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
|
||||
const extHostOutputService = new ExtHostOutputService(rpcProtocol);
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol);
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register an output channel for exthost log
|
||||
const name = localize('extensionsLog', "Extension Host");
|
||||
extHostOutputService.createOutputChannelFromLogFile(name, extHostLogService.logFile);
|
||||
|
||||
// Register API-ish commands
|
||||
ExtHostApiCommands.register(extHostCommands);
|
||||
|
||||
return function (extension: IExtensionDescription): typeof vscode {
|
||||
return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry): typeof vscode {
|
||||
|
||||
// Check document selectors for being overly generic. Technically this isn't a problem but
|
||||
// in practice many extensions say they support `fooLang` but need fs-access to do so. Those
|
||||
// extension should specify then the `file`-scheme, e.g `{ scheme: 'fooLang', language: 'fooLang' }`
|
||||
// We only inform once, it is not a warning because we just want to raise awareness and because
|
||||
// we cannot say if the extension is doing it right or wrong...
|
||||
let checkSelector = (function () {
|
||||
const checkSelector = (function () {
|
||||
let done = (!extension.isUnderDevelopment);
|
||||
function informOnce(selector: vscode.DocumentSelector) {
|
||||
if (!done) {
|
||||
@@ -176,6 +175,24 @@ export function createApiFactory(
|
||||
};
|
||||
})();
|
||||
|
||||
// Warn when trying to use the vscode.previewHtml command as it does not work properly in all scenarios and
|
||||
// has security concerns.
|
||||
const checkCommand = (() => {
|
||||
let done = !extension.isUnderDevelopment;
|
||||
const informOnce = () => {
|
||||
if (!done) {
|
||||
done = true;
|
||||
console.warn(`Extension '${extension.id}' uses the 'vscode.previewHtml' command which is deprecated and will be removed. Please update your extension to use the Webview API: https://go.microsoft.com/fwlink/?linkid=2039309`);
|
||||
}
|
||||
};
|
||||
return (commandId: string) => {
|
||||
if (commandId === 'vscode.previewHtml') {
|
||||
informOnce();
|
||||
}
|
||||
return commandId;
|
||||
};
|
||||
})();
|
||||
|
||||
// namespace: commands
|
||||
const commands: typeof vscode.commands = {
|
||||
registerCommand(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
|
||||
@@ -215,7 +232,7 @@ export function createApiFactory(
|
||||
});
|
||||
}),
|
||||
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
|
||||
return extHostCommands.executeCommand<T>(id, ...args);
|
||||
return extHostCommands.executeCommand<T>(checkCommand(id), ...args);
|
||||
},
|
||||
getCommands(filterInternal: boolean = false): Thenable<string[]> {
|
||||
return extHostCommands.getCommands(filterInternal);
|
||||
@@ -228,21 +245,31 @@ export function createApiFactory(
|
||||
get sessionId() { return initData.telemetryInfo.sessionId; },
|
||||
get language() { return platform.language; },
|
||||
get appName() { return product.nameLong; },
|
||||
get appRoot() { return initData.environment.appRoot; },
|
||||
get logLevel() { return extHostLogService.getLevel(); }
|
||||
get appRoot() { return initData.environment.appRoot.fsPath; },
|
||||
get logLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return typeConverters.LogLevel.to(extHostLogService.getLevel());
|
||||
},
|
||||
get onDidChangeLogLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return mapEvent(extHostLogService.onDidChangeLogLevel, l => typeConverters.LogLevel.to(l));
|
||||
},
|
||||
get clipboard(): vscode.Clipboard {
|
||||
return extHostClipboard;
|
||||
}
|
||||
});
|
||||
|
||||
// namespace: extensions
|
||||
const extensions: typeof vscode.extensions = {
|
||||
getExtension(extensionId: string): Extension<any> {
|
||||
let desc = extensionService.getExtensionDescription(extensionId);
|
||||
let desc = extensionRegistry.getExtensionDescription(extensionId);
|
||||
if (desc) {
|
||||
return new Extension(extensionService, desc);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
get all(): Extension<any>[] {
|
||||
return extensionService.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -257,68 +284,80 @@ export function createApiFactory(
|
||||
getDiagnostics: (resource?: vscode.Uri) => {
|
||||
return <any>extHostDiagnostics.getDiagnostics(resource);
|
||||
},
|
||||
getLanguages(): TPromise<string[]> {
|
||||
getLanguages(): Thenable<string[]> {
|
||||
return extHostLanguages.getLanguages();
|
||||
},
|
||||
setTextDocumentLanguage(document: vscode.TextDocument, languageId: string): Thenable<vscode.TextDocument> {
|
||||
return extHostLanguages.changeLanguage(document.uri, languageId);
|
||||
},
|
||||
match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number {
|
||||
return score(typeConverters.LanguageSelector.from(selector), document.uri, document.languageId, true);
|
||||
},
|
||||
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeActionProvider(checkSelector(selector), provider, extension, metadata);
|
||||
return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDefinitionProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDeclarationProvider(selector: vscode.DocumentSelector, provider: vscode.DeclarationProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDeclarationProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerImplementationProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerImplementationProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerTypeDefinitionProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerTypeDefinitionProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerHoverProvider(checkSelector(selector), provider, extension.id);
|
||||
return extHostLanguageFeatures.registerHoverProvider(extension, checkSelector(selector), provider, extension.id);
|
||||
},
|
||||
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerReferenceProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerReferenceProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerRenameProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerRenameProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentSymbolProvider(checkSelector(selector), provider, extension);
|
||||
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, metadata?: vscode.DocumentSymbolProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentSymbolProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerWorkspaceSymbolProvider(provider);
|
||||
return extHostLanguageFeatures.registerWorkspaceSymbolProvider(extension, provider);
|
||||
},
|
||||
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(checkSelector(selector), provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
|
||||
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(extension, checkSelector(selector), provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
|
||||
},
|
||||
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, ...triggerCharacters: string[]): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerSignatureHelpProvider(checkSelector(selector), provider, triggerCharacters);
|
||||
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, firstItem?: string | vscode.SignatureHelpProviderMetadata, ...remaining: string[]): vscode.Disposable {
|
||||
if (typeof firstItem === 'object') {
|
||||
return extHostLanguageFeatures.registerSignatureHelpProvider(extension, checkSelector(selector), provider, firstItem);
|
||||
}
|
||||
return extHostLanguageFeatures.registerSignatureHelpProvider(extension, checkSelector(selector), provider, typeof firstItem === 'undefined' ? [] : [firstItem, ...remaining]);
|
||||
},
|
||||
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCompletionItemProvider(checkSelector(selector), provider, triggerCharacters);
|
||||
return extHostLanguageFeatures.registerCompletionItemProvider(extension, checkSelector(selector), provider, triggerCharacters);
|
||||
},
|
||||
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentLinkProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentLinkProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerColorProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerColorProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerFoldingRangeProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerFoldingRangeProvider(checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerFoldingRangeProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerSelectionRangeProvider(selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerSelectionRangeProvider(extension, selector, provider);
|
||||
},
|
||||
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
|
||||
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
|
||||
@@ -334,17 +373,17 @@ export function createApiFactory(
|
||||
return extHostEditors.getVisibleTextEditors();
|
||||
},
|
||||
get activeTerminal() {
|
||||
return proposedApiFunction(extension, extHostTerminalService.activeTerminal);
|
||||
return extHostTerminalService.activeTerminal;
|
||||
},
|
||||
get terminals() {
|
||||
return extHostTerminalService.terminals;
|
||||
},
|
||||
showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): TPromise<vscode.TextEditor> {
|
||||
let documentPromise: TPromise<vscode.TextDocument>;
|
||||
showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
|
||||
let documentPromise: Promise<vscode.TextDocument>;
|
||||
if (URI.isUri(documentOrUri)) {
|
||||
documentPromise = TPromise.wrap(workspace.openTextDocument(documentOrUri));
|
||||
documentPromise = Promise.resolve(workspace.openTextDocument(documentOrUri));
|
||||
} else {
|
||||
documentPromise = TPromise.wrap(<vscode.TextDocument>documentOrUri);
|
||||
documentPromise = Promise.resolve(<vscode.TextDocument>documentOrUri);
|
||||
}
|
||||
return documentPromise.then(document => {
|
||||
return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
|
||||
@@ -377,9 +416,9 @@ export function createApiFactory(
|
||||
onDidOpenTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidOpenTerminal(listener, thisArg, disposables);
|
||||
},
|
||||
onDidChangeActiveTerminal: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
|
||||
onDidChangeActiveTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables);
|
||||
}),
|
||||
},
|
||||
get state() {
|
||||
return extHostWindow.state;
|
||||
},
|
||||
@@ -396,7 +435,7 @@ export function createApiFactory(
|
||||
return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest);
|
||||
},
|
||||
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any {
|
||||
return extHostQuickOpen.showQuickPick(items, options, token);
|
||||
return extHostQuickOpen.showQuickPick(items, extension.enableProposedApi, options, token);
|
||||
},
|
||||
showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) {
|
||||
return extHostQuickOpen.showWorkspaceFolderPick(options);
|
||||
@@ -427,7 +466,7 @@ export function createApiFactory(
|
||||
return extHostOutputService.createOutputChannel(name);
|
||||
},
|
||||
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
|
||||
return extHostWebviews.createWebview(extension.extensionLocation, viewType, title, showOptions, options);
|
||||
return extHostWebviews.createWebview(extension, viewType, title, showOptions, options);
|
||||
},
|
||||
createTerminal(nameOrOptions: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
|
||||
if (typeof nameOrOptions === 'object') {
|
||||
@@ -435,22 +474,18 @@ export function createApiFactory(
|
||||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
createTerminalRenderer: proposedApiFunction(extension, (name: string) => {
|
||||
return extHostTerminalService.createTerminalRenderer(name);
|
||||
},
|
||||
}),
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider);
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
|
||||
},
|
||||
createTreeView(viewId: string, options: { treeDataProvider: vscode.TreeDataProvider<any> }): vscode.TreeView<any> {
|
||||
return extHostTreeViews.createTreeView(viewId, options);
|
||||
return extHostTreeViews.createTreeView(viewId, options, extension);
|
||||
},
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
|
||||
},
|
||||
// proposed API
|
||||
sampleFunction: proposedApiFunction(extension, () => {
|
||||
return extHostMessageService.showMessage(extension, Severity.Info, 'Hello Proposed Api!', {}, []);
|
||||
}),
|
||||
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => {
|
||||
return extHostDecorations.registerDecorationProvider(provider, extension.id);
|
||||
}),
|
||||
@@ -458,7 +493,7 @@ export function createApiFactory(
|
||||
return extHostUrls.registerUriHandler(extension.id, handler);
|
||||
},
|
||||
createQuickPick<T extends vscode.QuickPickItem>(): vscode.QuickPick<T> {
|
||||
return extHostQuickOpen.createQuickPick(extension.id);
|
||||
return extHostQuickOpen.createQuickPick(extension.id, extension.enableProposedApi);
|
||||
},
|
||||
createInputBox(): vscode.InputBox {
|
||||
return extHostQuickOpen.createInputBox(extension.id);
|
||||
@@ -480,7 +515,7 @@ export function createApiFactory(
|
||||
return extHostWorkspace.getWorkspaceFolders();
|
||||
},
|
||||
get name() {
|
||||
return extHostWorkspace.workspace ? extHostWorkspace.workspace.name : undefined;
|
||||
return extHostWorkspace.name;
|
||||
},
|
||||
set name(value) {
|
||||
throw errors.readonly();
|
||||
@@ -515,7 +550,7 @@ export function createApiFactory(
|
||||
saveAll: (includeUntitled?) => {
|
||||
return extHostWorkspace.saveAll(includeUntitled);
|
||||
},
|
||||
applyEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
|
||||
applyEdit(edit: vscode.WorkspaceEdit): Thenable<boolean> {
|
||||
return extHostEditors.applyWorkspaceEdit(edit);
|
||||
},
|
||||
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
|
||||
@@ -528,13 +563,13 @@ export function createApiFactory(
|
||||
throw errors.readonly();
|
||||
},
|
||||
openTextDocument(uriOrFileNameOrOptions?: vscode.Uri | string | { language?: string; content?: string; }) {
|
||||
let uriPromise: TPromise<URI>;
|
||||
let uriPromise: Thenable<URI>;
|
||||
|
||||
let options = uriOrFileNameOrOptions as { language?: string; content?: string; };
|
||||
if (typeof uriOrFileNameOrOptions === 'string') {
|
||||
uriPromise = TPromise.as(URI.file(uriOrFileNameOrOptions));
|
||||
uriPromise = Promise.resolve(URI.file(uriOrFileNameOrOptions));
|
||||
} else if (uriOrFileNameOrOptions instanceof URI) {
|
||||
uriPromise = TPromise.as(uriOrFileNameOrOptions);
|
||||
uriPromise = Promise.resolve(uriOrFileNameOrOptions);
|
||||
} else if (!options || typeof options === 'object') {
|
||||
uriPromise = extHostDocuments.createDocumentData(options);
|
||||
} else {
|
||||
@@ -596,7 +631,7 @@ export function createApiFactory(
|
||||
return exthostCommentProviders.registerDocumentCommentProvider(provider);
|
||||
}),
|
||||
registerWorkspaceCommentProvider: proposedApiFunction(extension, (provider: vscode.WorkspaceCommentProvider) => {
|
||||
return exthostCommentProviders.registerWorkspaceCommentProvider(provider);
|
||||
return exthostCommentProviders.registerWorkspaceCommentProvider(extension.id, provider);
|
||||
}),
|
||||
onDidRenameFile: proposedApiFunction(extension, (listener, thisArg?, disposables?) => {
|
||||
return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables);
|
||||
@@ -646,44 +681,55 @@ export function createApiFactory(
|
||||
};
|
||||
|
||||
return <typeof vscode>{
|
||||
version: pkg.version,
|
||||
// {{SQL CARBON EDIT}} - Expose the VS Code version here for extensions that rely on it
|
||||
version: product.vscodeVersion,
|
||||
// namespaces
|
||||
commands,
|
||||
// {{SQL CARBON EDIT}}
|
||||
// debug,
|
||||
env,
|
||||
extensions,
|
||||
languages,
|
||||
scm,
|
||||
tasks,
|
||||
window,
|
||||
workspace,
|
||||
scm,
|
||||
// {{SQL CARBON EDIT}}
|
||||
// debug,
|
||||
tasks,
|
||||
// types
|
||||
Breakpoint: extHostTypes.Breakpoint,
|
||||
CancellationTokenSource: CancellationTokenSource,
|
||||
CodeAction: extHostTypes.CodeAction,
|
||||
CodeActionKind: extHostTypes.CodeActionKind,
|
||||
CodeActionTrigger: extHostTypes.CodeActionTrigger,
|
||||
CodeLens: extHostTypes.CodeLens,
|
||||
Color: extHostTypes.Color,
|
||||
ColorPresentation: extHostTypes.ColorPresentation,
|
||||
ColorInformation: extHostTypes.ColorInformation,
|
||||
CodeActionTrigger: extHostTypes.CodeActionTrigger,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
ColorPresentation: extHostTypes.ColorPresentation,
|
||||
CommentThreadCollapsibleState: extHostTypes.CommentThreadCollapsibleState,
|
||||
CompletionItem: extHostTypes.CompletionItem,
|
||||
CompletionItemKind: extHostTypes.CompletionItemKind,
|
||||
CompletionList: extHostTypes.CompletionList,
|
||||
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
// {{SQL CARBON EDIT}}
|
||||
// DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
|
||||
// DebugAdapterServer: extHostTypes.DebugAdapterServer,
|
||||
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
DiagnosticRelatedInformation: extHostTypes.DiagnosticRelatedInformation,
|
||||
DiagnosticTag: extHostTypes.DiagnosticTag,
|
||||
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
|
||||
DiagnosticTag: extHostTypes.DiagnosticTag,
|
||||
Disposable: extHostTypes.Disposable,
|
||||
DocumentHighlight: extHostTypes.DocumentHighlight,
|
||||
DocumentHighlightKind: extHostTypes.DocumentHighlightKind,
|
||||
DocumentLink: extHostTypes.DocumentLink,
|
||||
DocumentSymbol: extHostTypes.DocumentSymbol,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
FileType: files.FileType,
|
||||
FoldingRange: extHostTypes.FoldingRange,
|
||||
FoldingRangeKind: extHostTypes.FoldingRangeKind,
|
||||
FunctionBreakpoint: extHostTypes.FunctionBreakpoint,
|
||||
Hover: extHostTypes.Hover,
|
||||
IndentAction: languageConfiguration.IndentAction,
|
||||
@@ -693,52 +739,44 @@ export function createApiFactory(
|
||||
OverviewRulerLane: OverviewRulerLane,
|
||||
ParameterInformation: extHostTypes.ParameterInformation,
|
||||
Position: extHostTypes.Position,
|
||||
ProcessExecution: extHostTypes.ProcessExecution,
|
||||
ProgressLocation: extHostTypes.ProgressLocation,
|
||||
QuickInputButtons: extHostTypes.QuickInputButtons,
|
||||
Range: extHostTypes.Range,
|
||||
RelativePattern: extHostTypes.RelativePattern,
|
||||
Selection: extHostTypes.Selection,
|
||||
ShellExecution: extHostTypes.ShellExecution,
|
||||
ShellQuoting: extHostTypes.ShellQuoting,
|
||||
SignatureHelpTriggerKind: extHostTypes.SignatureHelpTriggerKind,
|
||||
SignatureHelp: extHostTypes.SignatureHelp,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SnippetString: extHostTypes.SnippetString,
|
||||
SourceBreakpoint: extHostTypes.SourceBreakpoint,
|
||||
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
SymbolInformation: extHostTypes.SymbolInformation,
|
||||
DocumentSymbol: extHostTypes.DocumentSymbol,
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
|
||||
Task: extHostTypes.Task,
|
||||
Task2: extHostTypes.Task,
|
||||
TaskGroup: extHostTypes.TaskGroup,
|
||||
TaskPanelKind: extHostTypes.TaskPanelKind,
|
||||
TaskRevealKind: extHostTypes.TaskRevealKind,
|
||||
TaskScope: extHostTypes.TaskScope,
|
||||
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
|
||||
TextEdit: extHostTypes.TextEdit,
|
||||
TextEditorCursorStyle: TextEditorCursorStyle,
|
||||
TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle,
|
||||
TextEditorRevealType: extHostTypes.TextEditorRevealType,
|
||||
TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind,
|
||||
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
|
||||
ThemeColor: extHostTypes.ThemeColor,
|
||||
ThemeIcon: extHostTypes.ThemeIcon,
|
||||
TreeItem: extHostTypes.TreeItem,
|
||||
TreeItem2: extHostTypes.TreeItem,
|
||||
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
|
||||
Uri: URI,
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
ProgressLocation: extHostTypes.ProgressLocation,
|
||||
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
|
||||
ThemeIcon: extHostTypes.ThemeIcon,
|
||||
TreeItem: extHostTypes.TreeItem,
|
||||
ThemeColor: extHostTypes.ThemeColor,
|
||||
// functions
|
||||
TaskRevealKind: extHostTypes.TaskRevealKind,
|
||||
TaskPanelKind: extHostTypes.TaskPanelKind,
|
||||
TaskGroup: extHostTypes.TaskGroup,
|
||||
ProcessExecution: extHostTypes.ProcessExecution,
|
||||
ShellExecution: extHostTypes.ShellExecution,
|
||||
ShellQuoting: extHostTypes.ShellQuoting,
|
||||
TaskScope: extHostTypes.TaskScope,
|
||||
Task: extHostTypes.Task,
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
RelativePattern: extHostTypes.RelativePattern,
|
||||
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileType: files.FileType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
FoldingRange: extHostTypes.FoldingRange,
|
||||
FoldingRangeKind: extHostTypes.FoldingRangeKind,
|
||||
|
||||
CommentThreadCollapsibleState: extHostTypes.CommentThreadCollapsibleState
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -783,11 +821,11 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory): TPromise<void> {
|
||||
return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie));
|
||||
export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry): Promise<void> {
|
||||
return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry));
|
||||
}
|
||||
|
||||
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree<IExtensionDescription>): void {
|
||||
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree<IExtensionDescription>, extensionRegistry: ExtensionDescriptionRegistry): void {
|
||||
|
||||
// each extension is meant to get its own api implementation
|
||||
const extApiImpl = new Map<string, typeof vscode>();
|
||||
@@ -805,7 +843,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT
|
||||
if (ext) {
|
||||
let apiImpl = extApiImpl.get(ext.id);
|
||||
if (!apiImpl) {
|
||||
apiImpl = factory(ext);
|
||||
apiImpl = factory(ext, extensionRegistry);
|
||||
extApiImpl.set(ext.id, apiImpl);
|
||||
}
|
||||
return apiImpl;
|
||||
@@ -816,24 +854,8 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT
|
||||
let extensionPathsPretty = '';
|
||||
extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.id}\n`);
|
||||
console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`);
|
||||
defaultApiImpl = factory(nullExtensionDescription);
|
||||
defaultApiImpl = factory(nullExtensionDescription, extensionRegistry);
|
||||
}
|
||||
return defaultApiImpl;
|
||||
};
|
||||
}
|
||||
|
||||
const nullExtensionDescription: IExtensionDescription = {
|
||||
id: 'nullExtensionDescription',
|
||||
name: 'Null Extension Description',
|
||||
publisher: 'vscode',
|
||||
activationEvents: undefined,
|
||||
contributes: undefined,
|
||||
enableProposedApi: false,
|
||||
engines: undefined,
|
||||
extensionDependencies: undefined,
|
||||
extensionLocation: undefined,
|
||||
isBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
main: undefined,
|
||||
version: undefined
|
||||
};
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
* 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 { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { SerializedError } from 'vs/base/common/errors';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
@@ -22,32 +21,40 @@ import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands
|
||||
import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { FileChangeType, FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities, FileType, FileWriteOptions, IStat, IWatchOptions } from 'vs/platform/files/common/files';
|
||||
import { LabelRules } from 'vs/platform/label/common/label';
|
||||
import { LogLevel } from 'vs/platform/log/common/log';
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { IPickOptions, IQuickInputButton, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IPatternInfo, IQueryOptions, IRawFileMatch2, IRawSearchQuery, ISearchCompleteStats } from 'vs/platform/search/common/search';
|
||||
import { IPatternInfo, IRawFileMatch2, IRawQuery, IRawTextQuery, ISearchCompleteStats } from 'vs/platform/search/common/search';
|
||||
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { EndOfLine, IFileOperationOptions, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
|
||||
import { TaskDTO, TaskExecutionDTO, TaskFilterDTO, TaskHandleDTO, TaskProcessEndedDTO, TaskProcessStartedDTO, TaskSystemInfoDTO } from 'vs/workbench/api/shared/tasks';
|
||||
import { ITreeItem } from 'vs/workbench/common/views';
|
||||
import { IAdapterExecutable, IConfig, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { ITreeItem, IRevealOptions } from 'vs/workbench/common/views';
|
||||
import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder';
|
||||
import { TaskSet } from 'vs/workbench/parts/tasks/common/tasks';
|
||||
import { ITerminalDimensions } from 'vs/workbench/parts/terminal/common/terminal';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol, ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { IProgressOptions, IProgressStep } from 'vs/workbench/services/progress/common/progress';
|
||||
import { IRPCProtocol, ProxyIdentifier, createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import * as vscode from 'vscode';
|
||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
|
||||
export interface IEnvironment {
|
||||
isExtensionDevelopmentDebug: boolean;
|
||||
appRoot: string;
|
||||
appSettingsHome: string;
|
||||
extensionDevelopmentPath: string;
|
||||
appRoot: URI;
|
||||
appSettingsHome: URI;
|
||||
extensionDevelopmentLocationURI: URI;
|
||||
extensionTestsPath: string;
|
||||
globalStorageHome: URI;
|
||||
}
|
||||
|
||||
export interface IWorkspaceData {
|
||||
@@ -58,15 +65,17 @@ export interface IWorkspaceData {
|
||||
}
|
||||
|
||||
export interface IInitData {
|
||||
commit: string;
|
||||
parentPid: number;
|
||||
environment: IEnvironment;
|
||||
workspace: IWorkspaceData;
|
||||
extensions: IExtensionDescription[];
|
||||
configuration: IConfigurationInitData;
|
||||
telemetryInfo: ITelemetryInfo;
|
||||
windowId: number;
|
||||
logLevel: LogLevel;
|
||||
logsPath: string;
|
||||
logsLocation: URI;
|
||||
autoStart: boolean;
|
||||
remoteAuthority?: string | null;
|
||||
}
|
||||
|
||||
export interface IConfigurationInitData extends IConfigurationData {
|
||||
@@ -79,6 +88,7 @@ export interface IWorkspaceConfigurationChangeEventData {
|
||||
}
|
||||
|
||||
export interface IExtHostContext extends IRPCProtocol {
|
||||
remoteAuthority: string;
|
||||
}
|
||||
|
||||
export interface IMainContext extends IRPCProtocol {
|
||||
@@ -86,6 +96,11 @@ export interface IMainContext extends IRPCProtocol {
|
||||
|
||||
// --- main thread
|
||||
|
||||
export interface MainThreadClipboardShape extends IDisposable {
|
||||
$readText(): Promise<string>;
|
||||
$writeText(value: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadCommandsShape extends IDisposable {
|
||||
$registerCommand(id: string): void;
|
||||
$unregisterCommand(id: string): void;
|
||||
@@ -93,17 +108,23 @@ export interface MainThreadCommandsShape extends IDisposable {
|
||||
$getCommands(): Thenable<string[]>;
|
||||
}
|
||||
|
||||
export interface CommentProviderFeatures {
|
||||
startDraftLabel?: string;
|
||||
deleteDraftLabel?: string;
|
||||
finishDraftLabel?: string;
|
||||
}
|
||||
|
||||
export interface MainThreadCommentsShape extends IDisposable {
|
||||
$registerDocumentCommentProvider(handle: number): void;
|
||||
$registerDocumentCommentProvider(handle: number, features: CommentProviderFeatures): void;
|
||||
$unregisterDocumentCommentProvider(handle: number): void;
|
||||
$registerWorkspaceCommentProvider(handle: number): void;
|
||||
$registerWorkspaceCommentProvider(handle: number, extensionId: string): void;
|
||||
$unregisterWorkspaceCommentProvider(handle: number): void;
|
||||
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent): void;
|
||||
}
|
||||
|
||||
export interface MainThreadConfigurationShape extends IDisposable {
|
||||
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: UriComponents): TPromise<void>;
|
||||
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: UriComponents): TPromise<void>;
|
||||
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: UriComponents): Thenable<void>;
|
||||
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: UriComponents): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadDiagnosticsShape extends IDisposable {
|
||||
@@ -127,8 +148,8 @@ export interface MainThreadDialogSaveOptions {
|
||||
}
|
||||
|
||||
export interface MainThreadDiaglogsShape extends IDisposable {
|
||||
$showOpenDialog(options: MainThreadDialogOpenOptions): Thenable<string[]>;
|
||||
$showSaveDialog(options: MainThreadDialogSaveOptions): Thenable<string>;
|
||||
$showOpenDialog(options: MainThreadDialogOpenOptions): Thenable<UriComponents[]>;
|
||||
$showSaveDialog(options: MainThreadDialogSaveOptions): Thenable<UriComponents>;
|
||||
}
|
||||
|
||||
export interface MainThreadDecorationsShape extends IDisposable {
|
||||
@@ -144,9 +165,9 @@ export interface MainThreadDocumentContentProvidersShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadDocumentsShape extends IDisposable {
|
||||
$tryCreateDocument(options?: { language?: string; content?: string; }): TPromise<UriComponents>;
|
||||
$tryOpenDocument(uri: UriComponents): TPromise<void>;
|
||||
$trySaveDocument(uri: UriComponents): TPromise<boolean>;
|
||||
$tryCreateDocument(options?: { language?: string; content?: string; }): Thenable<UriComponents>;
|
||||
$tryOpenDocument(uri: UriComponents): Thenable<void>;
|
||||
$trySaveDocument(uri: UriComponents): Thenable<boolean>;
|
||||
}
|
||||
|
||||
export interface ITextEditorConfigurationUpdate {
|
||||
@@ -187,26 +208,27 @@ export interface ITextDocumentShowOptions {
|
||||
}
|
||||
|
||||
export interface MainThreadTextEditorsShape extends IDisposable {
|
||||
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string>;
|
||||
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Thenable<string>;
|
||||
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
|
||||
$removeTextEditorDecorationType(key: string): void;
|
||||
$tryShowEditor(id: string, position: EditorViewColumn): TPromise<void>;
|
||||
$tryHideEditor(id: string): TPromise<void>;
|
||||
$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[]>;
|
||||
$tryShowEditor(id: string, position: EditorViewColumn): Thenable<void>;
|
||||
$tryHideEditor(id: string): Thenable<void>;
|
||||
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Thenable<void>;
|
||||
$trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): Thenable<void>;
|
||||
$trySetDecorationsFast(id: string, key: string, ranges: number[]): Thenable<void>;
|
||||
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Thenable<void>;
|
||||
$trySetSelections(id: string, selections: ISelection[]): Thenable<void>;
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Thenable<boolean>;
|
||||
$tryApplyWorkspaceEdit(workspaceEditDto: WorkspaceEditDto): Thenable<boolean>;
|
||||
$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): Thenable<boolean>;
|
||||
$getDiffInformation(id: string): Thenable<editorCommon.ILineChange[]>;
|
||||
}
|
||||
|
||||
export interface MainThreadTreeViewsShape extends IDisposable {
|
||||
$registerTreeViewDataProvider(treeViewId: string): void;
|
||||
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): TPromise<void>;
|
||||
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: { select: boolean, focus: boolean }): TPromise<void>;
|
||||
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean }): void;
|
||||
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Thenable<void>;
|
||||
$reveal(treeViewId: string, treeItem: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Thenable<void>;
|
||||
$setMessage(treeViewId: string, message: string | IMarkdownString): void;
|
||||
}
|
||||
|
||||
export interface MainThreadErrorsShape extends IDisposable {
|
||||
@@ -226,6 +248,7 @@ export interface ISerializedIndentationRule {
|
||||
export interface ISerializedOnEnterRule {
|
||||
beforeText: ISerializedRegExp;
|
||||
afterText?: ISerializedRegExp;
|
||||
oneLineAboveText?: ISerializedRegExp;
|
||||
action: EnterAction;
|
||||
}
|
||||
export interface ISerializedLanguageConfiguration {
|
||||
@@ -260,12 +283,18 @@ export interface ISerializedDocumentFilter {
|
||||
exclusive?: boolean;
|
||||
}
|
||||
|
||||
export interface ISerializedSignatureHelpProviderMetadata {
|
||||
readonly triggerCharacters: ReadonlyArray<string>;
|
||||
readonly retriggerCharacters: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$unregister(handle: number): void;
|
||||
$registerOutlineSupport(handle: number, selector: ISerializedDocumentFilter[], extensionId: string): void;
|
||||
$registerOutlineSupport(handle: number, selector: ISerializedDocumentFilter[], label: string): void;
|
||||
$registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void;
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): void;
|
||||
$registerDeclaractionSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerImplementationSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerTypeDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
@@ -278,15 +307,17 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerNavigateTypeSupport(handle: number): void;
|
||||
$registerRenameSupport(handle: number, selector: ISerializedDocumentFilter[], supportsResolveInitialValues: boolean): void;
|
||||
$registerSuggestSupport(handle: number, selector: ISerializedDocumentFilter[], triggerCharacters: string[], supportsResolveDetails: boolean): void;
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], triggerCharacter: string[]): void;
|
||||
$registerSignatureHelpProvider(handle: number, selector: ISerializedDocumentFilter[], metadata: ISerializedSignatureHelpProviderMetadata): void;
|
||||
$registerDocumentLinkProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
|
||||
$setLanguageConfiguration(handle: number, languageId: string, configuration: ISerializedLanguageConfiguration): void;
|
||||
}
|
||||
|
||||
export interface MainThreadLanguagesShape extends IDisposable {
|
||||
$getLanguages(): TPromise<string[]>;
|
||||
$getLanguages(): Thenable<string[]>;
|
||||
$changeLanguage(resource: UriComponents, languageId: string): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadMessageOptions {
|
||||
@@ -299,11 +330,13 @@ export interface MainThreadMessageServiceShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadOutputServiceShape extends IDisposable {
|
||||
$append(channelId: string, label: string, value: string): TPromise<void>;
|
||||
$clear(channelId: string, label: string): TPromise<void>;
|
||||
$dispose(channelId: string, label: string): TPromise<void>;
|
||||
$reveal(channelId: string, label: string, preserveFocus: boolean): TPromise<void>;
|
||||
$close(channelId: string): TPromise<void>;
|
||||
$register(label: string, log: boolean, file?: UriComponents): Thenable<string>;
|
||||
$append(channelId: string, value: string): Thenable<void>;
|
||||
$update(channelId: string): Thenable<void>;
|
||||
$clear(channelId: string, till: number): Thenable<void>;
|
||||
$reveal(channelId: string, preserveFocus: boolean): Thenable<void>;
|
||||
$close(channelId: string): Thenable<void>;
|
||||
$dispose(channelId: string): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadProgressShape extends IDisposable {
|
||||
@@ -314,8 +347,8 @@ export interface MainThreadProgressShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number>;
|
||||
$createTerminalRenderer(name: string): TPromise<number>;
|
||||
$createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): Thenable<number>;
|
||||
$createTerminalRenderer(name: string): Thenable<number>;
|
||||
$dispose(terminalId: number): void;
|
||||
$hide(terminalId: number): void;
|
||||
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
|
||||
@@ -401,12 +434,12 @@ export interface TransferInputBox extends BaseTransferQuickInput {
|
||||
}
|
||||
|
||||
export interface MainThreadQuickOpenShape extends IDisposable {
|
||||
$show(options: IPickOptions<TransferQuickPickItems>): TPromise<number | number[]>;
|
||||
$setItems(items: TransferQuickPickItems[]): TPromise<any>;
|
||||
$setError(error: Error): TPromise<any>;
|
||||
$input(options: vscode.InputBoxOptions, validateInput: boolean): TPromise<string>;
|
||||
$createOrUpdate(params: TransferQuickInput): TPromise<void>;
|
||||
$dispose(id: number): TPromise<void>;
|
||||
$show(instance: number, options: IPickOptions<TransferQuickPickItems>, token: CancellationToken): Thenable<number | number[]>;
|
||||
$setItems(instance: number, items: TransferQuickPickItems[]): Thenable<void>;
|
||||
$setError(instance: number, error: Error): Thenable<void>;
|
||||
$input(options: vscode.InputBoxOptions, validateInput: boolean, token: CancellationToken): Thenable<string>;
|
||||
$createOrUpdate(params: TransferQuickInput): Thenable<void>;
|
||||
$dispose(id: number): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadStatusBarShape extends IDisposable {
|
||||
@@ -415,8 +448,8 @@ 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<void>;
|
||||
$getValue<T>(shared: boolean, key: string): Thenable<T>;
|
||||
$setValue(shared: boolean, key: string, value: object): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadTelemetryShape extends IDisposable {
|
||||
@@ -431,7 +464,7 @@ export interface WebviewPanelShowOptions {
|
||||
}
|
||||
|
||||
export interface MainThreadWebviewsShape extends IDisposable {
|
||||
$createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: vscode.WebviewPanelOptions & vscode.WebviewOptions, extensionLocation: UriComponents): void;
|
||||
$createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: vscode.WebviewPanelOptions & vscode.WebviewOptions, extensionId: string, extensionLocation: UriComponents): void;
|
||||
$disposeWebview(handle: WebviewPanelHandle): void;
|
||||
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
|
||||
$setTitle(handle: WebviewPanelHandle, value: string): void;
|
||||
@@ -458,20 +491,21 @@ export interface ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
$registerUriHandler(handle: number, extensionId: string): TPromise<void>;
|
||||
$unregisterUriHandler(handle: number): TPromise<void>;
|
||||
$registerUriHandler(handle: number, extensionId: string): Thenable<void>;
|
||||
$unregisterUriHandler(handle: number): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostUrlsShape {
|
||||
$handleExternalUri(handle: number, uri: UriComponents): TPromise<void>;
|
||||
$handleExternalUri(handle: number, uri: UriComponents): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadWorkspaceShape extends IDisposable {
|
||||
$startFileSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<UriComponents[]>;
|
||||
$startTextSearch(query: IPatternInfo, options: IQueryOptions, requestId: number): TPromise<void>;
|
||||
$cancelSearch(requestId: number): Thenable<boolean>;
|
||||
$startFileSearch(includePattern: string, includeFolder: URI, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Thenable<UriComponents[]>;
|
||||
$startTextSearch(query: IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Thenable<vscode.TextSearchComplete>;
|
||||
$checkExists(includes: string[], token: CancellationToken): Thenable<boolean>;
|
||||
$saveAll(includeUntitled?: boolean): Thenable<boolean>;
|
||||
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void>;
|
||||
$resolveProxy(url: string): Thenable<string>;
|
||||
}
|
||||
|
||||
export interface IFileChangeDto {
|
||||
@@ -482,6 +516,7 @@ export interface IFileChangeDto {
|
||||
export interface MainThreadFileSystemShape extends IDisposable {
|
||||
$registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): void;
|
||||
$unregisterProvider(handle: number): void;
|
||||
$setUriFormatter(scheme: string, formatter: LabelRules): void;
|
||||
$onFileSystemChange(handle: number, resource: IFileChangeDto[]): void;
|
||||
}
|
||||
|
||||
@@ -496,11 +531,11 @@ export interface MainThreadSearchShape extends IDisposable {
|
||||
}
|
||||
|
||||
export interface MainThreadTaskShape extends IDisposable {
|
||||
$registerTaskProvider(handle: number): TPromise<void>;
|
||||
$unregisterTaskProvider(handle: number): TPromise<void>;
|
||||
$fetchTasks(filter?: TaskFilterDTO): TPromise<TaskDTO[]>;
|
||||
$executeTask(task: TaskHandleDTO | TaskDTO): TPromise<TaskExecutionDTO>;
|
||||
$terminateTask(id: string): TPromise<void>;
|
||||
$registerTaskProvider(handle: number): Thenable<void>;
|
||||
$unregisterTaskProvider(handle: number): Thenable<void>;
|
||||
$fetchTasks(filter?: TaskFilterDTO): Thenable<TaskDTO[]>;
|
||||
$executeTask(task: TaskHandleDTO | TaskDTO): Thenable<TaskExecutionDTO>;
|
||||
$terminateTask(id: string): Thenable<void>;
|
||||
$registerTaskSystem(scheme: string, info: TaskSystemInfoDTO): void;
|
||||
}
|
||||
|
||||
@@ -562,6 +597,7 @@ export interface MainThreadSCMShape extends IDisposable {
|
||||
|
||||
$setInputBoxValue(sourceControlHandle: number, value: string): void;
|
||||
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
|
||||
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void;
|
||||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
|
||||
}
|
||||
|
||||
@@ -575,20 +611,24 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
|
||||
$acceptDAError(handle: number, name: string, message: string, stack: string): void;
|
||||
$acceptDAExit(handle: number, code: number, signal: string): void;
|
||||
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<any>;
|
||||
$unregisterDebugConfigurationProvider(handle: number): TPromise<any>;
|
||||
$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>;
|
||||
$registerDebugConfigurationProvider(type: string, hasProvideMethod: boolean, hasResolveMethod: boolean, hasProvideDaMethod: boolean, hasProvideTrackerMethod: boolean, handle: number): Thenable<void>;
|
||||
$registerDebugAdapterDescriptorFactory(type: string, handle: number): Thenable<void>;
|
||||
$registerDebugAdapterTrackerFactory(type: string, handle: number);
|
||||
$unregisterDebugConfigurationProvider(handle: number): void;
|
||||
$unregisterDebugAdapterDescriptorFactory(handle: number): void;
|
||||
$unregisterDebugAdapterTrackerFactory(handle: number): void;
|
||||
$startDebugging(folder: UriComponents | undefined, nameOrConfig: string | vscode.DebugConfiguration): Thenable<boolean>;
|
||||
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Thenable<any>;
|
||||
$appendDebugConsole(value: string): void;
|
||||
$startBreakpointEvents(): void;
|
||||
$registerBreakpoints(breakpoints: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): Thenable<void>;
|
||||
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): Thenable<void>;
|
||||
}
|
||||
// {{SQL CARBON EDIT}}
|
||||
*/
|
||||
|
||||
export interface MainThreadWindowShape extends IDisposable {
|
||||
$getWindowVisibility(): TPromise<boolean>;
|
||||
$getWindowVisibility(): Thenable<boolean>;
|
||||
}
|
||||
|
||||
// -- extension host
|
||||
@@ -607,7 +647,7 @@ export interface ExtHostDiagnosticsShape {
|
||||
}
|
||||
|
||||
export interface ExtHostDocumentContentProvidersShape {
|
||||
$provideTextDocumentContent(handle: number, uri: UriComponents): TPromise<string>;
|
||||
$provideTextDocumentContent(handle: number, uri: UriComponents): Promise<string>;
|
||||
}
|
||||
|
||||
export interface IModelAddedData {
|
||||
@@ -668,7 +708,8 @@ export interface ExtHostDocumentsAndEditorsShape {
|
||||
}
|
||||
|
||||
export interface ExtHostTreeViewsShape {
|
||||
$getChildren(treeViewId: string, treeItemHandle?: string): TPromise<ITreeItem[]>;
|
||||
// {{SQL CARBON EDIT}}
|
||||
$getChildren(treeViewId: string, treeItemHandle?: string): Thenable<sqlITreeItem[]>;
|
||||
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
|
||||
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
|
||||
$setVisible(treeViewId: string, visible: boolean): void;
|
||||
@@ -680,26 +721,32 @@ export interface ExtHostWorkspaceShape {
|
||||
}
|
||||
|
||||
export interface ExtHostFileSystemShape {
|
||||
$stat(handle: number, resource: UriComponents): TPromise<IStat>;
|
||||
$readdir(handle: number, resource: UriComponents): TPromise<[string, FileType][]>;
|
||||
$readFile(handle: number, resource: UriComponents): TPromise<string>;
|
||||
$writeFile(handle: number, resource: UriComponents, base64Encoded: string, opts: FileWriteOptions): TPromise<void>;
|
||||
$rename(handle: number, resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): TPromise<void>;
|
||||
$copy(handle: number, resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): TPromise<void>;
|
||||
$mkdir(handle: number, resource: UriComponents): TPromise<void>;
|
||||
$delete(handle: number, resource: UriComponents, opts: FileDeleteOptions): TPromise<void>;
|
||||
$stat(handle: number, resource: UriComponents): Thenable<IStat>;
|
||||
$readdir(handle: number, resource: UriComponents): Thenable<[string, FileType][]>;
|
||||
$readFile(handle: number, resource: UriComponents): Thenable<Buffer>;
|
||||
$writeFile(handle: number, resource: UriComponents, content: Buffer, opts: FileWriteOptions): Thenable<void>;
|
||||
$rename(handle: number, resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Thenable<void>;
|
||||
$copy(handle: number, resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Thenable<void>;
|
||||
$mkdir(handle: number, resource: UriComponents): Thenable<void>;
|
||||
$delete(handle: number, resource: UriComponents, opts: FileDeleteOptions): Thenable<void>;
|
||||
$watch(handle: number, session: number, resource: UriComponents, opts: IWatchOptions): void;
|
||||
$unwatch(handle: number, session: number): void;
|
||||
$open(handle: number, resource: UriComponents): Thenable<number>;
|
||||
$close(handle: number, fd: number): Thenable<void>;
|
||||
$read(handle: number, fd: number, pos: number, data: Buffer, offset: number, length: number): Thenable<number>;
|
||||
$write(handle: number, fd: number, pos: number, data: Buffer, offset: number, length: number): Thenable<number>;
|
||||
}
|
||||
|
||||
export interface ExtHostSearchShape {
|
||||
$provideFileSearchResults(handle: number, session: number, query: IRawSearchQuery): TPromise<ISearchCompleteStats>;
|
||||
$clearCache(cacheKey: string): TPromise<void>;
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, query: IRawSearchQuery): TPromise<ISearchCompleteStats>;
|
||||
$provideFileSearchResults(handle: number, session: number, query: IRawQuery, token: CancellationToken): Thenable<ISearchCompleteStats>;
|
||||
$provideTextSearchResults(handle: number, session: number, query: IRawTextQuery, token: CancellationToken): Thenable<ISearchCompleteStats>;
|
||||
$clearCache(cacheKey: string): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostExtensionServiceShape {
|
||||
$activateByEvent(activationEvent: string): TPromise<void>;
|
||||
$resolveAuthority(remoteAuthority: string): Thenable<ResolvedAuthority>;
|
||||
$startExtensionHost(enabledExtensionIds: string[]): Thenable<void>;
|
||||
$activateByEvent(activationEvent: string): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface FileSystemEvents {
|
||||
@@ -710,7 +757,7 @@ export interface FileSystemEvents {
|
||||
export interface ExtHostFileSystemEventServiceShape {
|
||||
$onFileEvent(events: FileSystemEvents): void;
|
||||
$onFileRename(oldUri: UriComponents, newUri: UriComponents): void;
|
||||
$onWillRename(oldUri: UriComponents, newUri: UriComponents): TPromise<any>;
|
||||
$onWillRename(oldUri: UriComponents, newUri: UriComponents): Thenable<any>;
|
||||
}
|
||||
|
||||
export interface ObjectIdentifier {
|
||||
@@ -745,7 +792,7 @@ export class IdObject {
|
||||
}
|
||||
}
|
||||
|
||||
export interface SuggestionDto extends modes.ISuggestion {
|
||||
export interface SuggestionDto extends modes.CompletionItem {
|
||||
_id: number;
|
||||
_parentId: number;
|
||||
}
|
||||
@@ -820,38 +867,40 @@ export interface CodeActionDto {
|
||||
}
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<modes.DocumentSymbol[]>;
|
||||
$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<DefinitionLinkDto[]>;
|
||||
$provideImplementation(handle: number, resource: UriComponents, position: IPosition): TPromise<DefinitionLinkDto[]>;
|
||||
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<DefinitionLinkDto[]>;
|
||||
$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, rangeOrSelection: IRange | ISelection, 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: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto>;
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.DocumentSymbol[]>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.ICodeLensSymbol[]>;
|
||||
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol, token: CancellationToken): Thenable<modes.ICodeLensSymbol>;
|
||||
$provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<DefinitionLinkDto[]>;
|
||||
$provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<DefinitionLinkDto[]>;
|
||||
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<DefinitionLinkDto[]>;
|
||||
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<DefinitionLinkDto[]>;
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.Hover>;
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]>;
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<LocationDto[]>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Thenable<CodeActionDto[]>;
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]>;
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]>;
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]>;
|
||||
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Thenable<WorkspaceSymbolsDto>;
|
||||
$resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Thenable<WorkspaceSymbolDto>;
|
||||
$releaseWorkspaceSymbols(handle: number, id: number): void;
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<WorkspaceEditDto>;
|
||||
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.RenameLocation>;
|
||||
$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>;
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Thenable<WorkspaceEditDto>;
|
||||
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.RenameLocation>;
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Thenable<SuggestResultDto>;
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.CompletionItem, token: CancellationToken): Thenable<modes.CompletionItem>;
|
||||
$releaseCompletionItems(handle: number, id: number): void;
|
||||
$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: UriComponents): TPromise<IRawColorInfo[]>;
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]>;
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext): TPromise<modes.FoldingRange[]>;
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Thenable<modes.SignatureHelp>;
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.ILink[]>;
|
||||
$resolveDocumentLink(handle: number, link: modes.ILink, token: CancellationToken): Thenable<modes.ILink>;
|
||||
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Thenable<IRawColorInfo[]>;
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Thenable<modes.IColorPresentation[]>;
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Thenable<modes.FoldingRange[]>;
|
||||
$provideSelectionRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<IRange[]>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
$onItemSelected(handle: number): void;
|
||||
$validateInput(input: string): TPromise<string>;
|
||||
$validateInput(input: string): Thenable<string>;
|
||||
$onDidChangeActive(sessionId: number, handles: number[]): void;
|
||||
$onDidChangeSelection(sessionId: number, handles: number[]): void;
|
||||
$onDidAccept(sessionId: number): void;
|
||||
@@ -875,27 +924,29 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalProcessId(id: number, processId: number): void;
|
||||
$acceptTerminalProcessData(id: number, data: string): void;
|
||||
$acceptTerminalRendererInput(id: number, data: string): void;
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void;
|
||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, cols: number, rows: number): void;
|
||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: URI, cols: number, rows: number): void;
|
||||
$acceptProcessInput(id: number, data: string): void;
|
||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||
$acceptProcessShutdown(id: number): void;
|
||||
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
||||
}
|
||||
|
||||
export interface ExtHostSCMShape {
|
||||
$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>;
|
||||
$provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Thenable<UriComponents>;
|
||||
$onInputBoxValueChange(sourceControlHandle: number, value: string): void;
|
||||
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): Thenable<void>;
|
||||
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Thenable<[string, number] | undefined>;
|
||||
$setSelectedSourceControls(selectedSourceControlHandles: number[]): Thenable<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostTaskShape {
|
||||
$provideTasks(handle: number, validTypes: { [key: string]: boolean; }): TPromise<TaskSet>;
|
||||
$provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<TaskSet>;
|
||||
$onDidStartTask(execution: TaskExecutionDTO): void;
|
||||
$onDidStartTaskProcess(value: TaskProcessStartedDTO): void;
|
||||
$onDidEndTaskProcess(value: TaskProcessEndedDTO): void;
|
||||
$OnDidEndTask(execution: TaskExecutionDTO): void;
|
||||
$resolveVariables(workspaceFolder: UriComponents, variables: string[]): TPromise<any>;
|
||||
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string }, variables: string[] }): Thenable<{ process?: string; variables: { [key: string]: string } }>;
|
||||
}
|
||||
|
||||
export interface IBreakpointDto {
|
||||
@@ -941,20 +992,31 @@ export interface ISourceMultiBreakpointDto {
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
/*
|
||||
export interface IDebugSessionFullDto {
|
||||
id: DebugSessionUUID;
|
||||
type: string;
|
||||
name: string;
|
||||
folderUri: UriComponents | undefined;
|
||||
configuration: IConfig;
|
||||
}
|
||||
|
||||
export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID;
|
||||
|
||||
export interface ExtHostDebugServiceShape {
|
||||
$substituteVariables(folder: UriComponents | undefined, config: IConfig): TPromise<IConfig>;
|
||||
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise<void>;
|
||||
$startDASession(handle: number, debugType: string, adapterExecutableInfo: IAdapterExecutable | null, debugPort: number): TPromise<void>;
|
||||
$stopDASession(handle: number): TPromise<void>;
|
||||
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): TPromise<void>;
|
||||
$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: IBreakpointsDeltaDto): void;
|
||||
$substituteVariables(folder: UriComponents | undefined, config: IConfig): Thenable<IConfig>;
|
||||
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Thenable<number | undefined>;
|
||||
$startDASession(handle: number, session: IDebugSessionDto): Thenable<void>;
|
||||
$stopDASession(handle: number): Thenable<void>;
|
||||
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
|
||||
$resolveDebugConfiguration(handle: number, folder: UriComponents | undefined, debugConfiguration: IConfig): Thenable<IConfig>;
|
||||
$provideDebugConfigurations(handle: number, folder: UriComponents | undefined): Thenable<IConfig[]>;
|
||||
$legacyDebugAdapterExecutable(handle: number, folderUri: UriComponents | undefined): Thenable<IAdapterDescriptor>; // TODO@AW legacy
|
||||
$provideDebugAdapter(handle: number, session: IDebugSessionDto): Thenable<IAdapterDescriptor>;
|
||||
$acceptDebugSessionStarted(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionTerminated(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionActiveChanged(session: IDebugSessionDto): void;
|
||||
$acceptDebugSessionCustomEvent(session: IDebugSessionDto, event: any): void;
|
||||
$acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void;
|
||||
}
|
||||
// {{SQL CARBON EDIT}}
|
||||
*/
|
||||
@@ -969,7 +1031,7 @@ export type DecorationData = [number, boolean, string, string, ThemeColor, strin
|
||||
export type DecorationReply = { [id: number]: DecorationData };
|
||||
|
||||
export interface ExtHostDecorationsShape {
|
||||
$provideDecorations(requests: DecorationRequest[]): TPromise<DecorationReply>;
|
||||
$provideDecorations(requests: DecorationRequest[], token: CancellationToken): Thenable<DecorationReply>;
|
||||
}
|
||||
|
||||
export interface ExtHostWindowShape {
|
||||
@@ -980,20 +1042,34 @@ export interface ExtHostLogServiceShape {
|
||||
$setLevel(level: LogLevel): void;
|
||||
}
|
||||
|
||||
export interface ExtHostOutputServiceShape {
|
||||
$setVisibleChannel(channelId: string | null): void;
|
||||
}
|
||||
|
||||
export interface ExtHostProgressShape {
|
||||
$acceptProgressCanceled(handle: number): void;
|
||||
}
|
||||
|
||||
export interface ExtHostCommentsShape {
|
||||
$provideDocumentComments(handle: number, document: UriComponents): TPromise<modes.CommentInfo>;
|
||||
$createNewCommentThread?(handle: number, document: UriComponents, range: IRange, text: string): TPromise<modes.CommentThread>;
|
||||
$replyToCommentThread?(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): TPromise<modes.CommentThread>;
|
||||
$provideWorkspaceComments(handle: number): TPromise<modes.CommentThread[]>;
|
||||
$provideDocumentComments(handle: number, document: UriComponents): Thenable<modes.CommentInfo>;
|
||||
$createNewCommentThread(handle: number, document: UriComponents, range: IRange, text: string): Thenable<modes.CommentThread>;
|
||||
$replyToCommentThread(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): Thenable<modes.CommentThread>;
|
||||
$editComment(handle: number, document: UriComponents, comment: modes.Comment, text: string): Thenable<void>;
|
||||
$deleteComment(handle: number, document: UriComponents, comment: modes.Comment): Thenable<void>;
|
||||
$startDraft(handle: number): Thenable<void>;
|
||||
$deleteDraft(handle: number): Thenable<void>;
|
||||
$finishDraft(handle: number): Thenable<void>;
|
||||
$provideWorkspaceComments(handle: number): Thenable<modes.CommentThread[]>;
|
||||
}
|
||||
|
||||
export interface ExtHostStorageShape {
|
||||
$acceptValue(shared: boolean, key: string, value: object): void;
|
||||
}
|
||||
|
||||
// --- proxy identifiers
|
||||
|
||||
export const MainContext = {
|
||||
MainThreadClipboard: <ProxyIdentifier<MainThreadClipboardShape>>createMainId<MainThreadClipboardShape>('MainThreadClipboard'),
|
||||
MainThreadCommands: <ProxyIdentifier<MainThreadCommandsShape>>createMainId<MainThreadCommandsShape>('MainThreadCommands'),
|
||||
MainThreadComments: createMainId<MainThreadCommentsShape>('MainThreadComments'),
|
||||
MainThreadConfiguration: createMainId<MainThreadConfigurationShape>('MainThreadConfiguration'),
|
||||
@@ -1057,5 +1133,7 @@ export const ExtHostContext = {
|
||||
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
|
||||
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'),
|
||||
ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'),
|
||||
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls')
|
||||
ExtHostStorage: createMainId<ExtHostStorageShape>('ExtHostStorage'),
|
||||
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls'),
|
||||
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
|
||||
};
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
@@ -19,7 +17,8 @@ import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { CustomCodeAction } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { ICommandsExecutor, PreviewHTMLAPICommand, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
|
||||
export class ExtHostApiCommands {
|
||||
|
||||
@@ -49,6 +48,14 @@ export class ExtHostApiCommands {
|
||||
],
|
||||
returns: 'A promise that resolves to an array of Location-instances.'
|
||||
});
|
||||
this._register('vscode.executeDeclarationProvider', this._executeDeclaraionProvider, {
|
||||
description: 'Execute all declaration provider.',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position of a symbol', constraint: types.Position }
|
||||
],
|
||||
returns: 'A promise that resolves to an array of Location-instances.'
|
||||
});
|
||||
this._register('vscode.executeTypeDefinitionProvider', this._executeTypeDefinitionProvider, {
|
||||
description: 'Execute all type definition providers.',
|
||||
args: [
|
||||
@@ -112,7 +119,7 @@ export class ExtHostApiCommands {
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI }
|
||||
],
|
||||
returns: 'A promise that resolves to an array of SymbolInformation-instances.'
|
||||
returns: 'A promise that resolves to an array of SymbolInformation and DocumentSymbol instances.'
|
||||
});
|
||||
this._register('vscode.executeCompletionItemProvider', this._executeCompletionItemProvider, {
|
||||
description: 'Execute completion item provider.',
|
||||
@@ -189,7 +196,14 @@ export class ExtHostApiCommands {
|
||||
],
|
||||
returns: 'A promise that resolves to an array of ColorPresentation objects.'
|
||||
});
|
||||
|
||||
this._register('vscode.executeSelectionRangeProvider', this._executeSelectionRangeProvider, {
|
||||
description: 'Execute selection range provider.',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position }
|
||||
],
|
||||
returns: 'A promise that resolves to an array of ranges.'
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The following commands are registered on both sides separately.
|
||||
@@ -294,6 +308,15 @@ export class ExtHostApiCommands {
|
||||
.then(tryMapWith(typeConverters.location.to));
|
||||
}
|
||||
|
||||
private _executeDeclaraionProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
|
||||
const args = {
|
||||
resource,
|
||||
position: position && typeConverters.Position.from(position)
|
||||
};
|
||||
return this._commands.executeCommand<modes.Location[]>('_executeDeclarationProvider', args)
|
||||
.then(tryMapWith(typeConverters.location.to));
|
||||
}
|
||||
|
||||
private _executeTypeDefinitionProvider(resource: URI, position: types.Position): Thenable<types.Location[]> {
|
||||
const args = {
|
||||
resource,
|
||||
@@ -350,7 +373,7 @@ export class ExtHostApiCommands {
|
||||
return undefined;
|
||||
}
|
||||
if (value.rejectReason) {
|
||||
return TPromise.wrapError<types.WorkspaceEdit>(new Error(value.rejectReason));
|
||||
return Promise.reject(new Error(value.rejectReason));
|
||||
}
|
||||
return typeConverters.WorkspaceEdit.to(value);
|
||||
});
|
||||
@@ -377,11 +400,10 @@ export class ExtHostApiCommands {
|
||||
triggerCharacter,
|
||||
maxItemsToResolve
|
||||
};
|
||||
return this._commands.executeCommand<modes.ISuggestResult>('_executeCompletionItemProvider', args).then(result => {
|
||||
return this._commands.executeCommand<modes.CompletionList>('_executeCompletionItemProvider', args).then(result => {
|
||||
if (result) {
|
||||
const items = result.suggestions.map(suggestion => typeConverters.Suggest.to(position, suggestion));
|
||||
// {{SQL CARBON EDIT}}
|
||||
return new types.CompletionList(<any>items, result.incomplete);
|
||||
const items = result.suggestions.map(suggestion => typeConverters.CompletionItem.to(suggestion));
|
||||
return new types.CompletionList(items, result.incomplete);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
@@ -399,6 +421,19 @@ export class ExtHostApiCommands {
|
||||
});
|
||||
}
|
||||
|
||||
private _executeSelectionRangeProvider(resource: URI, position: types.Position): Thenable<types.Range[]> {
|
||||
const args = {
|
||||
resource,
|
||||
position: position && typeConverters.Position.from(position)
|
||||
};
|
||||
return this._commands.executeCommand<IRange[]>('_executeSelectionRangeProvider', args).then(result => {
|
||||
if (isNonEmptyArray(result)) {
|
||||
return result.map(typeConverters.Range.to);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
private _executeColorPresentationProvider(color: types.Color, context: { uri: URI, range: types.Range }): Thenable<types.ColorPresentation[]> {
|
||||
const args = {
|
||||
resource: context.uri,
|
||||
@@ -421,16 +456,27 @@ export class ExtHostApiCommands {
|
||||
if (isFalsyOrEmpty(value)) {
|
||||
return undefined;
|
||||
}
|
||||
let result: vscode.SymbolInformation[] = [];
|
||||
for (const symbol of value) {
|
||||
result.push(new types.SymbolInformation(
|
||||
symbol.name,
|
||||
typeConverters.SymbolKind.to(symbol.kind),
|
||||
symbol.containerName,
|
||||
new types.Location(resource, typeConverters.Range.to(symbol.range))
|
||||
));
|
||||
class MergedInfo extends types.SymbolInformation implements vscode.DocumentSymbol {
|
||||
static to(symbol: modes.DocumentSymbol): MergedInfo {
|
||||
let res = new MergedInfo(
|
||||
symbol.name,
|
||||
typeConverters.SymbolKind.to(symbol.kind),
|
||||
symbol.containerName,
|
||||
new types.Location(resource, typeConverters.Range.to(symbol.range))
|
||||
);
|
||||
res.detail = symbol.detail;
|
||||
res.range = res.location.range;
|
||||
res.selectionRange = typeConverters.Range.to(symbol.selectionRange);
|
||||
res.children = symbol.children && symbol.children.map(MergedInfo.to);
|
||||
return res;
|
||||
}
|
||||
|
||||
detail: string;
|
||||
range: vscode.Range;
|
||||
selectionRange: vscode.Range;
|
||||
children: vscode.DocumentSymbol[];
|
||||
}
|
||||
return result;
|
||||
return value.map(MergedInfo.to);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
24
src/vs/workbench/api/node/extHostClipboard.ts
Normal file
24
src/vs/workbench/api/node/extHostClipboard.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IMainContext, MainContext, MainThreadClipboardShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostClipboard implements vscode.Clipboard {
|
||||
|
||||
private readonly _proxy: MainThreadClipboardShape;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadClipboard);
|
||||
}
|
||||
|
||||
readText(): Promise<string> {
|
||||
return this._proxy.$readText();
|
||||
}
|
||||
|
||||
writeText(value: string): Promise<void> {
|
||||
return this._proxy.$writeText(value);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
* 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 { validateConstraint } from 'vs/base/common/types';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
@@ -11,7 +10,7 @@ import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverte
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { MainContext, MainThreadCommandsShape, ExtHostCommandsShape, ObjectIdentifier, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { isNonEmptyArray } 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';
|
||||
@@ -116,8 +115,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
try {
|
||||
validateConstraint(args[i], description.args[i].constraint);
|
||||
} catch (err) {
|
||||
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
|
||||
return <any>Promise.reject(new Error(`Running the contributed command:'${id}' failed. Illegal argument '${description.args[i].name}' - ${description.args[i].description}`));
|
||||
return Promise.reject(new Error(`Running the contributed command:'${id}' failed. Illegal argument '${description.args[i].name}' - ${description.args[i].description}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,8 +125,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
return Promise.resolve(result);
|
||||
} catch (err) {
|
||||
this._logService.error(err, id);
|
||||
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
|
||||
return <any>Promise.reject(new Error(`Running the contributed command:'${id}' failed.`));
|
||||
return Promise.reject(new Error(`Running the contributed command:'${id}' failed.`));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +133,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
this._logService.trace('ExtHostCommands#$executeContributedCommand', id);
|
||||
|
||||
if (!this._commands.has(id)) {
|
||||
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
|
||||
return <any>Promise.reject(new Error(`Contributed command '${id}' does not exist.`));
|
||||
return 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);
|
||||
@@ -193,7 +189,7 @@ export class CommandsConverter {
|
||||
title: command.title
|
||||
};
|
||||
|
||||
if (command.command && !isFalsyOrEmpty(command.arguments)) {
|
||||
if (command.command && isNonEmptyArray(command.arguments)) {
|
||||
// we have a contributed command with arguments. that
|
||||
// means we don't want to send the arguments around
|
||||
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { asThenable } from 'vs/base/common/async';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
@@ -15,6 +12,7 @@ import * as vscode from 'vscode';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol';
|
||||
import { CommandsConverter } from './extHostCommands';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class ExtHostComments implements ExtHostCommentsShape {
|
||||
private static handlePool = 0;
|
||||
@@ -33,11 +31,12 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
}
|
||||
|
||||
registerWorkspaceCommentProvider(
|
||||
extensionId: string,
|
||||
provider: vscode.WorkspaceCommentProvider
|
||||
): vscode.Disposable {
|
||||
const handle = ExtHostComments.handlePool++;
|
||||
this._workspaceProviders.set(handle, provider);
|
||||
this._proxy.$registerWorkspaceCommentProvider(handle);
|
||||
this._proxy.$registerWorkspaceCommentProvider(handle, extensionId);
|
||||
this.registerListeners(handle, provider);
|
||||
|
||||
return {
|
||||
@@ -53,7 +52,11 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
): vscode.Disposable {
|
||||
const handle = ExtHostComments.handlePool++;
|
||||
this._documentProviders.set(handle, provider);
|
||||
this._proxy.$registerDocumentCommentProvider(handle);
|
||||
this._proxy.$registerDocumentCommentProvider(handle, {
|
||||
startDraftLabel: provider.startDraftLabel,
|
||||
deleteDraftLabel: provider.deleteDraftLabel,
|
||||
finishDraftLabel: provider.finishDraftLabel
|
||||
});
|
||||
this.registerListeners(handle, provider);
|
||||
|
||||
return {
|
||||
@@ -64,57 +67,103 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
};
|
||||
}
|
||||
|
||||
$createNewCommentThread(handle: number, uri: UriComponents, range: IRange, text: string): TPromise<modes.CommentThread> {
|
||||
$createNewCommentThread(handle: number, uri: UriComponents, range: IRange, text: string): Thenable<modes.CommentThread> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
|
||||
|
||||
if (!data || !data.document) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => {
|
||||
let provider = this._documentProviders.get(handle);
|
||||
return provider.createNewCommentThread(data.document, ran, text, token);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(commentThread, this._commandsConverter) : null);
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.createNewCommentThread(data.document, ran, text, CancellationToken.None);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(provider, commentThread, this._commandsConverter) : null);
|
||||
}
|
||||
|
||||
$replyToCommentThread(handle: number, uri: UriComponents, range: IRange, thread: modes.CommentThread, text: string): TPromise<modes.CommentThread> {
|
||||
$replyToCommentThread(handle: number, uri: UriComponents, range: IRange, thread: modes.CommentThread, text: string): Thenable<modes.CommentThread> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
const ran = <vscode.Range>extHostTypeConverter.Range.to(range);
|
||||
|
||||
if (!data || !data.document) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => {
|
||||
let provider = this._documentProviders.get(handle);
|
||||
return provider.replyToCommentThread(data.document, ran, convertFromCommentThread(thread), text, token);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(commentThread, this._commandsConverter) : null);
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.replyToCommentThread(data.document, ran, convertFromCommentThread(thread), text, CancellationToken.None);
|
||||
}).then(commentThread => commentThread ? convertToCommentThread(provider, commentThread, this._commandsConverter) : null);
|
||||
}
|
||||
|
||||
$provideDocumentComments(handle: number, uri: UriComponents): TPromise<modes.CommentInfo> {
|
||||
$editComment(handle: number, uri: UriComponents, comment: modes.Comment, text: string): Thenable<void> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
|
||||
if (!data || !data.document) {
|
||||
throw new Error('Unable to retrieve document from URI');
|
||||
}
|
||||
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.editComment(data.document, convertFromComment(comment), text, CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$deleteComment(handle: number, uri: UriComponents, comment: modes.Comment): Thenable<void> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
|
||||
if (!data || !data.document) {
|
||||
throw new Error('Unable to retrieve document from URI');
|
||||
}
|
||||
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.deleteComment(data.document, convertFromComment(comment), CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$startDraft(handle: number): Thenable<void> {
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.startDraft(CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$deleteDraft(handle: number): Thenable<void> {
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.deleteDraft(CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$finishDraft(handle: number): Thenable<void> {
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.finishDraft(CancellationToken.None);
|
||||
});
|
||||
}
|
||||
|
||||
$provideDocumentComments(handle: number, uri: UriComponents): Thenable<modes.CommentInfo> {
|
||||
const data = this._documents.getDocumentData(URI.revive(uri));
|
||||
if (!data || !data.document) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => {
|
||||
let provider = this._documentProviders.get(handle);
|
||||
return provider.provideDocumentComments(data.document, token);
|
||||
})
|
||||
.then(commentInfo => commentInfo ? convertCommentInfo(handle, commentInfo, this._commandsConverter) : null);
|
||||
const provider = this._documentProviders.get(handle);
|
||||
return asThenable(() => {
|
||||
return provider.provideDocumentComments(data.document, CancellationToken.None);
|
||||
}).then(commentInfo => commentInfo ? convertCommentInfo(handle, provider, commentInfo, this._commandsConverter) : null);
|
||||
}
|
||||
|
||||
$provideWorkspaceComments(handle: number): TPromise<modes.CommentThread[]> {
|
||||
$provideWorkspaceComments(handle: number): Thenable<modes.CommentThread[]> {
|
||||
const provider = this._workspaceProviders.get(handle);
|
||||
if (!provider) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => {
|
||||
return provider.provideWorkspaceComments(token);
|
||||
return asThenable(() => {
|
||||
return provider.provideWorkspaceComments(CancellationToken.None);
|
||||
}).then(comments =>
|
||||
comments.map(x => convertToCommentThread(x, this._commandsConverter)
|
||||
comments.map(comment => convertToCommentThread(provider, comment, this._commandsConverter)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -122,29 +171,29 @@ export class ExtHostComments implements ExtHostCommentsShape {
|
||||
provider.onDidChangeCommentThreads(event => {
|
||||
|
||||
this._proxy.$onDidCommentThreadsChange(handle, {
|
||||
owner: handle,
|
||||
changed: event.changed.map(x => convertToCommentThread(x, this._commandsConverter)),
|
||||
added: event.added.map(x => convertToCommentThread(x, this._commandsConverter)),
|
||||
removed: event.removed.map(x => convertToCommentThread(x, this._commandsConverter))
|
||||
changed: event.changed.map(thread => convertToCommentThread(provider, thread, this._commandsConverter)),
|
||||
added: event.added.map(thread => convertToCommentThread(provider, thread, this._commandsConverter)),
|
||||
removed: event.removed.map(thread => convertToCommentThread(provider, thread, this._commandsConverter)),
|
||||
draftMode: !!(provider as vscode.DocumentCommentProvider).startDraft && !!(provider as vscode.DocumentCommentProvider).finishDraft ? (event.inDraftMode ? modes.DraftMode.InDraft : modes.DraftMode.NotInDraft) : modes.DraftMode.NotSupported
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function convertCommentInfo(owner: number, vscodeCommentInfo: vscode.CommentInfo, commandsConverter: CommandsConverter): modes.CommentInfo {
|
||||
function convertCommentInfo(owner: number, provider: vscode.DocumentCommentProvider, vscodeCommentInfo: vscode.CommentInfo, commandsConverter: CommandsConverter): modes.CommentInfo {
|
||||
return {
|
||||
owner: owner,
|
||||
threads: vscodeCommentInfo.threads.map(x => convertToCommentThread(x, commandsConverter)),
|
||||
commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : []
|
||||
threads: vscodeCommentInfo.threads.map(x => convertToCommentThread(provider, x, commandsConverter)),
|
||||
commentingRanges: vscodeCommentInfo.commentingRanges ? vscodeCommentInfo.commentingRanges.map(range => extHostTypeConverter.Range.from(range)) : [],
|
||||
draftMode: provider.startDraft && provider.finishDraft ? (vscodeCommentInfo.inDraftMode ? modes.DraftMode.InDraft : modes.DraftMode.NotInDraft) : modes.DraftMode.NotSupported
|
||||
};
|
||||
}
|
||||
|
||||
function convertToCommentThread(vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread {
|
||||
function convertToCommentThread(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread {
|
||||
return {
|
||||
threadId: vscodeCommentThread.threadId,
|
||||
resource: vscodeCommentThread.resource.toString(),
|
||||
range: extHostTypeConverter.Range.from(vscodeCommentThread.range),
|
||||
comments: vscodeCommentThread.comments.map(comment => convertToComment(comment, commandsConverter)),
|
||||
comments: vscodeCommentThread.comments.map(comment => convertToComment(provider, comment, commandsConverter)),
|
||||
collapsibleState: vscodeCommentThread.collapsibleState
|
||||
};
|
||||
}
|
||||
@@ -160,20 +209,38 @@ function convertFromCommentThread(commentThread: modes.CommentThread): vscode.Co
|
||||
}
|
||||
|
||||
function convertFromComment(comment: modes.Comment): vscode.Comment {
|
||||
let userIconPath: URI;
|
||||
if (comment.userIconPath) {
|
||||
try {
|
||||
userIconPath = URI.parse(comment.userIconPath);
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
commentId: comment.commentId,
|
||||
body: extHostTypeConverter.MarkdownString.to(comment.body),
|
||||
userName: comment.userName,
|
||||
gravatar: comment.gravatar
|
||||
userIconPath: userIconPath,
|
||||
canEdit: comment.canEdit,
|
||||
canDelete: comment.canDelete,
|
||||
isDraft: comment.isDraft
|
||||
};
|
||||
}
|
||||
|
||||
function convertToComment(vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment {
|
||||
function convertToComment(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment {
|
||||
const canEdit = !!(provider as vscode.DocumentCommentProvider).editComment && vscodeComment.canEdit;
|
||||
const canDelete = !!(provider as vscode.DocumentCommentProvider).deleteComment && vscodeComment.canDelete;
|
||||
const iconPath = vscodeComment.userIconPath ? vscodeComment.userIconPath.toString() : vscodeComment.gravatar;
|
||||
return {
|
||||
commentId: vscodeComment.commentId,
|
||||
body: extHostTypeConverter.MarkdownString.from(vscodeComment.body),
|
||||
userName: vscodeComment.userName,
|
||||
gravatar: vscodeComment.gravatar,
|
||||
command: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command) : null
|
||||
userIconPath: iconPath,
|
||||
canEdit: canEdit,
|
||||
canDelete: canDelete,
|
||||
command: vscodeComment.command ? commandsConverter.toInternal(vscodeComment.command) : null,
|
||||
isDraft: vscodeComment.isDraft
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
* 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 { mixin, deepClone } from 'vs/base/common/objects';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
@@ -18,8 +17,6 @@ import { ResourceMap } from 'vs/base/common/map';
|
||||
import { ConfigurationScope, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
|
||||
declare var Proxy: any; // TODO@TypeScript
|
||||
|
||||
function lookUp(tree: any, key: string) {
|
||||
if (key) {
|
||||
const parts = key.split('.');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,30 +2,33 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
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';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface ProviderData {
|
||||
provider: vscode.DecorationProvider;
|
||||
extensionId: string;
|
||||
}
|
||||
|
||||
export class ExtHostDecorations implements ExtHostDecorationsShape {
|
||||
|
||||
private static _handlePool = 0;
|
||||
|
||||
private readonly _provider = new Map<number, vscode.DecorationProvider>();
|
||||
private readonly _provider = new Map<number, ProviderData>();
|
||||
private readonly _proxy: MainThreadDecorationsShape;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadDecorations);
|
||||
}
|
||||
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider, label: string): vscode.Disposable {
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider, extensionId: string): vscode.Disposable {
|
||||
const handle = ExtHostDecorations._handlePool++;
|
||||
this._provider.set(handle, provider);
|
||||
this._proxy.$registerDecorationProvider(handle, label);
|
||||
this._provider.set(handle, { provider, extensionId });
|
||||
this._proxy.$registerDecorationProvider(handle, extensionId);
|
||||
|
||||
const listener = provider.onDidChangeDecorations(e => {
|
||||
this._proxy.$onDidChange(handle, !e ? null : Array.isArray(e) ? e : [e]);
|
||||
@@ -38,17 +41,20 @@ export class ExtHostDecorations implements ExtHostDecorationsShape {
|
||||
});
|
||||
}
|
||||
|
||||
$provideDecorations(requests: DecorationRequest[]): TPromise<DecorationReply> {
|
||||
$provideDecorations(requests: DecorationRequest[], token: CancellationToken): Thenable<DecorationReply> {
|
||||
const result: DecorationReply = Object.create(null);
|
||||
return TPromise.join(requests.map(request => {
|
||||
return Promise.all(requests.map(request => {
|
||||
const { handle, uri, id } = request;
|
||||
const provider = this._provider.get(handle);
|
||||
if (!provider) {
|
||||
if (!this._provider.has(handle)) {
|
||||
// might have been unregistered in the meantime
|
||||
return void 0;
|
||||
}
|
||||
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];
|
||||
const { provider, extensionId } = this._provider.get(handle);
|
||||
return Promise.resolve(provider.provideDecoration(URI.revive(uri), token)).then(data => {
|
||||
if (data && data.letter && data.letter.length !== 1) {
|
||||
console.warn(`INVALID decoration from extension '${extensionId}'. The 'letter' must be set and be one character, not '${data.letter}'.`);
|
||||
}
|
||||
result[id] = data && <DecorationData>[data.priority, data.bubble, data.title, data.letter, data.color, data.source];
|
||||
}, err => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
* 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 { localize } from 'vs/nls';
|
||||
import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape, IMainContext } from './extHost.protocol';
|
||||
import { DiagnosticSeverity } from './extHostTypes';
|
||||
import { DiagnosticSeverity, Diagnostic } from './extHostTypes';
|
||||
import * as converter from './extHostTypeConverters';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
import { mergeSort, equals } from 'vs/base/common/arrays';
|
||||
import { Event, Emitter, debounceEvent, mapEvent } from 'vs/base/common/event';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
|
||||
@@ -62,9 +61,13 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
|
||||
this._checkDisposed();
|
||||
let toSync: vscode.Uri[];
|
||||
let hasChanged = true;
|
||||
|
||||
if (first instanceof URI) {
|
||||
|
||||
// check if this has actually changed
|
||||
hasChanged = hasChanged && !equals(diagnostics, this.get(first), Diagnostic.isEqual);
|
||||
|
||||
if (!diagnostics) {
|
||||
// remove this entry
|
||||
this.delete(first);
|
||||
@@ -72,7 +75,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
}
|
||||
|
||||
// update single row
|
||||
this._data.set(first.toString(), diagnostics);
|
||||
this._data.set(first.toString(), diagnostics.slice());
|
||||
toSync = [first];
|
||||
|
||||
} else if (Array.isArray(first)) {
|
||||
@@ -103,6 +106,17 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
}
|
||||
}
|
||||
|
||||
// send event for extensions
|
||||
this._onDidChangeDiagnostics.fire(toSync);
|
||||
|
||||
// if nothing has changed then there is nothing else to do
|
||||
// we have updated the diagnostics but we don't send a message
|
||||
// to the renderer. tho we have still send an event for other
|
||||
// extensions because the diagnostic might carry more information
|
||||
// than known to us
|
||||
if (!hasChanged) {
|
||||
return;
|
||||
}
|
||||
// compute change and send to main side
|
||||
const entries: [URI, IMarkerData[]][] = [];
|
||||
for (let uri of toSync) {
|
||||
@@ -142,7 +156,6 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
|
||||
entries.push([uri, marker]);
|
||||
}
|
||||
|
||||
this._onDidChangeDiagnostics.fire(toSync);
|
||||
this._proxy.$changeMany(this._owner, entries);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MainContext, MainThreadDiaglogsShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
export class ExtHostDialogs {
|
||||
@@ -18,13 +17,13 @@ export class ExtHostDialogs {
|
||||
|
||||
showOpenDialog(options: vscode.OpenDialogOptions): Thenable<URI[]> {
|
||||
return this._proxy.$showOpenDialog(options).then(filepaths => {
|
||||
return filepaths && filepaths.map(URI.file);
|
||||
return filepaths && filepaths.map(URI.revive);
|
||||
});
|
||||
}
|
||||
|
||||
showSaveDialog(options: vscode.SaveDialogOptions): Thenable<URI> {
|
||||
return this._proxy.$showSaveDialog(options).then(filepath => {
|
||||
return filepath && URI.file(filepath);
|
||||
return filepath && URI.revive(filepath);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,17 @@
|
||||
* 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 { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import URI, { UriComponents } 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 { MainContext, ExtHostDocumentContentProvidersShape, MainThreadDocumentContentProvidersShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export class ExtHostDocumentContentProvider implements ExtHostDocumentContentProvidersShape {
|
||||
|
||||
@@ -86,11 +84,11 @@ export class ExtHostDocumentContentProvider implements ExtHostDocumentContentPro
|
||||
});
|
||||
}
|
||||
|
||||
$provideTextDocumentContent(handle: number, uri: UriComponents): TPromise<string> {
|
||||
$provideTextDocumentContent(handle: number, uri: UriComponents): Promise<string> {
|
||||
const provider = this._documentContentProviders.get(handle);
|
||||
if (!provider) {
|
||||
return TPromise.wrapError<string>(new Error(`unsupported uri-scheme: ${uri.scheme}`));
|
||||
return Promise.reject(new Error(`unsupported uri-scheme: ${uri.scheme}`));
|
||||
}
|
||||
return asWinJsPromise(token => provider.provideTextDocumentContent(URI.revive(uri), token));
|
||||
return Promise.resolve(provider.provideTextDocumentContent(URI.revive(uri), CancellationToken.None));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
* 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 { ok } from 'vs/base/common/assert';
|
||||
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
|
||||
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 { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { ensureValidWordDefinition, getWordAtText } from 'vs/editor/common/model/wordHelper';
|
||||
import { MainThreadDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { EndOfLine, Position, Range } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const _modeId2WordDefinition = new Map<string, RegExp>();
|
||||
export function setWordDefinitionFor(modeId: string, wordDefinition: RegExp): void {
|
||||
@@ -99,9 +97,9 @@ export class ExtHostDocumentData extends MirrorTextModel {
|
||||
this._isDirty = isDirty;
|
||||
}
|
||||
|
||||
private _save(): TPromise<boolean> {
|
||||
private _save(): Thenable<boolean> {
|
||||
if (this._isDisposed) {
|
||||
return TPromise.wrapError<boolean>(new Error('Document has been closed'));
|
||||
return Promise.reject(new Error('Document has been closed'));
|
||||
}
|
||||
return this._proxy.$trySaveDocument(this._uri);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
* 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 { Event } from 'vs/base/common/event';
|
||||
import URI, { UriComponents } 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 { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, ResourceTextEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
@@ -163,11 +162,11 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
|
||||
// apply edits if any and if document
|
||||
// didn't change somehow in the meantime
|
||||
if (resourceEdit.edits.length === 0) {
|
||||
return <any>undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (version === document.version) {
|
||||
return <any>this._mainThreadEditors.$tryApplyWorkspaceEdit({ edits: [resourceEdit] });
|
||||
return this._mainThreadEditors.$tryApplyWorkspaceEdit({ edits: [resourceEdit] });
|
||||
}
|
||||
|
||||
// TODO@joh bubble this to listener?
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
* 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 { Event, Emitter } from 'vs/base/common/event';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as TypeConverters from './extHostTypeConverters';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, MainThreadDocumentsShape, ExtHostDocumentsShape, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostDocumentData, setWordDefinitionFor } from './extHostDocumentData';
|
||||
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { ExtHostDocumentsShape, IMainContext, MainContext, MainThreadDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentData, setWordDefinitionFor } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
|
||||
@@ -30,7 +28,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
private _toDispose: IDisposable[];
|
||||
private _proxy: MainThreadDocumentsShape;
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
private _documentLoader = new Map<string, TPromise<ExtHostDocumentData>>();
|
||||
private _documentLoader = new Map<string, Thenable<ExtHostDocumentData>>();
|
||||
|
||||
constructor(mainContext: IMainContext, documentsAndEditors: ExtHostDocumentsAndEditors) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadDocuments);
|
||||
@@ -69,11 +67,11 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public ensureDocumentData(uri: URI): TPromise<ExtHostDocumentData> {
|
||||
public ensureDocumentData(uri: URI): Thenable<ExtHostDocumentData> {
|
||||
|
||||
let cached = this._documentsAndEditors.getDocument(uri.toString());
|
||||
if (cached) {
|
||||
return TPromise.as(cached);
|
||||
return Promise.resolve(cached);
|
||||
}
|
||||
|
||||
let promise = this._documentLoader.get(uri.toString());
|
||||
@@ -83,7 +81,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
return this._documentsAndEditors.getDocument(uri.toString());
|
||||
}, err => {
|
||||
this._documentLoader.delete(uri.toString());
|
||||
return TPromise.wrapError<ExtHostDocumentData>(err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
this._documentLoader.set(uri.toString(), promise);
|
||||
}
|
||||
@@ -91,7 +89,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
return promise;
|
||||
}
|
||||
|
||||
public createDocumentData(options?: { language?: string; content?: string }): TPromise<URI> {
|
||||
public createDocumentData(options?: { language?: string; content?: string }): Thenable<URI> {
|
||||
return this._proxy.$tryCreateDocument(options).then(data => URI.revive(data));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
* 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 { Event, Emitter } from 'vs/base/common/event';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { MainContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext } from './extHost.protocol';
|
||||
import { ExtHostDocumentData } from './extHostDocumentData';
|
||||
import { ExtHostTextEditor } from './extHostTextEditor';
|
||||
import * as assert from 'assert';
|
||||
import * as typeConverters from './extHostTypeConverters';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IMainContext, MainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/node/extHostTextEditor';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { Disposable } from 'vs/workbench/api/node/extHostTypes';
|
||||
|
||||
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
|
||||
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
* 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 nls from 'vs/nls';
|
||||
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/workbench/services/extensions/common/extensions';
|
||||
import { ExtHostLogger } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = TPromise.wrap<void>(void 0);
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(void 0);
|
||||
|
||||
export interface IExtensionMemento {
|
||||
get<T>(key: string, defaultValue: T): T;
|
||||
@@ -26,17 +23,17 @@ export interface IExtensionContext {
|
||||
globalState: IExtensionMemento;
|
||||
extensionPath: string;
|
||||
storagePath: string;
|
||||
globalStoragePath: string;
|
||||
asAbsolutePath(relativePath: string): string;
|
||||
logger: ExtHostLogger;
|
||||
readonly logDirectory: string;
|
||||
readonly logPath: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the source code (module) of an extension.
|
||||
*/
|
||||
export interface IExtensionModule {
|
||||
activate(ctx: IExtensionContext): TPromise<IExtensionAPI>;
|
||||
deactivate(): void;
|
||||
activate?(ctx: IExtensionContext): Promise<IExtensionAPI>;
|
||||
deactivate?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,6 +43,14 @@ export interface IExtensionAPI {
|
||||
// _extensionAPIBrand: any;
|
||||
}
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"ExtensionActivationTimes" : {
|
||||
"startup": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"codeLoadingTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"activateCallTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"activateResolvedTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
export class ExtensionActivationTimes {
|
||||
|
||||
public static readonly NONE = new ExtensionActivationTimes(false, -1, -1, -1);
|
||||
@@ -127,18 +132,18 @@ export class ExtensionActivationTimesBuilder {
|
||||
export class ActivatedExtension {
|
||||
|
||||
public readonly activationFailed: boolean;
|
||||
public readonly activationFailedError: Error;
|
||||
public readonly activationFailedError: Error | null;
|
||||
public readonly activationTimes: ExtensionActivationTimes;
|
||||
public readonly module: IExtensionModule;
|
||||
public readonly exports: IExtensionAPI;
|
||||
public readonly exports: IExtensionAPI | undefined;
|
||||
public readonly subscriptions: IDisposable[];
|
||||
|
||||
constructor(
|
||||
activationFailed: boolean,
|
||||
activationFailedError: Error,
|
||||
activationFailedError: Error | null,
|
||||
activationTimes: ExtensionActivationTimes,
|
||||
module: IExtensionModule,
|
||||
exports: IExtensionAPI,
|
||||
exports: IExtensionAPI | undefined,
|
||||
subscriptions: IDisposable[]
|
||||
) {
|
||||
this.activationFailed = activationFailed;
|
||||
@@ -165,7 +170,7 @@ export class FailedExtension extends ActivatedExtension {
|
||||
export interface IExtensionsActivatorHost {
|
||||
showMessage(severity: Severity, message: string): void;
|
||||
|
||||
actualActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TPromise<ActivatedExtension>;
|
||||
actualActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension>;
|
||||
}
|
||||
|
||||
export class ExtensionActivatedByEvent {
|
||||
@@ -187,7 +192,7 @@ export class ExtensionsActivator {
|
||||
|
||||
private readonly _registry: ExtensionDescriptionRegistry;
|
||||
private readonly _host: IExtensionsActivatorHost;
|
||||
private readonly _activatingExtensions: { [extensionId: string]: TPromise<void>; };
|
||||
private readonly _activatingExtensions: { [extensionId: string]: Promise<void>; };
|
||||
private readonly _activatedExtensions: { [extensionId: string]: ActivatedExtension; };
|
||||
/**
|
||||
* A map of already activated events to speed things up if the same activation event is triggered multiple times.
|
||||
@@ -213,7 +218,7 @@ export class ExtensionsActivator {
|
||||
return this._activatedExtensions[extensionId];
|
||||
}
|
||||
|
||||
public activateByEvent(activationEvent: string, reason: ExtensionActivationReason): TPromise<void> {
|
||||
public activateByEvent(activationEvent: string, reason: ExtensionActivationReason): Promise<void> {
|
||||
if (this._alreadyActivatedEvents[activationEvent]) {
|
||||
return NO_OP_VOID_PROMISE;
|
||||
}
|
||||
@@ -223,7 +228,7 @@ export class ExtensionsActivator {
|
||||
});
|
||||
}
|
||||
|
||||
public activateById(extensionId: string, reason: ExtensionActivationReason): TPromise<void> {
|
||||
public activateById(extensionId: string, reason: ExtensionActivationReason): Promise<void> {
|
||||
let desc = this._registry.getExtensionDescription(extensionId);
|
||||
if (!desc) {
|
||||
throw new Error('Extension `' + extensionId + '` is not known');
|
||||
@@ -246,7 +251,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', "Cannot activate extension '{0}' as the depending extension '{1}' is not found. Please install or enable the depending extension and reload the window.", currentExtension.displayName || currentExtension.id, depId));
|
||||
const error = new Error(`Unknown dependency '${depId}'`);
|
||||
this._activatedExtensions[currentExtension.id] = new FailedExtension(error);
|
||||
return;
|
||||
@@ -256,7 +261,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', "Cannot activate extension '{0}' as the depending extension '{1}' is failed to activate.", currentExtension.displayName || currentExtension.id, depId));
|
||||
const error = new Error(`Dependency ${depId} failed to activate`);
|
||||
(<any>error).detail = dep.activationFailedError;
|
||||
this._activatedExtensions[currentExtension.id] = new FailedExtension(error);
|
||||
@@ -276,15 +281,15 @@ export class ExtensionsActivator {
|
||||
}
|
||||
}
|
||||
|
||||
private _activateExtensions(extensionDescriptions: IExtensionDescription[], reason: ExtensionActivationReason, recursionLevel: number): TPromise<void> {
|
||||
private _activateExtensions(extensionDescriptions: IExtensionDescription[], reason: ExtensionActivationReason, recursionLevel: number): Promise<void> {
|
||||
// console.log(recursionLevel, '_activateExtensions: ', extensionDescriptions.map(p => p.id));
|
||||
if (extensionDescriptions.length === 0) {
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
extensionDescriptions = extensionDescriptions.filter((p) => !hasOwnProperty.call(this._activatedExtensions, p.id));
|
||||
if (extensionDescriptions.length === 0) {
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
if (recursionLevel > 10) {
|
||||
@@ -295,7 +300,7 @@ export class ExtensionsActivator {
|
||||
const error = new Error('More than 10 levels of dependencies (most likely a dependency loop)');
|
||||
this._activatedExtensions[extensionDescriptions[i].id] = new FailedExtension(error);
|
||||
}
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
let greenMap: { [id: string]: IExtensionDescription; } = Object.create(null),
|
||||
@@ -319,7 +324,7 @@ export class ExtensionsActivator {
|
||||
|
||||
if (red.length === 0) {
|
||||
// Finally reached only leafs!
|
||||
return TPromise.join(green.map((p) => this._activateExtension(p, reason))).then(_ => void 0);
|
||||
return Promise.all(green.map((p) => this._activateExtension(p, reason))).then(_ => void 0);
|
||||
}
|
||||
|
||||
return this._activateExtensions(green, reason, recursionLevel + 1).then(_ => {
|
||||
@@ -327,9 +332,9 @@ export class ExtensionsActivator {
|
||||
});
|
||||
}
|
||||
|
||||
private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TPromise<void> {
|
||||
private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<void> {
|
||||
if (hasOwnProperty.call(this._activatedExtensions, extensionDescription.id)) {
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
if (hasOwnProperty.call(this._activatingExtensions, extensionDescription.id)) {
|
||||
|
||||
@@ -2,28 +2,31 @@
|
||||
* 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 { dispose } from 'vs/base/common/lifecycle';
|
||||
import { join } from 'path';
|
||||
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/workbench/services/extensions/common/extensions';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'path';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { createApiFactory, initializeExtensionApi } from 'sql/workbench/api/node/sqlExtHost.api.impl';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { MainContext, MainThreadExtensionServiceShape, IWorkspaceData, IEnvironment, IInitData, ExtHostExtensionServiceShape, MainThreadTelemetryShape, IMainContext } from './extHost.protocol';
|
||||
import { IExtensionMemento, ExtensionsActivator, ActivatedExtension, IExtensionAPI, IExtensionContext, EmptyExtension, IExtensionModule, ExtensionActivationTimesBuilder, ExtensionActivationTimes, ExtensionActivationReason, ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { createApiFactory, initializeExtensionApi, ISqlExtensionApiFactory } from 'sql/workbench/api/node/sqlExtHost.api.impl';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
// {{SQL CARBON EDIT}} - Remove createApiFactory initializeExtensionApi, and IExtensionApiFactory imports
|
||||
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, IWorkspaceData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionMemento, IExtensionModule } from 'vs/workbench/api/node/extHostExtensionActivator';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { IExtensionDescription, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
|
||||
import { connectProxyResolver } from 'vs/workbench/node/proxyResolver';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
|
||||
class ExtensionMemento implements IExtensionMemento {
|
||||
|
||||
@@ -31,8 +34,9 @@ class ExtensionMemento implements IExtensionMemento {
|
||||
private readonly _shared: boolean;
|
||||
private readonly _storage: ExtHostStorage;
|
||||
|
||||
private readonly _init: TPromise<ExtensionMemento>;
|
||||
private readonly _init: Thenable<ExtensionMemento>;
|
||||
private _value: { [n: string]: any; };
|
||||
private readonly _storageListener: IDisposable;
|
||||
|
||||
constructor(id: string, global: boolean, storage: ExtHostStorage) {
|
||||
this._id = id;
|
||||
@@ -43,9 +47,15 @@ class ExtensionMemento implements IExtensionMemento {
|
||||
this._value = value;
|
||||
return this;
|
||||
});
|
||||
|
||||
this._storageListener = this._storage.onDidChangeStorage(e => {
|
||||
if (e.shared === this._shared && e.key === this._id) {
|
||||
this._value = e.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get whenReady(): TPromise<ExtensionMemento> {
|
||||
get whenReady(): Thenable<ExtensionMemento> {
|
||||
return this._init;
|
||||
}
|
||||
|
||||
@@ -63,6 +73,10 @@ class ExtensionMemento implements IExtensionMemento {
|
||||
.setValue(this._shared, this._id, this._value)
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._storageListener.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ExtensionStoragePath {
|
||||
@@ -83,31 +97,35 @@ class ExtensionStoragePath {
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
value(extension: IExtensionDescription): string {
|
||||
workspaceValue(extension: IExtensionDescription): string {
|
||||
if (this._value) {
|
||||
return join(this._value, extension.id);
|
||||
return path.join(this._value, extension.id);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
globalValue(extension: IExtensionDescription): string {
|
||||
return path.join(this._environment.globalStorageHome.fsPath, extension.id);
|
||||
}
|
||||
|
||||
private async _getOrCreateWorkspaceStoragePath(): Promise<string> {
|
||||
if (!this._workspace) {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const storageName = this._workspace.id;
|
||||
const storagePath = join(this._environment.appSettingsHome, 'workspaceStorage', storageName);
|
||||
const storagePath = path.join(this._environment.appSettingsHome.fsPath, 'workspaceStorage', storageName);
|
||||
|
||||
const exists = await dirExists(storagePath);
|
||||
const exists = await pfs.dirExists(storagePath);
|
||||
|
||||
if (exists) {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
try {
|
||||
await mkdirp(storagePath);
|
||||
await writeFile(
|
||||
join(storagePath, 'meta.json'),
|
||||
await pfs.mkdirp(storagePath);
|
||||
await pfs.writeFile(
|
||||
path.join(storagePath, 'meta.json'),
|
||||
JSON.stringify({
|
||||
id: this._workspace.id,
|
||||
configuration: this._workspace.configuration && URI.revive(this._workspace.configuration).toString(),
|
||||
@@ -123,67 +141,112 @@ class ExtensionStoragePath {
|
||||
}
|
||||
}
|
||||
|
||||
interface ITestRunner {
|
||||
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
||||
}
|
||||
|
||||
export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
private readonly _nativeExit: (code?: number) => void;
|
||||
private readonly _initData: IInitData;
|
||||
private readonly _extHostContext: IMainContext;
|
||||
private readonly _extHostWorkspace: ExtHostWorkspace;
|
||||
private readonly _extHostConfiguration: ExtHostConfiguration;
|
||||
private readonly _extHostLogService: ExtHostLogService;
|
||||
|
||||
private readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
|
||||
private readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape;
|
||||
private readonly _mainThreadExtensionsProxy: MainThreadExtensionServiceShape;
|
||||
|
||||
private readonly _barrier: Barrier;
|
||||
private readonly _registry: ExtensionDescriptionRegistry;
|
||||
private readonly _mainThreadTelemetry: MainThreadTelemetryShape;
|
||||
private readonly _storage: ExtHostStorage;
|
||||
private readonly _storagePath: ExtensionStoragePath;
|
||||
private readonly _proxy: MainThreadExtensionServiceShape;
|
||||
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,
|
||||
private readonly _activator: ExtensionsActivator;
|
||||
private _extensionPathIndex: Promise<TernarySearchTree<IExtensionDescription>>;
|
||||
// {{SQL CARBON EDIT}}
|
||||
private readonly _extensionApiFactory: ISqlExtensionApiFactory;
|
||||
|
||||
private _started: boolean;
|
||||
|
||||
constructor(
|
||||
nativeExit: (code?: number) => void,
|
||||
initData: IInitData,
|
||||
extHostContext: IMainContext,
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extHostLogService: ExtHostLogService
|
||||
) {
|
||||
this._nativeExit = nativeExit;
|
||||
this._initData = initData;
|
||||
this._extHostContext = extHostContext;
|
||||
this._extHostWorkspace = extHostWorkspace;
|
||||
this._extHostConfiguration = extHostConfiguration;
|
||||
this._extHostLogService = extHostLogService;
|
||||
|
||||
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
this._mainThreadTelemetryProxy = this._extHostContext.getProxy(MainContext.MainThreadTelemetry);
|
||||
this._mainThreadExtensionsProxy = this._extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
||||
|
||||
this._barrier = new Barrier();
|
||||
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
|
||||
this._extHostLogService = extHostLogService;
|
||||
this._mainThreadTelemetry = extHostContext.getProxy(MainContext.MainThreadTelemetry);
|
||||
this._storage = new ExtHostStorage(extHostContext);
|
||||
this._storage = new ExtHostStorage(this._extHostContext);
|
||||
this._storagePath = new ExtensionStoragePath(initData.workspace, initData.environment);
|
||||
this._proxy = extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
||||
this._activator = null;
|
||||
this._activator = new ExtensionsActivator(this._registry, {
|
||||
showMessage: (severity: Severity, message: string): void => {
|
||||
this._mainThreadExtensionsProxy.$localShowMessage(severity, message);
|
||||
|
||||
switch (severity) {
|
||||
case Severity.Error:
|
||||
console.error(message);
|
||||
break;
|
||||
case Severity.Warning:
|
||||
console.warn(message);
|
||||
break;
|
||||
default:
|
||||
console.log(message);
|
||||
}
|
||||
},
|
||||
|
||||
actualActivateExtension: (extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> => {
|
||||
return this._activateExtension(extensionDescription, reason);
|
||||
}
|
||||
});
|
||||
this._extensionPathIndex = null;
|
||||
|
||||
// initialize API first (i.e. do not release barrier until the API is initialized)
|
||||
const apiFactory = createApiFactory(initData, extHostContext, extHostWorkspace, extHostConfiguration, this, this._extHostLogService);
|
||||
this._extensionApiFactory = createApiFactory(this._initData, this._extHostContext, this._extHostWorkspace, this._extHostConfiguration, this, this._extHostLogService, this._storage);
|
||||
|
||||
initializeExtensionApi(this, apiFactory).then(() => {
|
||||
|
||||
this._activator = new ExtensionsActivator(this._registry, {
|
||||
showMessage: (severity: Severity, message: string): void => {
|
||||
this._proxy.$localShowMessage(severity, message);
|
||||
|
||||
switch (severity) {
|
||||
case Severity.Error:
|
||||
console.error(message);
|
||||
break;
|
||||
case Severity.Warning:
|
||||
console.warn(message);
|
||||
break;
|
||||
default:
|
||||
console.log(message);
|
||||
}
|
||||
},
|
||||
|
||||
actualActivateExtension: (extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TPromise<ActivatedExtension> => {
|
||||
return this._activateExtension(extensionDescription, reason);
|
||||
}
|
||||
});
|
||||
this._started = false;
|
||||
|
||||
initializeExtensionApi(this, this._extensionApiFactory, this._registry).then(() => {
|
||||
// Do this when extension service exists, but extensions are not being activated yet.
|
||||
return connectProxyResolver(this._extHostWorkspace, this._extHostConfiguration, this, this._extHostLogService, this._mainThreadTelemetryProxy);
|
||||
}).then(() => {
|
||||
this._barrier.open();
|
||||
});
|
||||
|
||||
if (this._initData.autoStart) {
|
||||
this._startExtensionHost();
|
||||
}
|
||||
}
|
||||
|
||||
public onExtensionAPIReady(): TPromise<boolean> {
|
||||
return this._barrier.wait();
|
||||
public async deactivateAll(): Promise<void> {
|
||||
let allPromises: Thenable<void>[] = [];
|
||||
try {
|
||||
const allExtensions = this._registry.getAllExtensionDescriptions();
|
||||
const allExtensionsIds = allExtensions.map(ext => ext.id);
|
||||
const activatedExtensions = allExtensionsIds.filter(id => this.isActivated(id));
|
||||
|
||||
allPromises = activatedExtensions.map((extensionId) => {
|
||||
return this._deactivate(extensionId);
|
||||
});
|
||||
} catch (err) {
|
||||
// TODO: write to log once we have one
|
||||
}
|
||||
await allPromises;
|
||||
}
|
||||
|
||||
public isActivated(extensionId: string): boolean {
|
||||
@@ -193,40 +256,28 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
return false;
|
||||
}
|
||||
|
||||
public activateByEvent(activationEvent: string, startup: boolean): TPromise<void> {
|
||||
private _activateByEvent(activationEvent: string, startup: boolean): Thenable<void> {
|
||||
const reason = new ExtensionActivatedByEvent(startup, activationEvent);
|
||||
if (this._barrier.isOpen()) {
|
||||
return this._activator.activateByEvent(activationEvent, reason);
|
||||
} else {
|
||||
return this._barrier.wait().then(() => this._activator.activateByEvent(activationEvent, reason));
|
||||
}
|
||||
return this._activator.activateByEvent(activationEvent, reason);
|
||||
}
|
||||
|
||||
public activateById(extensionId: string, reason: ExtensionActivationReason): TPromise<void> {
|
||||
if (this._barrier.isOpen()) {
|
||||
return this._activator.activateById(extensionId, reason);
|
||||
} else {
|
||||
return this._barrier.wait().then(() => this._activator.activateById(extensionId, reason));
|
||||
}
|
||||
private _activateById(extensionId: string, reason: ExtensionActivationReason): Thenable<void> {
|
||||
return this._activator.activateById(extensionId, reason);
|
||||
}
|
||||
|
||||
public activateByIdWithErrors(extensionId: string, reason: ExtensionActivationReason): TPromise<void> {
|
||||
return this.activateById(extensionId, reason).then(() => {
|
||||
public activateByIdWithErrors(extensionId: string, reason: ExtensionActivationReason): Thenable<void> {
|
||||
return this._activateById(extensionId, reason).then(() => {
|
||||
const extension = this._activator.getActivatedExtension(extensionId);
|
||||
if (extension.activationFailed) {
|
||||
// activation failed => bubble up the error as the promise result
|
||||
return TPromise.wrapError(extension.activationFailedError);
|
||||
return Promise.reject(extension.activationFailedError);
|
||||
}
|
||||
return void 0;
|
||||
});
|
||||
}
|
||||
|
||||
public getAllExtensionDescriptions(): IExtensionDescription[] {
|
||||
return this._registry.getAllExtensionDescriptions();
|
||||
}
|
||||
|
||||
public getExtensionDescription(extensionId: string): IExtensionDescription {
|
||||
return this._registry.getExtensionDescription(extensionId);
|
||||
public getExtensionRegistry(): Promise<ExtensionDescriptionRegistry> {
|
||||
return this._barrier.wait().then(_ => this._registry);
|
||||
}
|
||||
|
||||
public getExtensionExports(extensionId: string): IExtensionAPI {
|
||||
@@ -238,23 +289,22 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
}
|
||||
|
||||
// create trie to enable fast 'filename -> extension id' look up
|
||||
public getExtensionPathIndex(): TPromise<TernarySearchTree<IExtensionDescription>> {
|
||||
public getExtensionPathIndex(): Promise<TernarySearchTree<IExtensionDescription>> {
|
||||
if (!this._extensionPathIndex) {
|
||||
const tree = TernarySearchTree.forPaths<IExtensionDescription>();
|
||||
const extensions = this.getAllExtensionDescriptions().map(ext => {
|
||||
const extensions = this._registry.getAllExtensionDescriptions().map(ext => {
|
||||
if (!ext.main) {
|
||||
return undefined;
|
||||
}
|
||||
return realpath(ext.extensionLocation.fsPath).then(value => tree.set(value, ext));
|
||||
return pfs.realpath(ext.extensionLocation.fsPath).then(value => tree.set(URI.file(value).fsPath, ext));
|
||||
});
|
||||
this._extensionPathIndex = TPromise.join(extensions).then(() => tree);
|
||||
this._extensionPathIndex = Promise.all(extensions).then(() => tree);
|
||||
}
|
||||
return this._extensionPathIndex;
|
||||
}
|
||||
|
||||
|
||||
public deactivate(extensionId: string): TPromise<void> {
|
||||
let result: TPromise<void> = TPromise.as(void 0);
|
||||
private _deactivate(extensionId: string): Thenable<void> {
|
||||
let result = Promise.resolve(void 0);
|
||||
|
||||
if (!this._barrier.isOpen()) {
|
||||
return result;
|
||||
@@ -272,9 +322,9 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
// call deactivate if available
|
||||
try {
|
||||
if (typeof extension.module.deactivate === 'function') {
|
||||
result = TPromise.wrap(extension.module.deactivate()).then(null, (err) => {
|
||||
result = Promise.resolve(extension.module.deactivate()).then(null, (err) => {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -292,25 +342,45 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
}
|
||||
|
||||
public addMessage(extensionId: string, severity: Severity, message: string): void {
|
||||
this._proxy.$addMessage(extensionId, severity, message);
|
||||
this._mainThreadExtensionsProxy.$addMessage(extensionId, severity, message);
|
||||
}
|
||||
|
||||
// --- impl
|
||||
|
||||
private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TPromise<ActivatedExtension> {
|
||||
private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
|
||||
return this._doActivateExtension(extensionDescription, reason).then((activatedExtension) => {
|
||||
const activationTimes = activatedExtension.activationTimes;
|
||||
let activationEvent = (reason instanceof ExtensionActivatedByEvent ? reason.activationEvent : null);
|
||||
this._proxy.$onExtensionActivated(extensionDescription.id, activationTimes.startup, activationTimes.codeLoadingTime, activationTimes.activateCallTime, activationTimes.activateResolvedTime, activationEvent);
|
||||
this._mainThreadExtensionsProxy.$onExtensionActivated(extensionDescription.id, activationTimes.startup, activationTimes.codeLoadingTime, activationTimes.activateCallTime, activationTimes.activateResolvedTime, activationEvent);
|
||||
this._logExtensionActivationTimes(extensionDescription, reason, 'success', activationTimes);
|
||||
return activatedExtension;
|
||||
}, (err) => {
|
||||
this._proxy.$onExtensionActivationFailed(extensionDescription.id);
|
||||
this._mainThreadExtensionsProxy.$onExtensionActivationFailed(extensionDescription.id);
|
||||
this._logExtensionActivationTimes(extensionDescription, reason, 'failure');
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TPromise<ActivatedExtension> {
|
||||
let event = getTelemetryActivationEvent(extensionDescription);
|
||||
private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) {
|
||||
let event = getTelemetryActivationEvent(extensionDescription, reason);
|
||||
/* __GDPR__
|
||||
"extensionActivationTimes" : {
|
||||
"${include}": [
|
||||
"${TelemetryActivationEvent}",
|
||||
"${ExtensionActivationTimes}"
|
||||
],
|
||||
"outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemetryProxy.$publicLog('extensionActivationTimes', {
|
||||
...event,
|
||||
...(activationTimes || {}),
|
||||
outcome,
|
||||
});
|
||||
}
|
||||
|
||||
private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
|
||||
let event = getTelemetryActivationEvent(extensionDescription, reason);
|
||||
/* __GDPR__
|
||||
"activatePlugin" : {
|
||||
"${include}": [
|
||||
@@ -318,39 +388,30 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
]
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemetry.$publicLog('activatePlugin', event);
|
||||
this._mainThreadTelemetryProxy.$publicLog('activatePlugin', event);
|
||||
if (!extensionDescription.main) {
|
||||
// Treat the extension as being empty => NOT AN ERROR CASE
|
||||
return TPromise.as(new EmptyExtension(ExtensionActivationTimes.NONE));
|
||||
return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE));
|
||||
}
|
||||
|
||||
this._extHostLogService.info(`ExtensionService#_doActivateExtension ${extensionDescription.id} ${JSON.stringify(reason)}`);
|
||||
|
||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||
return TPromise.join<any>([
|
||||
return Promise.all<any>([
|
||||
loadCommonJSModule(this._extHostLogService, extensionDescription.main, activationTimesBuilder),
|
||||
this._loadExtensionContext(extensionDescription)
|
||||
]).then(values => {
|
||||
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]) {
|
||||
return TPromise.wrapError<ActivatedExtension>(errors[0]);
|
||||
}
|
||||
if (errors[1]) {
|
||||
return TPromise.wrapError<ActivatedExtension>(errors[1]);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): TPromise<IExtensionContext> {
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<IExtensionContext> {
|
||||
|
||||
let globalState = new ExtensionMemento(extensionDescription.id, true, this._storage);
|
||||
let workspaceState = new ExtensionMemento(extensionDescription.id, false, this._storage);
|
||||
|
||||
this._extHostLogService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.id}`);
|
||||
return TPromise.join([
|
||||
return Promise.all([
|
||||
globalState.whenReady,
|
||||
workspaceState.whenReady,
|
||||
this._storagePath.whenReady
|
||||
@@ -361,16 +422,10 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
workspaceState,
|
||||
subscriptions: [],
|
||||
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
|
||||
storagePath: this._storagePath.value(extensionDescription),
|
||||
asAbsolutePath: (relativePath: string) => { return join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
get logger() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._extHostLogService.getExtLogger(extensionDescription.id);
|
||||
},
|
||||
get logDirectory() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._extHostLogService.getLogDirectory(extensionDescription.id);
|
||||
}
|
||||
storagePath: this._storagePath.workspaceValue(extensionDescription),
|
||||
get globalStoragePath(): string { checkProposedApiEnabled(extensionDescription); return that._storagePath.globalValue(extensionDescription); },
|
||||
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
logPath: that._extHostLogService.getLogDirectory(extensionDescription.id)
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -392,60 +447,246 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
try {
|
||||
activationTimesBuilder.activateCallStart();
|
||||
logService.trace(`ExtensionService#_callActivateOptional ${extensionId}`);
|
||||
const activateResult: TPromise<IExtensionAPI> = extensionModule.activate.apply(global, [context]);
|
||||
const activateResult: Thenable<IExtensionAPI> = extensionModule.activate.apply(global, [context]);
|
||||
activationTimesBuilder.activateCallStop();
|
||||
|
||||
activationTimesBuilder.activateResolveStart();
|
||||
return TPromise.as(activateResult).then((value) => {
|
||||
return Promise.resolve(activateResult).then((value) => {
|
||||
activationTimesBuilder.activateResolveStop();
|
||||
return value;
|
||||
});
|
||||
} catch (err) {
|
||||
return TPromise.wrapError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
} else {
|
||||
// No activate found => the module is the extension's exports
|
||||
return TPromise.as<IExtensionAPI>(extensionModule);
|
||||
return Promise.resolve<IExtensionAPI>(extensionModule);
|
||||
}
|
||||
}
|
||||
|
||||
// -- eager activation
|
||||
|
||||
// Handle "eager" activation extensions
|
||||
private _handleEagerExtensions(): Promise<void> {
|
||||
this._activateByEvent('*', true).then(null, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
return this._handleWorkspaceContainsEagerExtensions(this._initData.workspace);
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtensions(workspace: IWorkspaceData): Promise<void> {
|
||||
if (!workspace || workspace.folders.length === 0) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
this._registry.getAllExtensionDescriptions().map((desc) => {
|
||||
return this._handleWorkspaceContainsEagerExtension(workspace, desc);
|
||||
})
|
||||
).then(() => { });
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtension(workspace: IWorkspaceData, desc: IExtensionDescription): Promise<void> {
|
||||
const activationEvents = desc.activationEvents;
|
||||
if (!activationEvents) {
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
const globPatterns: string[] = [];
|
||||
|
||||
for (let i = 0; i < activationEvents.length; i++) {
|
||||
if (/^workspaceContains:/.test(activationEvents[i])) {
|
||||
const fileNameOrGlob = activationEvents[i].substr('workspaceContains:'.length);
|
||||
if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0) {
|
||||
globPatterns.push(fileNameOrGlob);
|
||||
} else {
|
||||
fileNames.push(fileNameOrGlob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNames.length === 0 && globPatterns.length === 0) {
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(workspace, desc.id, fileName))).then(() => { });
|
||||
const globPatternPromise = this._activateIfGlobPatterns(desc.id, globPatterns);
|
||||
|
||||
return Promise.all([fileNamePromise, globPatternPromise]).then(() => { });
|
||||
}
|
||||
|
||||
private async _activateIfFileName(workspace: IWorkspaceData, extensionId: string, fileName: string): Promise<void> {
|
||||
|
||||
// find exact path
|
||||
for (const { uri } of workspace.folders) {
|
||||
if (await pfs.exists(path.join(URI.revive(uri).fsPath, fileName))) {
|
||||
// the file was found
|
||||
return (
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${fileName}`))
|
||||
.then(null, err => console.error(err))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async _activateIfGlobPatterns(extensionId: string, globPatterns: string[]): Promise<void> {
|
||||
this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId}, entryPoint: workspaceContains`);
|
||||
|
||||
if (globPatterns.length === 0) {
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const searchP = this._mainThreadWorkspaceProxy.$checkExists(globPatterns, tokenSource.token);
|
||||
|
||||
const timer = setTimeout(async () => {
|
||||
tokenSource.cancel();
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContainsTimeout:${globPatterns.join(',')}`))
|
||||
.then(null, err => console.error(err));
|
||||
}, ExtHostExtensionService.WORKSPACE_CONTAINS_TIMEOUT);
|
||||
|
||||
let exists: boolean;
|
||||
try {
|
||||
exists = await searchP;
|
||||
} catch (err) {
|
||||
if (!errors.isPromiseCanceledError(err)) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
clearTimeout(timer);
|
||||
|
||||
if (exists) {
|
||||
// a file was found matching one of the glob patterns
|
||||
return (
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${globPatterns.join(',')}`))
|
||||
.then(null, err => console.error(err))
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
private _handleExtensionTests(): Promise<void> {
|
||||
if (!this._initData.environment.extensionTestsPath || !this._initData.environment.extensionDevelopmentLocationURI) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
// Require the test runner via node require from the provided path
|
||||
let testRunner: ITestRunner;
|
||||
let requireError: Error;
|
||||
try {
|
||||
testRunner = <any>require.__$__nodeRequire(this._initData.environment.extensionTestsPath);
|
||||
} catch (error) {
|
||||
requireError = error;
|
||||
}
|
||||
|
||||
// Execute the runner if it follows our spec
|
||||
if (testRunner && typeof testRunner.run === 'function') {
|
||||
return new Promise<void>((c, e) => {
|
||||
testRunner.run(this._initData.environment.extensionTestsPath, (error, failures) => {
|
||||
if (error) {
|
||||
e(error.toString());
|
||||
} else {
|
||||
c(null);
|
||||
}
|
||||
|
||||
// after tests have run, we shutdown the host
|
||||
this._gracefulExit(failures && failures > 0 ? 1 /* ERROR */ : 0 /* OK */);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise make sure to shutdown anyway even in case of an error
|
||||
else {
|
||||
this._gracefulExit(1 /* ERROR */);
|
||||
}
|
||||
|
||||
return Promise.reject(new Error(requireError ? requireError.toString() : nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", this._initData.environment.extensionTestsPath)));
|
||||
}
|
||||
|
||||
private _gracefulExit(code: number): void {
|
||||
// to give the PH process a chance to flush any outstanding console
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => this._nativeExit(code), 500);
|
||||
}
|
||||
|
||||
private _startExtensionHost(): Thenable<void> {
|
||||
if (this._started) {
|
||||
throw new Error(`Extension host is already started!`);
|
||||
}
|
||||
this._started = true;
|
||||
|
||||
return this._barrier.wait()
|
||||
.then(() => this._handleEagerExtensions())
|
||||
.then(() => this._handleExtensionTests())
|
||||
.then(() => {
|
||||
this._extHostLogService.info(`eager extensions activated`);
|
||||
});
|
||||
}
|
||||
|
||||
// -- called by main thread
|
||||
|
||||
public $activateByEvent(activationEvent: string): TPromise<void> {
|
||||
return this.activateByEvent(activationEvent, false);
|
||||
public async $resolveAuthority(remoteAuthority: string): Promise<ResolvedAuthority> {
|
||||
throw new Error(`Not implemented`);
|
||||
}
|
||||
|
||||
public $startExtensionHost(enabledExtensionIds: string[]): Thenable<void> {
|
||||
this._registry.keepOnly(enabledExtensionIds);
|
||||
return this._startExtensionHost();
|
||||
}
|
||||
|
||||
public $activateByEvent(activationEvent: string): Thenable<void> {
|
||||
return (
|
||||
this._barrier.wait()
|
||||
.then(_ => this._activateByEvent(activationEvent, false))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function loadCommonJSModule<T>(logService: ILogService, modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): TPromise<T> {
|
||||
let r: T = null;
|
||||
function loadCommonJSModule<T>(logService: ILogService, modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
let r: T | null = null;
|
||||
activationTimesBuilder.codeLoadingStart();
|
||||
logService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
|
||||
try {
|
||||
r = require.__$__nodeRequire<T>(modulePath);
|
||||
} catch (e) {
|
||||
return TPromise.wrapError<T>(e);
|
||||
return Promise.reject(e);
|
||||
} finally {
|
||||
activationTimesBuilder.codeLoadingStop();
|
||||
}
|
||||
return TPromise.as(r);
|
||||
return Promise.resolve(r);
|
||||
}
|
||||
|
||||
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription): any {
|
||||
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): any {
|
||||
const reasonStr = reason instanceof ExtensionActivatedByEvent ? reason.activationEvent :
|
||||
reason instanceof ExtensionActivatedByAPI ? 'api' :
|
||||
'';
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"TelemetryActivationEvent" : {
|
||||
"id": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"name": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"extensionVersion": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
|
||||
"publisherDisplayName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"activationEvents": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
"isBuiltin": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"reason": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
let event = {
|
||||
id: extensionDescription.id,
|
||||
name: extensionDescription.name,
|
||||
extensionVersion: extensionDescription.version,
|
||||
publisherDisplayName: extensionDescription.publisher,
|
||||
activationEvents: extensionDescription.activationEvents ? extensionDescription.activationEvents.join(',') : null,
|
||||
isBuiltin: extensionDescription.isBuiltin
|
||||
isBuiltin: extensionDescription.isBuiltin,
|
||||
reason: reasonStr
|
||||
};
|
||||
|
||||
return event;
|
||||
|
||||
@@ -2,56 +2,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 URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape, IFileChangeDto } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { Range, FileChangeType } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType, DocumentLink } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as typeConverter from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/node/extHostLanguageFeatures';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { LabelRules } from 'vs/platform/label/common/label';
|
||||
import { State, StateMachine, LinkComputer } from 'vs/editor/common/modes/linkComputer';
|
||||
import { commonPrefixLength } from 'vs/base/common/strings';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
class FsLinkProvider implements vscode.DocumentLinkProvider {
|
||||
class FsLinkProvider {
|
||||
|
||||
private _schemes = new Set<string>();
|
||||
private _regex: RegExp;
|
||||
private _schemes: string[] = [];
|
||||
private _stateMachine: StateMachine;
|
||||
|
||||
add(scheme: string): void {
|
||||
this._regex = undefined;
|
||||
this._schemes.add(scheme);
|
||||
this._stateMachine = undefined;
|
||||
this._schemes.push(scheme);
|
||||
}
|
||||
|
||||
delete(scheme: string): void {
|
||||
if (this._schemes.delete(scheme)) {
|
||||
this._regex = undefined;
|
||||
let idx = this._schemes.indexOf(scheme);
|
||||
if (idx >= 0) {
|
||||
this._schemes.splice(idx, 1);
|
||||
this._stateMachine = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _initStateMachine(): void {
|
||||
if (!this._stateMachine) {
|
||||
|
||||
// sort and compute common prefix with previous scheme
|
||||
// then build state transitions based on the data
|
||||
const schemes = this._schemes.sort();
|
||||
const edges = [];
|
||||
let prevScheme: string;
|
||||
let prevState: State;
|
||||
let nextState = State.LastKnownState;
|
||||
for (const scheme of schemes) {
|
||||
|
||||
// skip the common prefix of the prev scheme
|
||||
// and continue with its last state
|
||||
let pos = !prevScheme ? 0 : commonPrefixLength(prevScheme, scheme);
|
||||
if (pos === 0) {
|
||||
prevState = State.Start;
|
||||
} else {
|
||||
prevState = nextState;
|
||||
}
|
||||
|
||||
for (; pos < scheme.length; pos++) {
|
||||
// keep creating new (next) states until the
|
||||
// end (and the BeforeColon-state) is reached
|
||||
if (pos + 1 === scheme.length) {
|
||||
nextState = State.BeforeColon;
|
||||
} else {
|
||||
nextState += 1;
|
||||
}
|
||||
edges.push([prevState, scheme.toUpperCase().charCodeAt(pos), nextState]);
|
||||
edges.push([prevState, scheme.toLowerCase().charCodeAt(pos), nextState]);
|
||||
prevState = nextState;
|
||||
}
|
||||
|
||||
prevScheme = scheme;
|
||||
}
|
||||
|
||||
// all link must match this pattern `<scheme>:/<more>`
|
||||
edges.push([State.BeforeColon, CharCode.Colon, State.AfterColon]);
|
||||
edges.push([State.AfterColon, CharCode.Slash, State.End]);
|
||||
|
||||
this._stateMachine = new StateMachine(edges);
|
||||
}
|
||||
}
|
||||
|
||||
provideDocumentLinks(document: vscode.TextDocument): 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]);
|
||||
if (target.path[0] !== '/') {
|
||||
continue;
|
||||
}
|
||||
const range = new Range(line, this._regex.lastIndex - m[0].length, line, this._regex.lastIndex);
|
||||
result.push({ target, range });
|
||||
this._initStateMachine();
|
||||
|
||||
const result: vscode.DocumentLink[] = [];
|
||||
const links = LinkComputer.computeLinks({
|
||||
getLineContent(lineNumber: number): string {
|
||||
return document.lineAt(lineNumber - 1).text;
|
||||
},
|
||||
getLineCount(): number {
|
||||
return document.lineCount;
|
||||
}
|
||||
}, this._stateMachine);
|
||||
|
||||
for (const link of links) {
|
||||
try {
|
||||
let uri = URI.parse(link.url, true);
|
||||
result.push(new DocumentLink(typeConverter.Range.to(link.range), uri));
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -66,9 +113,10 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
private readonly _usedSchemes = new Set<string>();
|
||||
private readonly _watches = new Map<number, IDisposable>();
|
||||
|
||||
private _linkProviderRegistration: IDisposable;
|
||||
private _handlePool: number = 0;
|
||||
|
||||
constructor(mainContext: IMainContext, extHostLanguageFeatures: ExtHostLanguageFeatures) {
|
||||
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
|
||||
this._usedSchemes.add(Schemas.file);
|
||||
this._usedSchemes.add(Schemas.untitled);
|
||||
@@ -79,8 +127,16 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
this._usedSchemes.add(Schemas.https);
|
||||
this._usedSchemes.add(Schemas.mailto);
|
||||
this._usedSchemes.add(Schemas.data);
|
||||
}
|
||||
|
||||
extHostLanguageFeatures.registerDocumentLinkProvider('*', this._linkProvider);
|
||||
dispose(): void {
|
||||
dispose(this._linkProviderRegistration);
|
||||
}
|
||||
|
||||
private _registerLinkProviderIfNotYetRegistered(): void {
|
||||
if (!this._linkProviderRegistration) {
|
||||
this._linkProviderRegistration = this._extHostLanguageFeatures.registerDocumentLinkProvider(undefined, '*', this._linkProvider);
|
||||
}
|
||||
}
|
||||
|
||||
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}) {
|
||||
@@ -89,6 +145,9 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
|
||||
}
|
||||
|
||||
//
|
||||
this._registerLinkProviderIfNotYetRegistered();
|
||||
|
||||
const handle = this._handlePool++;
|
||||
this._linkProvider.add(scheme);
|
||||
this._usedSchemes.add(scheme);
|
||||
@@ -104,6 +163,11 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
if (typeof provider.copy === 'function') {
|
||||
capabilites += files.FileSystemProviderCapabilities.FileFolderCopy;
|
||||
}
|
||||
if (typeof provider.open === 'function' && typeof provider.close === 'function'
|
||||
&& typeof provider.read === 'function' && typeof provider.write === 'function'
|
||||
) {
|
||||
capabilites += files.FileSystemProviderCapabilities.FileOpenReadWriteClose;
|
||||
}
|
||||
|
||||
this._proxy.$registerFileSystemProvider(handle, scheme, capabilites);
|
||||
|
||||
@@ -141,52 +205,70 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
});
|
||||
}
|
||||
|
||||
setUriFormatter(scheme: string, formatter: LabelRules): void {
|
||||
this._proxy.$setUriFormatter(scheme, formatter);
|
||||
}
|
||||
|
||||
private static _asIStat(stat: vscode.FileStat): files.IStat {
|
||||
const { type, ctime, mtime, size } = stat;
|
||||
return { type, ctime, mtime, size };
|
||||
}
|
||||
|
||||
$stat(handle: number, resource: UriComponents): TPromise<files.IStat, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
private _checkProviderExists(handle: number): void {
|
||||
if (!this._fsProvider.has(handle)) {
|
||||
const err = new Error();
|
||||
err.name = 'ENOPRO';
|
||||
err.message = `no provider`;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
$readdir(handle: number, resource: UriComponents): TPromise<[string, files.FileType][], any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).readDirectory(URI.revive(resource)));
|
||||
$stat(handle: number, resource: UriComponents): Promise<files.IStat> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
|
||||
}
|
||||
|
||||
$readFile(handle: number, resource: UriComponents): TPromise<string> {
|
||||
return asWinJsPromise(() => {
|
||||
return this._fsProvider.get(handle).readFile(URI.revive(resource));
|
||||
}).then(data => {
|
||||
return Buffer.isBuffer(data) ? data.toString('base64') : Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString('base64');
|
||||
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).readDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$readFile(handle: number, resource: UriComponents): Promise<Buffer> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).readFile(URI.revive(resource))).then(data => {
|
||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
});
|
||||
}
|
||||
|
||||
$writeFile(handle: number, resource: UriComponents, base64Content: string, opts: files.FileWriteOptions): TPromise<void, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).writeFile(URI.revive(resource), Buffer.from(base64Content, 'base64'), opts));
|
||||
$writeFile(handle: number, resource: UriComponents, content: Buffer, opts: files.FileWriteOptions): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).writeFile(URI.revive(resource), content, opts));
|
||||
}
|
||||
|
||||
$delete(handle: number, resource: UriComponents, opts: files.FileDeleteOptions): TPromise<void, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).delete(URI.revive(resource), opts));
|
||||
$delete(handle: number, resource: UriComponents, opts: files.FileDeleteOptions): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).delete(URI.revive(resource), opts));
|
||||
}
|
||||
|
||||
$rename(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): TPromise<void, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
$rename(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).rename(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
}
|
||||
|
||||
$copy(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): TPromise<void, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).copy(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
$copy(handle: number, oldUri: UriComponents, newUri: UriComponents, opts: files.FileOverwriteOptions): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).copy(URI.revive(oldUri), URI.revive(newUri), opts));
|
||||
}
|
||||
|
||||
$mkdir(handle: number, resource: UriComponents): TPromise<void, any> {
|
||||
return asWinJsPromise(() => this._fsProvider.get(handle).createDirectory(URI.revive(resource)));
|
||||
$mkdir(handle: number, resource: UriComponents): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).createDirectory(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$watch(handle: number, session: number, resource: UriComponents, opts: files.IWatchOptions): void {
|
||||
asWinJsPromise(() => {
|
||||
let subscription = this._fsProvider.get(handle).watch(URI.revive(resource), opts);
|
||||
this._watches.set(session, subscription);
|
||||
});
|
||||
this._checkProviderExists(handle);
|
||||
let subscription = this._fsProvider.get(handle).watch(URI.revive(resource), opts);
|
||||
this._watches.set(session, subscription);
|
||||
}
|
||||
|
||||
$unwatch(session: number): void {
|
||||
@@ -196,4 +278,25 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
|
||||
this._watches.delete(session);
|
||||
}
|
||||
}
|
||||
|
||||
$open(handle: number, resource: UriComponents): Promise<number> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).open(URI.revive(resource)));
|
||||
}
|
||||
|
||||
$close(handle: number, fd: number): Promise<void> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).close(fd));
|
||||
}
|
||||
|
||||
$read(handle: number, fd: number, pos: number, data: Buffer, offset: number, length: number): Promise<number> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).read(fd, pos, data, offset, length));
|
||||
}
|
||||
|
||||
$write(handle: number, fd: number, pos: number, data: Buffer, offset: number, length: number): Promise<number> {
|
||||
this._checkProviderExists(handle);
|
||||
return Promise.resolve(this._fsProvider.get(handle).write(fd, pos, data, offset, length));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
* 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 { flatten } from 'vs/base/common/arrays';
|
||||
import { AsyncEmitter, Emitter, Event } from 'vs/base/common/event';
|
||||
import { IRelativePattern, parse } from 'vs/base/common/glob';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -141,12 +139,12 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
|
||||
};
|
||||
}
|
||||
|
||||
$onWillRename(oldUriDto: UriComponents, newUriDto: UriComponents): TPromise<any> {
|
||||
$onWillRename(oldUriDto: UriComponents, newUriDto: UriComponents): Thenable<any> {
|
||||
const oldUri = URI.revive(oldUriDto);
|
||||
const newUri = URI.revive(newUriDto);
|
||||
|
||||
const edits: WorkspaceEdit[] = [];
|
||||
return TPromise.wrap(this._onWillRenameFile.fireAsync((bucket, listener) => {
|
||||
return Promise.resolve(this._onWillRenameFile.fireAsync((bucket, _listener) => {
|
||||
return {
|
||||
oldUri,
|
||||
newUri,
|
||||
@@ -155,7 +153,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
|
||||
throw new TypeError('waitUntil cannot be called async');
|
||||
}
|
||||
const index = bucket.length;
|
||||
const wrappedThenable = TPromise.as(thenable).then(result => {
|
||||
const wrappedThenable = Promise.resolve(thenable).then(result => {
|
||||
// ignore all results except for WorkspaceEdits. Those
|
||||
// are stored in a spare array
|
||||
if (result instanceof WorkspaceEdit) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* 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 { ExtHostHeapServiceShape } from './extHost.protocol';
|
||||
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConvert from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
@@ -16,16 +14,17 @@ import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto } from './extHost.protocol';
|
||||
import { asThenable } from 'vs/base/common/async';
|
||||
import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, SuggestionDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata } from './extHost.protocol';
|
||||
import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
// --- adapter
|
||||
|
||||
@@ -39,9 +38,9 @@ class OutlineAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideDocumentSymbols(resource: URI): TPromise<modes.DocumentSymbol[]> {
|
||||
provideDocumentSymbols(resource: URI, token: CancellationToken): Thenable<modes.DocumentSymbol[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideDocumentSymbols(doc, token)).then(value => {
|
||||
if (isFalsyOrEmpty(value)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -105,10 +104,10 @@ class CodeLensAdapter {
|
||||
private readonly _provider: vscode.CodeLensProvider
|
||||
) { }
|
||||
|
||||
provideCodeLenses(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
|
||||
provideCodeLenses(resource: URI, token: CancellationToken): Thenable<modes.ICodeLensSymbol[]> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
|
||||
return asThenable(() => this._provider.provideCodeLenses(doc, token)).then(lenses => {
|
||||
if (Array.isArray(lenses)) {
|
||||
return lenses.map(lens => {
|
||||
const id = this._heapService.keep(lens);
|
||||
@@ -122,18 +121,18 @@ class CodeLensAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveCodeLens(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
|
||||
resolveCodeLens(resource: URI, symbol: modes.ICodeLensSymbol, token: CancellationToken): Thenable<modes.ICodeLensSymbol> {
|
||||
|
||||
const lens = this._heapService.get<vscode.CodeLens>(ObjectIdentifier.of(symbol));
|
||||
if (!lens) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let resolve: TPromise<vscode.CodeLens>;
|
||||
let resolve: Thenable<vscode.CodeLens>;
|
||||
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
|
||||
resolve = TPromise.as(lens);
|
||||
resolve = Promise.resolve(lens);
|
||||
} else {
|
||||
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
|
||||
resolve = asThenable(() => this._provider.resolveCodeLens(lens, token));
|
||||
}
|
||||
|
||||
return resolve.then(newLens => {
|
||||
@@ -160,10 +159,24 @@ class DefinitionAdapter {
|
||||
private readonly _provider: vscode.DefinitionProvider
|
||||
) { }
|
||||
|
||||
provideDefinition(resource: URI, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
provideDefinition(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
return asThenable(() => this._provider.provideDefinition(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
}
|
||||
}
|
||||
|
||||
class DeclarationAdapter {
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.DeclarationProvider
|
||||
) { }
|
||||
|
||||
provideDeclaration(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
return asThenable(() => this._provider.provideDeclaration(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,10 +187,10 @@ class ImplementationAdapter {
|
||||
private readonly _provider: vscode.ImplementationProvider
|
||||
) { }
|
||||
|
||||
provideImplementation(resource: URI, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
provideImplementation(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
return asWinJsPromise(token => this._provider.provideImplementation(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
return asThenable(() => this._provider.provideImplementation(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,10 +201,10 @@ class TypeDefinitionAdapter {
|
||||
private readonly _provider: vscode.TypeDefinitionProvider
|
||||
) { }
|
||||
|
||||
provideTypeDefinition(resource: URI, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
provideTypeDefinition(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const pos = typeConvert.Position.to(position);
|
||||
return asWinJsPromise(token => this._provider.provideTypeDefinition(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
return asThenable(() => this._provider.provideTypeDefinition(doc, pos, token)).then(convertToDefinitionLinks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,12 +215,12 @@ class HoverAdapter {
|
||||
private readonly _provider: vscode.HoverProvider,
|
||||
) { }
|
||||
|
||||
public provideHover(resource: URI, position: IPosition): TPromise<modes.Hover> {
|
||||
public provideHover(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.Hover> {
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideHover(doc, pos, token)).then(value => {
|
||||
if (!value || isFalsyOrEmpty(value.contents)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -230,12 +243,12 @@ class DocumentHighlightAdapter {
|
||||
private readonly _provider: vscode.DocumentHighlightProvider
|
||||
) { }
|
||||
|
||||
provideDocumentHighlights(resource: URI, position: IPosition): TPromise<modes.DocumentHighlight[]> {
|
||||
provideDocumentHighlights(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> {
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(typeConvert.DocumentHighlight.from);
|
||||
}
|
||||
@@ -251,11 +264,11 @@ class ReferenceAdapter {
|
||||
private readonly _provider: vscode.ReferenceProvider
|
||||
) { }
|
||||
|
||||
provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext): TPromise<modes.Location[]> {
|
||||
provideReferences(resource: URI, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> {
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideReferences(doc, pos, context, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideReferences(doc, pos, context, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(typeConvert.location.from);
|
||||
}
|
||||
@@ -279,7 +292,7 @@ class CodeActionAdapter {
|
||||
private readonly _extensionId: string
|
||||
) { }
|
||||
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
|
||||
provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Thenable<CodeActionDto[]> {
|
||||
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const ran = Selection.isISelection(rangeOrSelection)
|
||||
@@ -298,9 +311,7 @@ class CodeActionAdapter {
|
||||
only: context.only ? new CodeActionKind(context.only) : undefined
|
||||
};
|
||||
|
||||
return asWinJsPromise(token =>
|
||||
this._provider.provideCodeActions(doc, ran, codeActionContext, token)
|
||||
).then(commandsOrActions => {
|
||||
return asThenable(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => {
|
||||
if (isFalsyOrEmpty(commandsOrActions)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -352,11 +363,11 @@ class DocumentFormattingAdapter {
|
||||
private readonly _provider: vscode.DocumentFormattingEditProvider
|
||||
) { }
|
||||
|
||||
provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
provideDocumentFormattingEdits(resource: URI, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
|
||||
const { document } = this._documents.getDocumentData(resource);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(document, <any>options, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideDocumentFormattingEdits(document, <any>options, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(typeConvert.TextEdit.from);
|
||||
}
|
||||
@@ -372,12 +383,12 @@ class RangeFormattingAdapter {
|
||||
private readonly _provider: vscode.DocumentRangeFormattingEditProvider
|
||||
) { }
|
||||
|
||||
provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
|
||||
const { document } = this._documents.getDocumentData(resource);
|
||||
const ran = typeConvert.Range.to(range);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(typeConvert.TextEdit.from);
|
||||
}
|
||||
@@ -395,12 +406,12 @@ class OnTypeFormattingAdapter {
|
||||
|
||||
autoFormatTriggerCharacters: string[] = []; // not here
|
||||
|
||||
provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
|
||||
const { document } = this._documents.getDocumentData(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any>options, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any>options, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(typeConvert.TextEdit.from);
|
||||
}
|
||||
@@ -419,10 +430,10 @@ class NavigateTypeAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideWorkspaceSymbols(search: string): TPromise<WorkspaceSymbolsDto> {
|
||||
provideWorkspaceSymbols(search: string, token: CancellationToken): Thenable<WorkspaceSymbolsDto> {
|
||||
const result: WorkspaceSymbolsDto = IdObject.mixin({ symbols: [] });
|
||||
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
|
||||
if (!isFalsyOrEmpty(value)) {
|
||||
return asThenable(() => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
|
||||
if (isNonEmptyArray(value)) {
|
||||
for (const item of value) {
|
||||
if (!item) {
|
||||
// drop
|
||||
@@ -445,15 +456,15 @@ class NavigateTypeAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveWorkspaceSymbol(symbol: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto> {
|
||||
resolveWorkspaceSymbol(symbol: WorkspaceSymbolDto, token: CancellationToken): Thenable<WorkspaceSymbolDto> {
|
||||
|
||||
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
|
||||
return TPromise.as(symbol);
|
||||
return Promise.resolve(symbol);
|
||||
}
|
||||
|
||||
const item = this._symbolCache[symbol._id];
|
||||
if (item) {
|
||||
return asWinJsPromise(token => this._provider.resolveWorkspaceSymbol(item, token)).then(value => {
|
||||
return asThenable(() => this._provider.resolveWorkspaceSymbol(item, token)).then(value => {
|
||||
return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true);
|
||||
});
|
||||
}
|
||||
@@ -482,43 +493,36 @@ class RenameAdapter {
|
||||
private readonly _provider: vscode.RenameProvider
|
||||
) { }
|
||||
|
||||
provideRenameEdits(resource: URI, position: IPosition, newName: string): TPromise<WorkspaceEditDto> {
|
||||
provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Thenable<WorkspaceEditDto> {
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
return typeConvert.WorkspaceEdit.from(value);
|
||||
}, err => {
|
||||
if (typeof err === 'string') {
|
||||
return <WorkspaceEditDto>{
|
||||
edits: undefined,
|
||||
rejectReason: err
|
||||
};
|
||||
} else if (err instanceof Error && typeof err.message === 'string') {
|
||||
return <WorkspaceEditDto>{
|
||||
edits: undefined,
|
||||
rejectReason: err.message
|
||||
};
|
||||
let rejectReason = RenameAdapter._asMessage(err);
|
||||
if (rejectReason) {
|
||||
return <WorkspaceEditDto>{ rejectReason, edits: undefined };
|
||||
} else {
|
||||
// generic error
|
||||
return TPromise.wrapError<WorkspaceEditDto>(err);
|
||||
return Promise.reject<WorkspaceEditDto>(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resolveRenameLocation(resource: URI, position: IPosition): TPromise<modes.RenameLocation> {
|
||||
resolveRenameLocation(resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.RenameLocation & modes.Rejection> {
|
||||
if (typeof this._provider.prepareRename !== 'function') {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
let doc = this._documents.getDocumentData(resource).document;
|
||||
let pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => {
|
||||
return asThenable(() => this._provider.prepareRename(doc, pos, token)).then(rangeOrLocation => {
|
||||
|
||||
let range: vscode.Range;
|
||||
let text: string;
|
||||
@@ -534,14 +538,30 @@ class RenameAdapter {
|
||||
if (!range) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!range.contains(pos)) {
|
||||
console.warn('INVALID rename location: range must contain position');
|
||||
if (range.start.line > pos.line || range.end.line < pos.line) {
|
||||
console.warn('INVALID rename location: position line must be within range start/end lines');
|
||||
return undefined;
|
||||
}
|
||||
return { range: typeConvert.Range.from(range), text };
|
||||
}, err => {
|
||||
let rejectReason = RenameAdapter._asMessage(err);
|
||||
if (rejectReason) {
|
||||
return <modes.RenameLocation & modes.Rejection>{ rejectReason, range: undefined, text: undefined };
|
||||
} else {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static _asMessage(err: any): string {
|
||||
if (typeof err === 'string') {
|
||||
return err;
|
||||
} else if (err instanceof Error && typeof err.message === 'string') {
|
||||
return err.message;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SuggestAdapter {
|
||||
@@ -563,14 +583,14 @@ class SuggestAdapter {
|
||||
this._provider = provider;
|
||||
}
|
||||
|
||||
provideCompletionItems(resource: URI, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto> {
|
||||
provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Thenable<SuggestResultDto> {
|
||||
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise<vscode.CompletionItem[] | vscode.CompletionList>(token => {
|
||||
return this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.from(context));
|
||||
}).then(value => {
|
||||
return asThenable<vscode.CompletionItem[] | vscode.CompletionList>(
|
||||
() => this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.to(context))
|
||||
).then(value => {
|
||||
|
||||
const _id = this._idPool++;
|
||||
|
||||
@@ -610,19 +630,19 @@ class SuggestAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion> {
|
||||
resolveCompletionItem(resource: URI, position: IPosition, suggestion: modes.CompletionItem, token: CancellationToken): Thenable<modes.CompletionItem> {
|
||||
|
||||
if (typeof this._provider.resolveCompletionItem !== 'function') {
|
||||
return TPromise.as(suggestion);
|
||||
return Promise.resolve(suggestion);
|
||||
}
|
||||
|
||||
const { _parentId, _id } = (<SuggestionDto>suggestion);
|
||||
const item = this._cache.has(_parentId) && this._cache.get(_parentId)[_id];
|
||||
if (!item) {
|
||||
return TPromise.as(suggestion);
|
||||
return Promise.resolve(suggestion);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
|
||||
return asThenable(() => this._provider.resolveCompletionItem(item, token)).then(resolvedItem => {
|
||||
|
||||
if (!resolvedItem) {
|
||||
return suggestion;
|
||||
@@ -656,35 +676,38 @@ class SuggestAdapter {
|
||||
_parentId,
|
||||
//
|
||||
label: item.label,
|
||||
type: typeConvert.CompletionItemKind.from(item.kind),
|
||||
kind: typeConvert.CompletionItemKind.from(item.kind),
|
||||
detail: item.detail,
|
||||
documentation: item.documentation,
|
||||
documentation: typeConvert.MarkdownString.fromStrict(item.documentation),
|
||||
filterText: item.filterText,
|
||||
sortText: item.sortText,
|
||||
preselect: item.preselect,
|
||||
//
|
||||
range: undefined,
|
||||
insertText: undefined,
|
||||
insertTextRules: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0,
|
||||
additionalTextEdits: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||
command: this._commands.toInternal(item.command),
|
||||
commitCharacters: item.commitCharacters
|
||||
commitCharacters: item.commitCharacters,
|
||||
// help with perf
|
||||
_labelLow: item.label.toLowerCase(),
|
||||
_filterTextLow: item.filterText && item.filterText.toLowerCase(),
|
||||
_sortTextLow: item.sortText && item.sortText.toLowerCase()
|
||||
};
|
||||
|
||||
// 'insertText'-logic
|
||||
if (item.textEdit) {
|
||||
result.insertText = item.textEdit.newText;
|
||||
result.snippetType = 'internal';
|
||||
|
||||
} else if (typeof item.insertText === 'string') {
|
||||
result.insertText = item.insertText;
|
||||
result.snippetType = 'internal';
|
||||
|
||||
} else if (item.insertText instanceof SnippetString) {
|
||||
result.insertText = item.insertText.value;
|
||||
result.snippetType = 'textmate';
|
||||
result.insertTextRules += modes.CompletionItemInsertTextRule.InsertAsSnippet;
|
||||
|
||||
} else {
|
||||
result.insertText = item.label;
|
||||
result.snippetType = 'internal';
|
||||
}
|
||||
|
||||
// 'overwrite[Before|After]'-logic
|
||||
@@ -696,8 +719,7 @@ class SuggestAdapter {
|
||||
} else {
|
||||
range = defaultRange;
|
||||
}
|
||||
result.overwriteBefore = position.character - range.start.character;
|
||||
result.overwriteAfter = range.end.character - position.character;
|
||||
result.range = typeConvert.Range.from(range);
|
||||
|
||||
if (!range.isSingleLine || range.start.line !== position.line) {
|
||||
console.warn('INVALID text edit -> must be single line and on the same line');
|
||||
@@ -715,12 +737,12 @@ class SignatureHelpAdapter {
|
||||
private readonly _provider: vscode.SignatureHelpProvider
|
||||
) { }
|
||||
|
||||
provideSignatureHelp(resource: URI, position: IPosition): TPromise<modes.SignatureHelp> {
|
||||
provideSignatureHelp(resource: URI, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Thenable<modes.SignatureHelp> {
|
||||
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
const pos = typeConvert.Position.to(position);
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideSignatureHelp(doc, pos, token, context)).then(value => {
|
||||
if (value) {
|
||||
return typeConvert.SignatureHelp.from(value);
|
||||
}
|
||||
@@ -737,10 +759,10 @@ class LinkProviderAdapter {
|
||||
private readonly _provider: vscode.DocumentLinkProvider
|
||||
) { }
|
||||
|
||||
provideLinks(resource: URI): TPromise<modes.ILink[]> {
|
||||
provideLinks(resource: URI, token: CancellationToken): Thenable<modes.ILink[]> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideDocumentLinks(doc, token)).then(links => {
|
||||
return asThenable(() => this._provider.provideDocumentLinks(doc, token)).then(links => {
|
||||
if (!Array.isArray(links)) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -755,7 +777,7 @@ class LinkProviderAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
resolveLink(link: modes.ILink): TPromise<modes.ILink> {
|
||||
resolveLink(link: modes.ILink, token: CancellationToken): Thenable<modes.ILink> {
|
||||
if (typeof this._provider.resolveDocumentLink !== 'function') {
|
||||
return undefined;
|
||||
}
|
||||
@@ -766,7 +788,7 @@ class LinkProviderAdapter {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => this._provider.resolveDocumentLink(item, token)).then(value => {
|
||||
return asThenable(() => this._provider.resolveDocumentLink(item, token)).then(value => {
|
||||
if (value) {
|
||||
return typeConvert.DocumentLink.from(value);
|
||||
}
|
||||
@@ -782,9 +804,9 @@ class ColorProviderAdapter {
|
||||
private _provider: vscode.DocumentColorProvider
|
||||
) { }
|
||||
|
||||
provideColors(resource: URI): TPromise<IRawColorInfo[]> {
|
||||
provideColors(resource: URI, token: CancellationToken): Thenable<IRawColorInfo[]> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
return asWinJsPromise(token => this._provider.provideDocumentColors(doc, token)).then(colors => {
|
||||
return asThenable(() => this._provider.provideDocumentColors(doc, token)).then(colors => {
|
||||
if (!Array.isArray(colors)) {
|
||||
return [];
|
||||
}
|
||||
@@ -800,11 +822,11 @@ class ColorProviderAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
provideColorPresentations(resource: URI, raw: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
|
||||
provideColorPresentations(resource: URI, raw: IRawColorInfo, token: CancellationToken): Thenable<modes.IColorPresentation[]> {
|
||||
const document = this._documents.getDocumentData(resource).document;
|
||||
const range = typeConvert.Range.to(raw.range);
|
||||
const color = typeConvert.Color.to(raw.color);
|
||||
return asWinJsPromise(token => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => {
|
||||
return asThenable(() => this._provider.provideColorPresentations(color, { document, range }, token)).then(value => {
|
||||
return value.map(typeConvert.ColorPresentation.from);
|
||||
});
|
||||
}
|
||||
@@ -817,9 +839,9 @@ class FoldingProviderAdapter {
|
||||
private _provider: vscode.FoldingRangeProvider
|
||||
) { }
|
||||
|
||||
provideFoldingRanges(resource: URI, context: modes.FoldingContext): TPromise<modes.FoldingRange[]> {
|
||||
provideFoldingRanges(resource: URI, context: modes.FoldingContext, token: CancellationToken): Thenable<modes.FoldingRange[]> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
return asWinJsPromise(token => this._provider.provideFoldingRanges(doc, context, token)).then(ranges => {
|
||||
return asThenable(() => this._provider.provideFoldingRanges(doc, context, token)).then(ranges => {
|
||||
if (!Array.isArray(ranges)) {
|
||||
return void 0;
|
||||
}
|
||||
@@ -828,11 +850,46 @@ class FoldingProviderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
class SelectionRangeAdapter {
|
||||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.SelectionRangeProvider
|
||||
) { }
|
||||
|
||||
provideSelectionRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<IRange[]> {
|
||||
const { document } = this._documents.getDocumentData(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
return asThenable(() => this._provider.provideSelectionRanges(document, pos, token)).then(ranges => {
|
||||
if (isFalsyOrEmpty(ranges)) {
|
||||
return undefined;
|
||||
}
|
||||
let result: IRange[] = [];
|
||||
let last: vscode.Position | vscode.Range = pos;
|
||||
for (const range of ranges) {
|
||||
if (!range.contains(last)) {
|
||||
throw new Error('INVALID selection range, must contain the previous range');
|
||||
}
|
||||
result.push(typeConvert.Range.from(range));
|
||||
last = range;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
|
||||
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
|
||||
| ColorProviderAdapter | FoldingProviderAdapter;
|
||||
| ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | SelectionRangeAdapter;
|
||||
|
||||
class AdapterData {
|
||||
constructor(
|
||||
readonly adapter: Adapter,
|
||||
readonly extension: IExtensionDescription | undefined
|
||||
) { }
|
||||
}
|
||||
|
||||
export interface ISchemeTransformer {
|
||||
transformOutgoing(scheme: string): string;
|
||||
@@ -848,7 +905,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
private _commands: ExtHostCommands;
|
||||
private _heapService: ExtHostHeapService;
|
||||
private _diagnostics: ExtHostDiagnostics;
|
||||
private _adapter = new Map<number, Adapter>();
|
||||
private _adapter = new Map<number, AdapterData>();
|
||||
private readonly _logService: ILogService;
|
||||
|
||||
constructor(
|
||||
@@ -916,39 +973,55 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return ExtHostLanguageFeatures._handlePool++;
|
||||
}
|
||||
|
||||
private _withAdapter<A, R>(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => TPromise<R>): TPromise<R> {
|
||||
let adapter = this._adapter.get(handle);
|
||||
if (!(adapter instanceof ctor)) {
|
||||
return TPromise.wrapError<R>(new Error('no adapter found'));
|
||||
private _withAdapter<A, R>(handle: number, ctor: { new(...args: any[]): A }, callback: (adapter: A) => Thenable<R>): Thenable<R> {
|
||||
let data = this._adapter.get(handle);
|
||||
if (data.adapter instanceof ctor) {
|
||||
let t1: number;
|
||||
if (data.extension) {
|
||||
t1 = Date.now();
|
||||
this._logService.trace(`[${data.extension.id}] INVOKE provider '${(ctor as any).name}'`);
|
||||
}
|
||||
let p = callback(data.adapter);
|
||||
if (data.extension) {
|
||||
Promise.resolve(p).then(
|
||||
() => this._logService.trace(`[${data.extension.id}] provider DONE after ${Date.now() - t1}ms`),
|
||||
err => {
|
||||
this._logService.error(`[${data.extension.id}] provider FAILED`);
|
||||
this._logService.error(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
return callback(<any>adapter);
|
||||
return Promise.reject(new Error('no adapter found'));
|
||||
}
|
||||
|
||||
private _addNewAdapter(adapter: Adapter): number {
|
||||
private _addNewAdapter(adapter: Adapter, extension: IExtensionDescription): number {
|
||||
const handle = this._nextHandle();
|
||||
this._adapter.set(handle, adapter);
|
||||
this._adapter.set(handle, new AdapterData(adapter, extension));
|
||||
return handle;
|
||||
}
|
||||
|
||||
// --- outline
|
||||
|
||||
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, extension?: IExtensionDescription): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OutlineAdapter(this._documents, provider));
|
||||
this._proxy.$registerOutlineSupport(handle, this._transformDocumentSelector(selector), extension ? extension.displayName || extension.name : undefined);
|
||||
registerDocumentSymbolProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, metadata?: vscode.DocumentSymbolProviderMetadata): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OutlineAdapter(this._documents, provider), extension);
|
||||
const displayName = (metadata && metadata.label) || (extension && (extension.displayName || extension.name)) || undefined;
|
||||
this._proxy.$registerOutlineSupport(handle, this._transformDocumentSelector(selector), displayName);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents): TPromise<modes.DocumentSymbol[]> {
|
||||
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource)));
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.DocumentSymbol[]> {
|
||||
return this._withAdapter(handle, OutlineAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource), token));
|
||||
}
|
||||
|
||||
// --- code lens
|
||||
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
registerCodeLensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
const handle = this._nextHandle();
|
||||
const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined;
|
||||
|
||||
this._adapter.set(handle, new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider));
|
||||
this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider), extension));
|
||||
this._proxy.$registerCodeLensSupport(handle, this._transformDocumentSelector(selector), eventHandle);
|
||||
let result = this._createDisposable(handle);
|
||||
|
||||
@@ -960,177 +1033,187 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
$provideCodeLenses(handle: number, resource: UriComponents): TPromise<modes.ICodeLensSymbol[]> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource)));
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.ICodeLensSymbol[]> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token));
|
||||
}
|
||||
|
||||
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol));
|
||||
$resolveCodeLens(handle: number, resource: UriComponents, symbol: modes.ICodeLensSymbol, token: CancellationToken): Thenable<modes.ICodeLensSymbol> {
|
||||
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(URI.revive(resource), symbol, token));
|
||||
}
|
||||
|
||||
// --- declaration
|
||||
|
||||
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DefinitionAdapter(this._documents, provider));
|
||||
this._proxy.$registerDeclaractionSupport(handle, this._transformDocumentSelector(selector));
|
||||
registerDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DefinitionAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDefinitionSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(URI.revive(resource), position));
|
||||
$provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ImplementationAdapter(this._documents, provider));
|
||||
registerDeclarationProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DeclarationProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DeclarationAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDeclarationSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, DeclarationAdapter, adapter => adapter.provideDeclaration(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
registerImplementationProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ImplementationAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerImplementationSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideImplementation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(URI.revive(resource), position));
|
||||
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new TypeDefinitionAdapter(this._documents, provider));
|
||||
registerTypeDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new TypeDefinitionAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerTypeDefinitionSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(URI.revive(resource), position));
|
||||
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DefinitionLink[]> {
|
||||
return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
// --- extra info
|
||||
|
||||
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new HoverAdapter(this._documents, provider));
|
||||
registerHoverProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new HoverAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerHoverProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.Hover> {
|
||||
return this._withAdapter(handle, HoverAdapter, adpater => adpater.provideHover(URI.revive(resource), position));
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.Hover> {
|
||||
return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
// --- occurrences
|
||||
|
||||
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DocumentHighlightAdapter(this._documents, provider));
|
||||
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DocumentHighlightAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentHighlightProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.DocumentHighlight[]> {
|
||||
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position));
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> {
|
||||
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ReferenceAdapter(this._documents, provider));
|
||||
registerReferenceProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ReferenceAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerReferenceSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$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));
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> {
|
||||
return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(URI.revive(resource), position, context, token));
|
||||
}
|
||||
|
||||
// --- quick fix
|
||||
|
||||
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, extension?: IExtensionDescription, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider, this._logService, extension ? extension.id : ''));
|
||||
registerCodeActionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider, this._logService, extension.id), extension);
|
||||
this._proxy.$registerQuickFixSupport(handle, this._transformDocumentSelector(selector), metadata && metadata.providedCodeActionKinds ? metadata.providedCodeActionKinds.map(kind => kind.value) : undefined);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext): TPromise<CodeActionDto[]> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context));
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Thenable<CodeActionDto[]> {
|
||||
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token));
|
||||
}
|
||||
|
||||
// --- formatting
|
||||
|
||||
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DocumentFormattingAdapter(this._documents, provider));
|
||||
registerDocumentFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new DocumentFormattingAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentFormattingSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions): TPromise<ISingleEditOperation[]> {
|
||||
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options));
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options, token));
|
||||
}
|
||||
|
||||
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider));
|
||||
registerDocumentRangeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerRangeFormattingSupport(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$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));
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(URI.revive(resource), range, options, token));
|
||||
}
|
||||
|
||||
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OnTypeFormattingAdapter(this._documents, provider));
|
||||
registerOnTypeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OnTypeFormattingAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerOnTypeFormattingSupport(handle, this._transformDocumentSelector(selector), triggerCharacters);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$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));
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> {
|
||||
return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(URI.revive(resource), position, ch, options, token));
|
||||
}
|
||||
|
||||
// --- navigate types
|
||||
|
||||
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new NavigateTypeAdapter(provider));
|
||||
registerWorkspaceSymbolProvider(extension: IExtensionDescription, provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new NavigateTypeAdapter(provider), extension);
|
||||
this._proxy.$registerNavigateTypeSupport(handle);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideWorkspaceSymbols(handle: number, search: string): TPromise<WorkspaceSymbolsDto> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search));
|
||||
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Thenable<WorkspaceSymbolsDto> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token));
|
||||
}
|
||||
|
||||
$resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto): TPromise<WorkspaceSymbolDto> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol));
|
||||
$resolveWorkspaceSymbol(handle: number, symbol: WorkspaceSymbolDto, token: CancellationToken): Thenable<WorkspaceSymbolDto> {
|
||||
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token));
|
||||
}
|
||||
|
||||
$releaseWorkspaceSymbols(handle: number, id: number) {
|
||||
$releaseWorkspaceSymbols(handle: number, id: number): void {
|
||||
this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id));
|
||||
}
|
||||
|
||||
// --- rename
|
||||
|
||||
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider));
|
||||
registerRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerRenameSupport(handle, this._transformDocumentSelector(selector), RenameAdapter.supportsResolving(provider));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<WorkspaceEditDto> {
|
||||
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName));
|
||||
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Thenable<WorkspaceEditDto> {
|
||||
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token));
|
||||
}
|
||||
|
||||
$resolveRenameLocation(handle: number, resource: URI, position: IPosition): TPromise<modes.RenameLocation> {
|
||||
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveRenameLocation(URI.revive(resource), position));
|
||||
$resolveRenameLocation(handle: number, resource: URI, position: IPosition, token: CancellationToken): Thenable<modes.RenameLocation> {
|
||||
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveRenameLocation(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
// --- suggestion
|
||||
|
||||
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider));
|
||||
registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider), extension);
|
||||
this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$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));
|
||||
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Thenable<SuggestResultDto> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token));
|
||||
}
|
||||
|
||||
$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));
|
||||
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.CompletionItem, token: CancellationToken): Thenable<modes.CompletionItem> {
|
||||
return this._withAdapter(handle, SuggestAdapter, adapter => adapter.resolveCompletionItem(URI.revive(resource), position, suggestion, token));
|
||||
}
|
||||
|
||||
$releaseCompletionItems(handle: number, id: number): void {
|
||||
@@ -1139,54 +1222,70 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
|
||||
// --- parameter hints
|
||||
|
||||
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, triggerCharacters: string[]): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider));
|
||||
this._proxy.$registerSignatureHelpProvider(handle, this._transformDocumentSelector(selector), triggerCharacters);
|
||||
registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars?: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable {
|
||||
const metadata: ISerializedSignatureHelpProviderMetadata = Array.isArray(metadataOrTriggerChars)
|
||||
? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] }
|
||||
: metadataOrTriggerChars;
|
||||
|
||||
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerSignatureHelpProvider(handle, this._transformDocumentSelector(selector), metadata);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.SignatureHelp> {
|
||||
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position));
|
||||
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Thenable<modes.SignatureHelp> {
|
||||
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token));
|
||||
}
|
||||
|
||||
// --- links
|
||||
|
||||
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, this._heapService, provider));
|
||||
registerDocumentLinkProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, this._heapService, provider), extension);
|
||||
this._proxy.$registerDocumentLinkProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents): TPromise<modes.ILink[]> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource)));
|
||||
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Thenable<modes.ILink[]> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token));
|
||||
}
|
||||
|
||||
$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link));
|
||||
$resolveDocumentLink(handle: number, link: modes.ILink, token: CancellationToken): Thenable<modes.ILink> {
|
||||
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(link, token));
|
||||
}
|
||||
|
||||
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ColorProviderAdapter(this._documents, provider));
|
||||
registerColorProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new ColorProviderAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerDocumentColorProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentColors(handle: number, resource: UriComponents): TPromise<IRawColorInfo[]> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource)));
|
||||
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Thenable<IRawColorInfo[]> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource), token));
|
||||
}
|
||||
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo));
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Thenable<modes.IColorPresentation[]> {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token));
|
||||
}
|
||||
|
||||
registerFoldingRangeProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider));
|
||||
registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerFoldingRangeProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext): TPromise<modes.FoldingRange[]> {
|
||||
return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource), context));
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext, token: CancellationToken): Thenable<modes.FoldingRange[]> {
|
||||
return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource), context, token));
|
||||
}
|
||||
|
||||
// --- smart select
|
||||
|
||||
registerSelectionRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerSelectionRangeProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideSelectionRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Thenable<IRange[]> {
|
||||
return this._withAdapter(handle, SelectionRangeAdapter, adapter => adapter.provideSelectionRanges(URI.revive(resource), position, token));
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
@@ -1223,6 +1322,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return {
|
||||
beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
|
||||
afterText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText),
|
||||
oneLineAboveText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.oneLineAboveText),
|
||||
action: onEnterRule.action
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,22 +2,31 @@
|
||||
* 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 { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { MainContext, MainThreadLanguagesShape, IMainContext } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
||||
|
||||
export class ExtHostLanguages {
|
||||
|
||||
private _proxy: MainThreadLanguagesShape;
|
||||
private readonly _proxy: MainThreadLanguagesShape;
|
||||
private readonly _documents: ExtHostDocuments;
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext
|
||||
mainContext: IMainContext,
|
||||
documents: ExtHostDocuments
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguages);
|
||||
this._documents = documents;
|
||||
}
|
||||
|
||||
getLanguages(): TPromise<string[]> {
|
||||
getLanguages(): Thenable<string[]> {
|
||||
return this._proxy.$getLanguages();
|
||||
}
|
||||
|
||||
changeLanguage(uri: vscode.Uri, languageId: string): Thenable<vscode.TextDocument> {
|
||||
return this._proxy.$changeLanguage(uri, languageId).then(() => {
|
||||
return this._documents.getDocumentData(uri).document;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,80 +2,34 @@
|
||||
* 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 { join } from 'vs/base/common/paths';
|
||||
import { LogLevel } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ILogService, DelegatedLogService } from 'vs/platform/log/common/log';
|
||||
import { ILogService, DelegatedLogService, LogLevel } from 'vs/platform/log/common/log';
|
||||
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { ExtHostLogServiceShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
|
||||
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
|
||||
|
||||
private _loggers: Map<string, ExtHostLogger> = new Map();
|
||||
private _logsPath: string;
|
||||
readonly logFile: URI;
|
||||
|
||||
constructor(
|
||||
private _windowId: number,
|
||||
logLevel: LogLevel,
|
||||
private _logsPath: string
|
||||
logsPath: string,
|
||||
) {
|
||||
super(createSpdLogService(`exthost${_windowId}`, logLevel, _logsPath));
|
||||
super(createSpdLogService(ExtensionHostLogFileName, logLevel, logsPath));
|
||||
this._logsPath = logsPath;
|
||||
this.logFile = URI.file(join(logsPath, `${ExtensionHostLogFileName}.log`));
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
getLogDirectory(extensionID: string): string {
|
||||
return join(this._logsPath, `${extensionID}_${this._windowId}`);
|
||||
}
|
||||
|
||||
private createLogger(extensionID: string): ExtHostLogger {
|
||||
const logsDirPath = this.getLogDirectory(extensionID);
|
||||
const logService = createSpdLogService(extensionID, this.getLevel(), logsDirPath);
|
||||
this._register(this.onDidChangeLogLevel(level => logService.setLevel(level)));
|
||||
return new ExtHostLogger(logService);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostLogger implements vscode.Logger {
|
||||
|
||||
constructor(
|
||||
private readonly _logService: ILogService
|
||||
) { }
|
||||
|
||||
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);
|
||||
return join(this._logsPath, extensionID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* 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 Severity from 'vs/base/common/severity';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
@@ -2,41 +2,47 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { MainContext, MainThreadOutputServiceShape, IMainContext } from './extHost.protocol';
|
||||
import { MainContext, MainThreadOutputServiceShape, IMainContext, ExtHostOutputServiceShape } from './extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { posix } from 'path';
|
||||
import { OutputAppender } from 'vs/platform/output/node/outputAppender';
|
||||
import { toLocalISOString } from 'vs/base/common/date';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
||||
export class ExtHostOutputChannel implements vscode.OutputChannel {
|
||||
export abstract class AbstractExtHostOutputChannel extends Disposable implements vscode.OutputChannel {
|
||||
|
||||
private static _idPool = 1;
|
||||
|
||||
private _proxy: MainThreadOutputServiceShape;
|
||||
private _name: string;
|
||||
private _id: string;
|
||||
readonly _id: Thenable<string>;
|
||||
private readonly _name: string;
|
||||
protected readonly _proxy: MainThreadOutputServiceShape;
|
||||
private _disposed: boolean;
|
||||
private _offset: number;
|
||||
|
||||
protected readonly _onDidAppend: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onDidAppend: Event<void> = this._onDidAppend.event;
|
||||
|
||||
constructor(name: string, log: boolean, file: URI, proxy: MainThreadOutputServiceShape) {
|
||||
super();
|
||||
|
||||
constructor(name: string, proxy: MainThreadOutputServiceShape) {
|
||||
this._name = name;
|
||||
this._id = 'extension-output-#' + (ExtHostOutputChannel._idPool++);
|
||||
this._proxy = proxy;
|
||||
this._id = proxy.$register(this.name, log, file);
|
||||
this._offset = 0;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (!this._disposed) {
|
||||
this._proxy.$dispose(this._id, this._name).then(() => {
|
||||
this._disposed = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
this.validate();
|
||||
this._proxy.$append(this._id, this._name, value);
|
||||
this._offset += value ? Buffer.from(value).byteLength : 0;
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._id.then(id => this._proxy.$update(id));
|
||||
}
|
||||
|
||||
appendLine(value: string): void {
|
||||
@@ -46,44 +52,149 @@ export class ExtHostOutputChannel implements vscode.OutputChannel {
|
||||
|
||||
clear(): void {
|
||||
this.validate();
|
||||
this._proxy.$clear(this._id, this._name);
|
||||
const till = this._offset;
|
||||
this._id.then(id => this._proxy.$clear(id, till));
|
||||
}
|
||||
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
this.validate();
|
||||
if (typeof columnOrPreserveFocus === 'boolean') {
|
||||
preserveFocus = columnOrPreserveFocus;
|
||||
}
|
||||
|
||||
this._proxy.$reveal(this._id, this._name, preserveFocus);
|
||||
this._id.then(id => this._proxy.$reveal(id, typeof columnOrPreserveFocus === 'boolean' ? columnOrPreserveFocus : preserveFocus));
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
this.validate();
|
||||
this._proxy.$close(this._id);
|
||||
this._id.then(id => this._proxy.$close(id));
|
||||
}
|
||||
|
||||
private validate(): void {
|
||||
protected validate(): void {
|
||||
if (this._disposed) {
|
||||
throw new Error('Channel has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (!this._disposed) {
|
||||
this._id
|
||||
.then(id => this._proxy.$dispose(id))
|
||||
.then(() => this._disposed = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostOutputService {
|
||||
export class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
|
||||
|
||||
constructor(name: string, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, false, null, proxy);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
super.append(value);
|
||||
this._id.then(id => this._proxy.$append(id, value));
|
||||
this._onDidAppend.fire();
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
|
||||
private static _namePool = 1;
|
||||
private _appender: OutputAppender;
|
||||
|
||||
constructor(name: string, outputDir: string, proxy: MainThreadOutputServiceShape) {
|
||||
const fileName = `${ExtHostOutputChannelBackedByFile._namePool++}-${name}`;
|
||||
const file = URI.file(posix.join(outputDir, `${fileName}.log`));
|
||||
|
||||
super(name, false, file, proxy);
|
||||
this._appender = new OutputAppender(fileName, file.fsPath);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
super.append(value);
|
||||
this._appender.append(value);
|
||||
this._onDidAppend.fire();
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._appender.flush();
|
||||
super.update();
|
||||
}
|
||||
|
||||
show(columnOrPreserveFocus?: vscode.ViewColumn | boolean, preserveFocus?: boolean): void {
|
||||
this._appender.flush();
|
||||
super.show(columnOrPreserveFocus, preserveFocus);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this._appender.flush();
|
||||
super.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostLogFileOutputChannel extends AbstractExtHostOutputChannel {
|
||||
|
||||
constructor(name: string, file: URI, proxy: MainThreadOutputServiceShape) {
|
||||
super(name, true, file, proxy);
|
||||
}
|
||||
|
||||
append(value: string): void {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostOutputService implements ExtHostOutputServiceShape {
|
||||
|
||||
private _proxy: MainThreadOutputServiceShape;
|
||||
private _outputDir: string;
|
||||
private _channels: Map<string, AbstractExtHostOutputChannel> = new Map<string, AbstractExtHostOutputChannel>();
|
||||
private _visibleChannelDisposable: IDisposable;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
constructor(logsLocation: URI, mainContext: IMainContext) {
|
||||
this._outputDir = posix.join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadOutputService);
|
||||
}
|
||||
|
||||
$setVisibleChannel(channelId: string): void {
|
||||
if (this._visibleChannelDisposable) {
|
||||
this._visibleChannelDisposable = dispose(this._visibleChannelDisposable);
|
||||
}
|
||||
if (channelId) {
|
||||
const channel = this._channels.get(channelId);
|
||||
if (channel) {
|
||||
this._visibleChannelDisposable = channel.onDidAppend(() => channel.update());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
const channel = this._createOutputChannel(name);
|
||||
channel._id.then(id => this._channels.set(id, channel));
|
||||
return channel;
|
||||
}
|
||||
|
||||
private _createOutputChannel(name: string): AbstractExtHostOutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
} else {
|
||||
return new ExtHostOutputChannel(name, this._proxy);
|
||||
// Do not crash if logger cannot be created
|
||||
try {
|
||||
return new ExtHostOutputChannelBackedByFile(name, this._outputDir, this._proxy);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return new ExtHostPushOutputChannel(name, this._proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOutputChannelFromLogFile(name: string, file: URI): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
}
|
||||
if (!file) {
|
||||
throw new Error('illegal argument `file`. must not be falsy');
|
||||
}
|
||||
return new ExtHostLogFileOutputChannel(name, file, this._proxy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
* 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 { ProgressOptions } from 'vscode';
|
||||
import { MainThreadProgressShape, ExtHostProgressShape } from './extHost.protocol';
|
||||
import { ProgressLocation } from './extHostTypeConverters';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { Progress, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { IProgressStep } from 'vs/workbench/services/progress/common/progress';
|
||||
|
||||
export class ExtHostProgress implements ExtHostProgressShape {
|
||||
|
||||
|
||||
@@ -2,19 +2,18 @@
|
||||
* 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 { asWinJsPromise, wireCancellationToken } from 'vs/base/common/async';
|
||||
import { asThenable } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
|
||||
import { ExtHostQuickOpenShape, IMainContext, MainContext, MainThreadQuickOpenShape, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
|
||||
export type Item = string | QuickPickItem;
|
||||
|
||||
@@ -29,32 +28,39 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
|
||||
private _sessions = new Map<number, ExtHostQuickInput>();
|
||||
|
||||
private _instances = 0;
|
||||
|
||||
constructor(mainContext: IMainContext, workspace: ExtHostWorkspace, commands: ExtHostCommands) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadQuickOpen);
|
||||
this._workspace = workspace;
|
||||
this._commands = commands;
|
||||
}
|
||||
|
||||
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: string[] | Thenable<string[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: Item[] | Thenable<Item[]>, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
|
||||
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, enableProposedApi: boolean, options: QuickPickOptions & { canPickMany: true; }, token?: CancellationToken): Thenable<QuickPickItem[] | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: string[] | Thenable<string[]>, enableProposedApi: boolean, options?: QuickPickOptions, token?: CancellationToken): Thenable<string | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: QuickPickItem[] | Thenable<QuickPickItem[]>, enableProposedApi: boolean, options?: QuickPickOptions, token?: CancellationToken): Thenable<QuickPickItem | undefined>;
|
||||
showQuickPick(itemsOrItemsPromise: Item[] | Thenable<Item[]>, enableProposedApi: boolean, options?: QuickPickOptions, token: CancellationToken = CancellationToken.None): Thenable<Item | Item[] | undefined> {
|
||||
|
||||
// clear state from last invocation
|
||||
this._onDidSelectItem = undefined;
|
||||
|
||||
const itemsPromise = <TPromise<Item[]>>TPromise.wrap(itemsOrItemsPromise);
|
||||
const itemsPromise = <Promise<Item[]>>Promise.resolve(itemsOrItemsPromise);
|
||||
|
||||
const quickPickWidget = this._proxy.$show({
|
||||
const instance = ++this._instances;
|
||||
|
||||
const quickPickWidget = this._proxy.$show(instance, {
|
||||
placeHolder: options && options.placeHolder,
|
||||
matchOnDescription: options && options.matchOnDescription,
|
||||
matchOnDetail: options && options.matchOnDetail,
|
||||
ignoreFocusLost: options && options.ignoreFocusOut,
|
||||
canPickMany: options && options.canPickMany
|
||||
});
|
||||
}, token);
|
||||
|
||||
const promise = TPromise.any(<TPromise<number | Item[]>[]>[quickPickWidget, itemsPromise]).then(values => {
|
||||
if (values.key === '0') {
|
||||
const widgetClosedMarker = {};
|
||||
const widgetClosedPromise = quickPickWidget.then(() => widgetClosedMarker);
|
||||
|
||||
return Promise.race([widgetClosedPromise, itemsPromise]).then(result => {
|
||||
if (result === widgetClosedMarker) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -68,6 +74,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
let description: string;
|
||||
let detail: string;
|
||||
let picked: boolean;
|
||||
let alwaysShow: boolean;
|
||||
|
||||
if (typeof item === 'string') {
|
||||
label = item;
|
||||
@@ -76,13 +83,15 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
description = item.description;
|
||||
detail = item.detail;
|
||||
picked = item.picked;
|
||||
alwaysShow = item.alwaysShow;
|
||||
}
|
||||
pickItems.push({
|
||||
label,
|
||||
description,
|
||||
handle,
|
||||
detail,
|
||||
picked
|
||||
picked,
|
||||
alwaysShow
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,7 +103,7 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
}
|
||||
|
||||
// show items
|
||||
this._proxy.$setItems(pickItems);
|
||||
this._proxy.$setItems(instance, pickItems);
|
||||
|
||||
return quickPickWidget.then(handle => {
|
||||
if (typeof handle === 'number') {
|
||||
@@ -104,13 +113,16 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}, (err) => {
|
||||
this._proxy.$setError(err);
|
||||
|
||||
return TPromise.wrapError(err);
|
||||
});
|
||||
}).then(null, err => {
|
||||
if (isPromiseCanceledError(err)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this._proxy.$setError(instance, err);
|
||||
|
||||
return Promise.reject(err);
|
||||
});
|
||||
return wireCancellationToken<Item | Item[]>(token, promise, true);
|
||||
}
|
||||
|
||||
$onItemSelected(handle: number): void {
|
||||
@@ -126,13 +138,19 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
// global validate fn used in callback below
|
||||
this._validateInput = options && options.validateInput;
|
||||
|
||||
const promise = this._proxy.$input(options, typeof this._validateInput === 'function');
|
||||
return wireCancellationToken(token, promise, true);
|
||||
return this._proxy.$input(options, typeof this._validateInput === 'function', token)
|
||||
.then(null, err => {
|
||||
if (isPromiseCanceledError(err)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
$validateInput(input: string): TPromise<string> {
|
||||
$validateInput(input: string): Thenable<string> {
|
||||
if (this._validateInput) {
|
||||
return asWinJsPromise(_ => this._validateInput(input));
|
||||
return asThenable(() => this._validateInput(input));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -151,8 +169,8 @@ export class ExtHostQuickOpen implements ExtHostQuickOpenShape {
|
||||
|
||||
// ---- QuickInput
|
||||
|
||||
createQuickPick<T extends QuickPickItem>(extensionId: string): QuickPick<T> {
|
||||
const session = new ExtHostQuickPick(this._proxy, extensionId, () => this._sessions.delete(session._id));
|
||||
createQuickPick<T extends QuickPickItem>(extensionId: string, enableProposedApi: boolean): QuickPick<T> {
|
||||
const session = new ExtHostQuickPick(this._proxy, extensionId, enableProposedApi, () => this._sessions.delete(session._id));
|
||||
this._sessions.set(session._id, session);
|
||||
return session;
|
||||
}
|
||||
@@ -215,6 +233,7 @@ class ExtHostQuickInput implements QuickInput {
|
||||
private _steps: number;
|
||||
private _totalSteps: number;
|
||||
private _visible = false;
|
||||
private _expectingHide = false;
|
||||
private _enabled = true;
|
||||
private _busy = false;
|
||||
private _ignoreFocusOut = true;
|
||||
@@ -226,7 +245,7 @@ class ExtHostQuickInput implements QuickInput {
|
||||
private _onDidChangeValueEmitter = new Emitter<string>();
|
||||
private _onDidTriggerButtonEmitter = new Emitter<QuickInputButton>();
|
||||
private _onDidHideEmitter = new Emitter<void>();
|
||||
private _updateTimeout: number;
|
||||
private _updateTimeout: any;
|
||||
private _pendingUpdate: TransferQuickInput = { id: this._id };
|
||||
|
||||
private _disposed = false;
|
||||
@@ -340,6 +359,7 @@ class ExtHostQuickInput implements QuickInput {
|
||||
|
||||
show(): void {
|
||||
this._visible = true;
|
||||
this._expectingHide = true;
|
||||
this.update({ visible: true });
|
||||
}
|
||||
|
||||
@@ -365,7 +385,10 @@ class ExtHostQuickInput implements QuickInput {
|
||||
}
|
||||
|
||||
_fireDidHide() {
|
||||
this._onDidHideEmitter.fire();
|
||||
if (this._expectingHide) {
|
||||
this._expectingHide = false;
|
||||
this._onDidHideEmitter.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -456,7 +479,7 @@ class ExtHostQuickPick<T extends QuickPickItem> extends ExtHostQuickInput implem
|
||||
private _selectedItems: T[] = [];
|
||||
private _onDidChangeSelectionEmitter = new Emitter<T[]>();
|
||||
|
||||
constructor(proxy: MainThreadQuickOpenShape, extensionId: string, onDispose: () => void) {
|
||||
constructor(proxy: MainThreadQuickOpenShape, extensionId: string, enableProposedApi: boolean, onDispose: () => void) {
|
||||
super(proxy, extensionId, onDispose);
|
||||
this._disposables.push(
|
||||
this._onDidChangeActiveEmitter,
|
||||
@@ -483,7 +506,8 @@ class ExtHostQuickPick<T extends QuickPickItem> extends ExtHostQuickInput implem
|
||||
description: item.description,
|
||||
handle: i,
|
||||
detail: item.detail,
|
||||
picked: item.picked
|
||||
picked: item.picked,
|
||||
alwaysShow: item.alwaysShow
|
||||
}))
|
||||
});
|
||||
}
|
||||
@@ -587,4 +611,4 @@ class ExtHostInputBox extends ExtHostQuickInput implements InputBox {
|
||||
this._validationMessage = validationMessage;
|
||||
this.update({ validationMessage });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
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 { asThenable } from 'vs/base/common/async';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape } from './extHost.protocol';
|
||||
@@ -18,6 +16,7 @@ import { comparePaths } from 'vs/base/common/comparers';
|
||||
import * as vscode from 'vscode';
|
||||
import { ISplice } from 'vs/base/common/sequence';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
type ProviderHandle = number;
|
||||
type GroupHandle = number;
|
||||
@@ -110,6 +109,37 @@ function compareResourceStates(a: vscode.SourceControlResourceState, b: vscode.S
|
||||
return result;
|
||||
}
|
||||
|
||||
function compareArgs(a: any[], b: any[]): boolean {
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function commandEquals(a: vscode.Command, b: vscode.Command): boolean {
|
||||
return a.command === b.command
|
||||
&& a.title === b.title
|
||||
&& a.tooltip === b.tooltip
|
||||
&& (a.arguments && b.arguments ? compareArgs(a.arguments, b.arguments) : a.arguments === b.arguments);
|
||||
}
|
||||
|
||||
function commandListEquals(a: vscode.Command[], b: vscode.Command[]): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (!commandEquals(a[i], b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export interface IValidateInput {
|
||||
(value: string, cursorPosition: number): vscode.ProviderResult<vscode.SourceControlInputBoxValidation | undefined | null>;
|
||||
}
|
||||
@@ -168,6 +198,18 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
|
||||
this._proxy.$setValidationProviderIsEnabled(this._sourceControlHandle, !!fn);
|
||||
}
|
||||
|
||||
private _visible: boolean = true;
|
||||
|
||||
get visible(): boolean {
|
||||
return this._visible;
|
||||
}
|
||||
|
||||
set visible(visible: boolean | undefined) {
|
||||
visible = !!visible;
|
||||
this._visible = visible;
|
||||
this._proxy.$setInputBoxVisibility(this._sourceControlHandle, visible);
|
||||
}
|
||||
|
||||
constructor(private _extension: IExtensionDescription, private _proxy: MainThreadSCMShape, private _sourceControlHandle: number) {
|
||||
// noop
|
||||
}
|
||||
@@ -237,14 +279,14 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
return this._resourceStatesMap.get(handle);
|
||||
}
|
||||
|
||||
$executeResourceCommand(handle: number): TPromise<void> {
|
||||
$executeResourceCommand(handle: number): Thenable<void> {
|
||||
const command = this._resourceStatesCommandsMap.get(handle);
|
||||
|
||||
if (!command) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(_ => this._commands.executeCommand(command.command, ...command.arguments));
|
||||
return asThenable(() => this._commands.executeCommand(command.command, ...command.arguments));
|
||||
}
|
||||
|
||||
_takeResourceStateSnapshot(): SCMRawResourceSplice[] {
|
||||
@@ -343,6 +385,10 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
}
|
||||
|
||||
set count(count: number | undefined) {
|
||||
if (this._count === count) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._count = count;
|
||||
this._proxy.$updateSourceControl(this.handle, { count });
|
||||
}
|
||||
@@ -389,12 +435,25 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
}
|
||||
|
||||
set statusBarCommands(statusBarCommands: vscode.Command[] | undefined) {
|
||||
if (this._statusBarCommands && statusBarCommands && commandListEquals(this._statusBarCommands, statusBarCommands)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._statusBarCommands = statusBarCommands;
|
||||
|
||||
const internal = (statusBarCommands || []).map(c => this._commands.converter.toInternal(c));
|
||||
this._proxy.$updateSourceControl(this.handle, { statusBarCommands: internal });
|
||||
}
|
||||
|
||||
private _selected: boolean = false;
|
||||
|
||||
get selected(): boolean {
|
||||
return this._selected;
|
||||
}
|
||||
|
||||
private _onDidChangeSelection = new Emitter<boolean>();
|
||||
readonly onDidChangeSelection = this._onDidChangeSelection.event;
|
||||
|
||||
private handle: number = ExtHostSourceControl._handlePool++;
|
||||
|
||||
constructor(
|
||||
@@ -454,6 +513,11 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
return this._groups.get(handle);
|
||||
}
|
||||
|
||||
setSelectionState(selected: boolean): void {
|
||||
this._selected = selected;
|
||||
this._onDidChangeSelection.fire(selected);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._groups.forEach(group => group.dispose());
|
||||
this._proxy.$unregisterSourceControl(this.handle);
|
||||
@@ -471,6 +535,8 @@ export class ExtHostSCM implements ExtHostSCMShape {
|
||||
private _onDidChangeActiveProvider = new Emitter<vscode.SourceControl>();
|
||||
get onDidChangeActiveProvider(): Event<vscode.SourceControl> { return this._onDidChangeActiveProvider.event; }
|
||||
|
||||
private _selectedSourceControlHandles = new Set<number>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
private _commands: ExtHostCommands,
|
||||
@@ -542,69 +608,106 @@ export class ExtHostSCM implements ExtHostSCMShape {
|
||||
return inputBox;
|
||||
}
|
||||
|
||||
$provideOriginalResource(sourceControlHandle: number, uriComponents: UriComponents): TPromise<UriComponents> {
|
||||
$provideOriginalResource(sourceControlHandle: number, uriComponents: UriComponents, token: CancellationToken): Thenable<UriComponents> {
|
||||
const uri = URI.revive(uriComponents);
|
||||
this.logService.trace('ExtHostSCM#$provideOriginalResource', sourceControlHandle, uri.toString());
|
||||
|
||||
const sourceControl = this._sourceControls.get(sourceControlHandle);
|
||||
|
||||
if (!sourceControl || !sourceControl.quickDiffProvider) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return asWinJsPromise(token => sourceControl.quickDiffProvider.provideOriginalResource(uri, token));
|
||||
return asThenable(() => sourceControl.quickDiffProvider.provideOriginalResource(uri, token));
|
||||
}
|
||||
|
||||
$onInputBoxValueChange(sourceControlHandle: number, value: string): TPromise<void> {
|
||||
$onInputBoxValueChange(sourceControlHandle: number, value: string): Promise<void> {
|
||||
this.logService.trace('ExtHostSCM#$onInputBoxValueChange', sourceControlHandle);
|
||||
|
||||
const sourceControl = this._sourceControls.get(sourceControlHandle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
sourceControl.inputBox.$onInputBoxValueChange(value);
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): TPromise<void> {
|
||||
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number): Thenable<void> {
|
||||
this.logService.trace('ExtHostSCM#$executeResourceCommand', sourceControlHandle, groupHandle, handle);
|
||||
|
||||
const sourceControl = this._sourceControls.get(sourceControlHandle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
const group = sourceControl.getResourceGroup(groupHandle);
|
||||
|
||||
if (!group) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return group.$executeResourceCommand(handle);
|
||||
}
|
||||
|
||||
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): TPromise<[string, number] | undefined> {
|
||||
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Thenable<[string, number] | undefined> {
|
||||
this.logService.trace('ExtHostSCM#$validateInput', sourceControlHandle);
|
||||
|
||||
const sourceControl = this._sourceControls.get(sourceControlHandle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (!sourceControl.inputBox.validateInput) {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return asWinJsPromise(_ => Promise.resolve(sourceControl.inputBox.validateInput(value, cursorPosition))).then(result => {
|
||||
return asThenable(() => sourceControl.inputBox.validateInput(value, cursorPosition)).then(result => {
|
||||
if (!result) {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return TPromise.as<[string, number]>([result.message, result.type]);
|
||||
return Promise.resolve<[string, number]>([result.message, result.type]);
|
||||
});
|
||||
}
|
||||
|
||||
$setSelectedSourceControls(selectedSourceControlHandles: number[]): Thenable<void> {
|
||||
this.logService.trace('ExtHostSCM#$setSelectedSourceControls', selectedSourceControlHandles);
|
||||
|
||||
const set = new Set<number>();
|
||||
|
||||
for (const handle of selectedSourceControlHandles) {
|
||||
set.add(handle);
|
||||
}
|
||||
|
||||
set.forEach(handle => {
|
||||
if (!this._selectedSourceControlHandles.has(handle)) {
|
||||
const sourceControl = this._sourceControls.get(handle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
sourceControl.setSelectionState(true);
|
||||
}
|
||||
});
|
||||
|
||||
this._selectedSourceControlHandles.forEach(handle => {
|
||||
if (!set.has(handle)) {
|
||||
const sourceControl = this._sourceControls.get(handle);
|
||||
|
||||
if (!sourceControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
sourceControl.setSelectionState(false);
|
||||
}
|
||||
});
|
||||
|
||||
this._selectedSourceControlHandles = set;
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,143 +2,27 @@
|
||||
* 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 path from 'path';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer';
|
||||
import { IFileMatch, IFolderQuery, IRawSearchQuery, ISearchCompleteStats, ISearchQuery } from 'vs/platform/search/common/search';
|
||||
import { ICachedSearchStats, IFileIndexProviderStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, ISearchCompleteStats } from 'vs/platform/search/common/search';
|
||||
import { IDirectoryEntry, IDirectoryTree, IInternalFileMatch } from 'vs/workbench/services/search/node/fileSearchManager';
|
||||
import { QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/node/search';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export interface IInternalFileMatch {
|
||||
base: URI;
|
||||
original?: URI;
|
||||
relativePath?: string; // Not present for extraFiles or absolute path matches
|
||||
basename: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the patterns that the provider handles. Discards sibling clauses and 'false' patterns
|
||||
*/
|
||||
export function resolvePatternsForProvider(globalPattern: glob.IExpression, folderPattern: glob.IExpression): string[] {
|
||||
const merged = {
|
||||
...(globalPattern || {}),
|
||||
...(folderPattern || {})
|
||||
};
|
||||
|
||||
return Object.keys(merged)
|
||||
.filter(key => {
|
||||
const value = merged[key];
|
||||
return typeof value === 'boolean' && value;
|
||||
});
|
||||
}
|
||||
|
||||
export class QueryGlobTester {
|
||||
|
||||
private _excludeExpression: glob.IExpression;
|
||||
private _parsedExcludeExpression: glob.ParsedExpression;
|
||||
|
||||
private _parsedIncludeExpression: glob.ParsedExpression;
|
||||
|
||||
constructor(config: ISearchQuery, folderQuery: IFolderQuery) {
|
||||
this._excludeExpression = {
|
||||
...(config.excludePattern || {}),
|
||||
...(folderQuery.excludePattern || {})
|
||||
};
|
||||
this._parsedExcludeExpression = glob.parse(this._excludeExpression);
|
||||
|
||||
// Empty includeExpression means include nothing, so no {} shortcuts
|
||||
let includeExpression: glob.IExpression = config.includePattern;
|
||||
if (folderQuery.includePattern) {
|
||||
if (includeExpression) {
|
||||
includeExpression = {
|
||||
...includeExpression,
|
||||
...folderQuery.includePattern
|
||||
};
|
||||
} else {
|
||||
includeExpression = folderQuery.includePattern;
|
||||
}
|
||||
}
|
||||
|
||||
if (includeExpression) {
|
||||
this._parsedIncludeExpression = glob.parse(includeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed sync - siblingsFn should not return a promise.
|
||||
*/
|
||||
public includedInQuerySync(testPath: string, basename?: string, hasSibling?: (name: string) => boolean): boolean {
|
||||
if (this._parsedExcludeExpression && this._parsedExcludeExpression(testPath, basename, hasSibling)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._parsedIncludeExpression && !this._parsedIncludeExpression(testPath, basename, hasSibling)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed async.
|
||||
*/
|
||||
public includedInQuery(testPath: string, basename?: string, hasSibling?: (name: string) => boolean | TPromise<boolean>): TPromise<boolean> {
|
||||
const excludeP = this._parsedExcludeExpression ?
|
||||
TPromise.as(this._parsedExcludeExpression(testPath, basename, hasSibling)).then(result => !!result) :
|
||||
TPromise.wrap(false);
|
||||
|
||||
return excludeP.then(excluded => {
|
||||
if (excluded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._parsedIncludeExpression ?
|
||||
TPromise.as(this._parsedIncludeExpression(testPath, basename, hasSibling)).then(result => !!result) :
|
||||
TPromise.wrap(true);
|
||||
}).then(included => {
|
||||
return included;
|
||||
});
|
||||
}
|
||||
|
||||
public hasSiblingExcludeClauses(): boolean {
|
||||
return hasSiblingClauses(this._excludeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
function hasSiblingClauses(pattern: glob.IExpression): boolean {
|
||||
for (let key in pattern) {
|
||||
if (typeof pattern[key] !== 'boolean') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export interface IDirectoryEntry {
|
||||
base: URI;
|
||||
relativePath: string;
|
||||
basename: string;
|
||||
}
|
||||
|
||||
export interface IDirectoryTree {
|
||||
rootEntries: IDirectoryEntry[];
|
||||
pathToEntries: { [relativePath: string]: IDirectoryEntry[] };
|
||||
}
|
||||
|
||||
// ???
|
||||
interface IInternalSearchComplete {
|
||||
interface IInternalSearchComplete<T = IFileSearchStats> {
|
||||
limitHit: boolean;
|
||||
results: IInternalFileMatch[];
|
||||
stats: T;
|
||||
}
|
||||
|
||||
export class FileIndexSearchEngine {
|
||||
@@ -151,11 +35,14 @@ export class FileIndexSearchEngine {
|
||||
private resultCount: number;
|
||||
private isCanceled: boolean;
|
||||
|
||||
private filesWalked = 0;
|
||||
private dirsWalked = 0;
|
||||
|
||||
private activeCancellationTokens: Set<CancellationTokenSource>;
|
||||
|
||||
private globalExcludePattern: glob.ParsedExpression;
|
||||
|
||||
constructor(private config: ISearchQuery, private provider: vscode.FileIndexProvider) {
|
||||
constructor(private config: IFileQuery, private provider: vscode.FileIndexProvider) {
|
||||
this.filePattern = config.filePattern;
|
||||
this.includePattern = config.includePattern && glob.parse(config.includePattern);
|
||||
this.maxResults = config.maxResults || null;
|
||||
@@ -177,21 +64,18 @@ export class FileIndexSearchEngine {
|
||||
this.activeCancellationTokens = new Set();
|
||||
}
|
||||
|
||||
public search(_onResult: (match: IInternalFileMatch) => void): TPromise<{ isLimitHit: boolean }> {
|
||||
if (this.config.folderQueries.length !== 1) {
|
||||
throw new Error('Searches just one folder');
|
||||
}
|
||||
|
||||
public search(_onResult: (match: IInternalFileMatch) => void): Promise<{ isLimitHit: boolean, stats: IFileIndexProviderStats }> {
|
||||
// Searches a single folder
|
||||
const folderQuery = this.config.folderQueries[0];
|
||||
|
||||
return new TPromise<{ isLimitHit: boolean }>((resolve, reject) => {
|
||||
return new Promise<{ isLimitHit: boolean, stats: IFileIndexProviderStats }>((resolve, reject) => {
|
||||
const onResult = (match: IInternalFileMatch) => {
|
||||
this.resultCount++;
|
||||
_onResult(match);
|
||||
};
|
||||
|
||||
if (this.isCanceled) {
|
||||
return resolve({ isLimitHit: this.isLimitHit });
|
||||
throw canceled();
|
||||
}
|
||||
|
||||
// For each extra file
|
||||
@@ -209,22 +93,31 @@ export class FileIndexSearchEngine {
|
||||
});
|
||||
}
|
||||
|
||||
return this.searchInFolder(folderQuery, _onResult)
|
||||
.then(() => {
|
||||
resolve({ isLimitHit: this.isLimitHit });
|
||||
}, (errs: Error[]) => {
|
||||
const errMsg = errs
|
||||
.map(err => toErrorMessage(err))
|
||||
.filter(msg => !!msg)[0];
|
||||
|
||||
reject(new Error(errMsg));
|
||||
return Promise.all(this.config.folderQueries.map(fq => this.searchInFolder(folderQuery, onResult))).then(stats => {
|
||||
resolve({
|
||||
isLimitHit: this.isLimitHit,
|
||||
stats: {
|
||||
directoriesWalked: this.dirsWalked,
|
||||
filesWalked: this.filesWalked,
|
||||
fileWalkTime: stats.map(s => s.fileWalkTime).reduce((s, c) => s + c, 0),
|
||||
providerTime: stats.map(s => s.providerTime).reduce((s, c) => s + c, 0),
|
||||
providerResultCount: stats.map(s => s.providerResultCount).reduce((s, c) => s + c, 0)
|
||||
}
|
||||
});
|
||||
}, (errs: Error[]) => {
|
||||
if (!Array.isArray(errs)) {
|
||||
errs = [errs];
|
||||
}
|
||||
|
||||
errs = errs.filter(e => !!e);
|
||||
return Promise.reject(errs[0]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private searchInFolder(fq: IFolderQuery<URI>, onResult: (match: IInternalFileMatch) => void): TPromise<void> {
|
||||
private searchInFolder(fq: IFolderQuery<URI>, onResult: (match: IInternalFileMatch) => void): Promise<IFileIndexProviderStats> {
|
||||
let cancellation = new CancellationTokenSource();
|
||||
return new TPromise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = this.getSearchOptionsForFolder(fq);
|
||||
const tree = this.initDirectoryTree();
|
||||
|
||||
@@ -249,12 +142,18 @@ export class FileIndexSearchEngine {
|
||||
this.addDirectoryEntries(tree, fq.folder, relativePath, onResult);
|
||||
};
|
||||
|
||||
new TPromise(resolve => process.nextTick(resolve))
|
||||
let providerSW: StopWatch;
|
||||
let providerTime: number;
|
||||
let fileWalkTime: number;
|
||||
new Promise(resolve => process.nextTick(resolve))
|
||||
.then(() => {
|
||||
this.activeCancellationTokens.add(cancellation);
|
||||
providerSW = StopWatch.create();
|
||||
return this.provider.provideFileIndex(options, cancellation.token);
|
||||
})
|
||||
.then(results => {
|
||||
providerTime = providerSW.elapsed();
|
||||
const postProcessSW = StopWatch.create();
|
||||
this.activeCancellationTokens.delete(cancellation);
|
||||
if (this.isCanceled) {
|
||||
return null;
|
||||
@@ -263,11 +162,17 @@ export class FileIndexSearchEngine {
|
||||
results.forEach(onProviderResult);
|
||||
|
||||
this.matchDirectoryTree(tree, queryTester, onResult);
|
||||
fileWalkTime = postProcessSW.elapsed();
|
||||
return null;
|
||||
}).then(
|
||||
() => {
|
||||
cancellation.dispose();
|
||||
resolve(undefined);
|
||||
resolve(<IFileIndexProviderStats>{
|
||||
providerTime,
|
||||
fileWalkTime,
|
||||
directoriesWalked: this.dirsWalked,
|
||||
filesWalked: this.filesWalked
|
||||
});
|
||||
},
|
||||
err => {
|
||||
cancellation.dispose();
|
||||
@@ -284,8 +189,9 @@ export class FileIndexSearchEngine {
|
||||
folder: fq.folder,
|
||||
excludes,
|
||||
includes,
|
||||
useIgnoreFiles: !this.config.disregardIgnoreFiles,
|
||||
followSymlinks: !this.config.ignoreSymlinks
|
||||
useIgnoreFiles: !fq.disregardIgnoreFiles,
|
||||
useGlobalIgnoreFiles: !fq.disregardGlobalIgnoreFiles,
|
||||
followSymlinks: !fq.ignoreSymlinks
|
||||
};
|
||||
}
|
||||
|
||||
@@ -327,7 +233,7 @@ export class FileIndexSearchEngine {
|
||||
const self = this;
|
||||
const filePattern = this.filePattern;
|
||||
function matchDirectory(entries: IDirectoryEntry[]) {
|
||||
// self.directoriesWalked++;
|
||||
self.dirsWalked++;
|
||||
for (let i = 0, n = entries.length; i < n; i++) {
|
||||
const entry = entries[i];
|
||||
const { relativePath, basename } = entry;
|
||||
@@ -345,7 +251,7 @@ export class FileIndexSearchEngine {
|
||||
if (sub) {
|
||||
matchDirectory(sub);
|
||||
} else {
|
||||
// self.filesWalked++;
|
||||
self.filesWalked++;
|
||||
if (relativePath === filePattern) {
|
||||
continue; // ignore file if its path matches with the file pattern because that is already matched above
|
||||
}
|
||||
@@ -397,9 +303,9 @@ export class FileIndexSearchManager {
|
||||
|
||||
private readonly folderCacheKeys = new Map<string, Set<string>>();
|
||||
|
||||
public fileSearch(config: ISearchQuery, provider: vscode.FileIndexProvider, onBatch: (matches: IFileMatch[]) => void): TPromise<ISearchCompleteStats> {
|
||||
public fileSearch(config: IFileQuery, provider: vscode.FileIndexProvider, onBatch: (matches: IFileMatch[]) => void, token: CancellationToken): Promise<ISearchCompleteStats> {
|
||||
if (config.sortByScore) {
|
||||
let sortedSearch = this.trySortedSearchFromCache(config);
|
||||
let sortedSearch = this.trySortedSearchFromCache(config, token);
|
||||
if (!sortedSearch) {
|
||||
const engineConfig = config.maxResults ?
|
||||
{
|
||||
@@ -409,30 +315,32 @@ export class FileIndexSearchManager {
|
||||
config;
|
||||
|
||||
const engine = new FileIndexSearchEngine(engineConfig, provider);
|
||||
sortedSearch = this.doSortedSearch(engine, config);
|
||||
sortedSearch = this.doSortedSearch(engine, config, token);
|
||||
}
|
||||
|
||||
return new TPromise<ISearchCompleteStats>((c, e) => {
|
||||
sortedSearch.then(complete => {
|
||||
this.sendAsBatches(complete.results, onBatch, FileIndexSearchManager.BATCH_SIZE);
|
||||
c(complete);
|
||||
}, e, onBatch);
|
||||
}, () => {
|
||||
sortedSearch.cancel();
|
||||
return sortedSearch.then(complete => {
|
||||
this.sendAsBatches(complete.results, onBatch, FileIndexSearchManager.BATCH_SIZE);
|
||||
return complete;
|
||||
});
|
||||
}
|
||||
|
||||
const engine = new FileIndexSearchEngine(config, provider);
|
||||
return this.doSearch(engine)
|
||||
return this.doSearch(engine, token)
|
||||
.then(complete => {
|
||||
this.sendAsBatches(complete.results, onBatch, FileIndexSearchManager.BATCH_SIZE);
|
||||
return <ISearchCompleteStats>{
|
||||
limitHit: complete.limitHit
|
||||
limitHit: complete.limitHit,
|
||||
stats: {
|
||||
type: 'fileIndexProvider',
|
||||
detailStats: complete.stats,
|
||||
fromCache: false,
|
||||
resultCount: complete.results.length
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private getFolderCacheKey(config: ISearchQuery): string {
|
||||
private getFolderCacheKey(config: IFileQuery): string {
|
||||
const uri = config.folderQueries[0].folder.toString();
|
||||
const folderCacheKey = config.cacheKey && `${uri}_${config.cacheKey}`;
|
||||
if (!this.folderCacheKeys.get(config.cacheKey)) {
|
||||
@@ -450,41 +358,50 @@ export class FileIndexSearchManager {
|
||||
};
|
||||
}
|
||||
|
||||
private doSortedSearch(engine: FileIndexSearchEngine, config: ISearchQuery): TPromise<IInternalSearchComplete> {
|
||||
let searchPromise: TPromise<void>;
|
||||
let allResultsPromise = new TPromise<IInternalSearchComplete>((c, e) => {
|
||||
searchPromise = this.doSearch(engine).then(c, e);
|
||||
}, () => {
|
||||
searchPromise.cancel();
|
||||
private doSortedSearch(engine: FileIndexSearchEngine, config: IFileQuery, token: CancellationToken): Promise<IInternalSearchComplete> {
|
||||
let allResultsPromise = createCancelablePromise<IInternalSearchComplete<IFileIndexProviderStats>>(token => {
|
||||
return this.doSearch(engine, token);
|
||||
});
|
||||
|
||||
const folderCacheKey = this.getFolderCacheKey(config);
|
||||
let cache: Cache;
|
||||
if (folderCacheKey) {
|
||||
cache = this.getOrCreateCache(folderCacheKey);
|
||||
cache.resultsToSearchCache[config.filePattern] = allResultsPromise;
|
||||
allResultsPromise.then(null, err => {
|
||||
const cacheRow: ICacheRow = {
|
||||
promise: allResultsPromise,
|
||||
resolved: false
|
||||
};
|
||||
cache.resultsToSearchCache[config.filePattern] = cacheRow;
|
||||
allResultsPromise.then(() => {
|
||||
cacheRow.resolved = true;
|
||||
}, err => {
|
||||
delete cache.resultsToSearchCache[config.filePattern];
|
||||
});
|
||||
allResultsPromise = this.preventCancellation(allResultsPromise);
|
||||
}
|
||||
|
||||
let chained: TPromise<void>;
|
||||
return new TPromise<IInternalSearchComplete>((c, e) => {
|
||||
chained = allResultsPromise.then(complete => {
|
||||
return Promise.resolve<IInternalSearchComplete>(
|
||||
allResultsPromise.then(complete => {
|
||||
const scorerCache: ScorerCache = cache ? cache.scorerCache : Object.create(null);
|
||||
return this.sortResults(config, complete.results, scorerCache)
|
||||
const sortSW = (typeof config.maxResults !== 'number' || config.maxResults > 0) && StopWatch.create();
|
||||
return this.sortResults(config, complete.results, scorerCache, token)
|
||||
.then(sortedResults => {
|
||||
|
||||
c({
|
||||
// sortingTime: -1 indicates a "sorted" search that was not sorted, i.e. populating the cache when quickopen is opened.
|
||||
// Contrasting with findFiles which is not sorted and will have sortingTime: undefined
|
||||
const sortingTime = sortSW ? sortSW.elapsed() : -1;
|
||||
return <IInternalSearchComplete>{
|
||||
limitHit: complete.limitHit || typeof config.maxResults === 'number' && complete.results.length > config.maxResults, // ??
|
||||
results: sortedResults
|
||||
});
|
||||
results: sortedResults,
|
||||
stats: {
|
||||
detailStats: complete.stats,
|
||||
fromCache: false,
|
||||
resultCount: sortedResults.length,
|
||||
sortingTime,
|
||||
type: 'fileIndexProvider'
|
||||
}
|
||||
};
|
||||
});
|
||||
}, e);
|
||||
}, () => {
|
||||
chained.cancel();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private getOrCreateCache(cacheKey: string): Cache {
|
||||
@@ -495,34 +412,41 @@ export class FileIndexSearchManager {
|
||||
return this.caches[cacheKey] = new Cache();
|
||||
}
|
||||
|
||||
private trySortedSearchFromCache(config: ISearchQuery): TPromise<IInternalSearchComplete> {
|
||||
private trySortedSearchFromCache(config: IFileQuery, token: CancellationToken): Promise<IInternalSearchComplete> {
|
||||
const folderCacheKey = this.getFolderCacheKey(config);
|
||||
const cache = folderCacheKey && this.caches[folderCacheKey];
|
||||
if (!cache) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const cached = this.getResultsFromCache(cache, config.filePattern);
|
||||
const cached = this.getResultsFromCache(cache, config.filePattern, token);
|
||||
if (cached) {
|
||||
let chained: TPromise<void>;
|
||||
return new TPromise<IInternalSearchComplete>((c, e) => {
|
||||
chained = cached.then(complete => {
|
||||
return this.sortResults(config, complete.results, cache.scorerCache)
|
||||
.then(sortedResults => {
|
||||
c({
|
||||
limitHit: complete.limitHit || typeof config.maxResults === 'number' && complete.results.length > config.maxResults,
|
||||
results: sortedResults
|
||||
});
|
||||
});
|
||||
}, e);
|
||||
}, () => {
|
||||
chained.cancel();
|
||||
return cached.then(complete => {
|
||||
const sortSW = StopWatch.create();
|
||||
return this.sortResults(config, complete.results, cache.scorerCache, token)
|
||||
.then(sortedResults => {
|
||||
if (token && token.isCancellationRequested) {
|
||||
throw canceled();
|
||||
}
|
||||
|
||||
return <IInternalSearchComplete<IFileSearchStats>>{
|
||||
limitHit: complete.limitHit || typeof config.maxResults === 'number' && complete.results.length > config.maxResults,
|
||||
results: sortedResults,
|
||||
stats: {
|
||||
fromCache: true,
|
||||
detailStats: complete.stats,
|
||||
type: 'fileIndexProvider',
|
||||
resultCount: sortedResults.length,
|
||||
sortingTime: sortSW.elapsed()
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private sortResults(config: IRawSearchQuery, results: IInternalFileMatch[], scorerCache: ScorerCache): TPromise<IInternalFileMatch[]> {
|
||||
private sortResults(config: IFileQuery, results: IInternalFileMatch[], scorerCache: ScorerCache, token: CancellationToken): Promise<IInternalFileMatch[]> {
|
||||
// we use the same compare function that is used later when showing the results using fuzzy scoring
|
||||
// this is very important because we are also limiting the number of results by config.maxResults
|
||||
// and as such we want the top items to be included in this result set if the number of items
|
||||
@@ -530,7 +454,7 @@ export class FileIndexSearchManager {
|
||||
const query = prepareQuery(config.filePattern);
|
||||
const compare = (matchA: IInternalFileMatch, matchB: IInternalFileMatch) => compareItemsByScore(matchA, matchB, query, true, FileMatchItemAccessor, scorerCache);
|
||||
|
||||
return arrays.topAsync(results, compare, config.maxResults, 10000);
|
||||
return arrays.topAsync(results, compare, config.maxResults, 10000, token);
|
||||
}
|
||||
|
||||
private sendAsBatches(rawMatches: IInternalFileMatch[], onBatch: (batch: IFileMatch[]) => void, batchSize: number) {
|
||||
@@ -544,14 +468,16 @@ export class FileIndexSearchManager {
|
||||
}
|
||||
}
|
||||
|
||||
private getResultsFromCache(cache: Cache, searchValue: string): TPromise<IInternalSearchComplete> {
|
||||
private getResultsFromCache(cache: Cache, searchValue: string, token: CancellationToken): Promise<IInternalSearchComplete<ICachedSearchStats>> {
|
||||
const cacheLookupSW = StopWatch.create();
|
||||
|
||||
if (path.isAbsolute(searchValue)) {
|
||||
return null; // bypass cache if user looks up an absolute path where matching goes directly on disk
|
||||
}
|
||||
|
||||
// Find cache entries by prefix of search value
|
||||
const hasPathSep = searchValue.indexOf(path.sep) >= 0;
|
||||
let cached: TPromise<IInternalSearchComplete>;
|
||||
let cacheRow: ICacheRow;
|
||||
for (let previousSearch in cache.resultsToSearchCache) {
|
||||
|
||||
// If we narrow down, we might be able to reuse the cached results
|
||||
@@ -560,18 +486,30 @@ export class FileIndexSearchManager {
|
||||
continue; // since a path character widens the search for potential more matches, require it in previous search too
|
||||
}
|
||||
|
||||
const c = cache.resultsToSearchCache[previousSearch];
|
||||
cached = this.preventCancellation(c);
|
||||
const row = cache.resultsToSearchCache[previousSearch];
|
||||
cacheRow = {
|
||||
promise: this.preventCancellation(row.promise),
|
||||
resolved: row.resolved
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached) {
|
||||
if (!cacheRow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TPromise<IInternalSearchComplete>((c, e) => {
|
||||
cached.then(complete => {
|
||||
const cacheLookupTime = cacheLookupSW.elapsed();
|
||||
const cacheFilterSW = StopWatch.create();
|
||||
|
||||
return new Promise<IInternalSearchComplete<ICachedSearchStats>>((c, e) => {
|
||||
token.onCancellationRequested(() => e(canceled()));
|
||||
|
||||
cacheRow.promise.then(complete => {
|
||||
if (token && token.isCancellationRequested) {
|
||||
e(canceled());
|
||||
}
|
||||
|
||||
// Pattern match on results
|
||||
let results: IInternalFileMatch[] = [];
|
||||
const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase();
|
||||
@@ -586,34 +524,37 @@ export class FileIndexSearchManager {
|
||||
results.push(entry);
|
||||
}
|
||||
|
||||
c({
|
||||
c(<IInternalSearchComplete<ICachedSearchStats>>{
|
||||
limitHit: complete.limitHit,
|
||||
results
|
||||
results,
|
||||
stats: {
|
||||
cacheWasResolved: cacheRow.resolved,
|
||||
cacheLookupTime,
|
||||
cacheFilterTime: cacheFilterSW.elapsed(),
|
||||
cacheEntryCount: complete.results.length
|
||||
}
|
||||
});
|
||||
}, e);
|
||||
}, () => {
|
||||
cached.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
private doSearch(engine: FileIndexSearchEngine): TPromise<IInternalSearchComplete> {
|
||||
private doSearch(engine: FileIndexSearchEngine, token: CancellationToken): Promise<IInternalSearchComplete<IFileIndexProviderStats>> {
|
||||
token.onCancellationRequested(() => engine.cancel());
|
||||
const results: IInternalFileMatch[] = [];
|
||||
const onResult = match => results.push(match);
|
||||
return new TPromise<IInternalSearchComplete>((c, e) => {
|
||||
engine.search(onResult).then(result => {
|
||||
c({
|
||||
limitHit: result.isLimitHit,
|
||||
results
|
||||
});
|
||||
}, e);
|
||||
}, () => {
|
||||
engine.cancel();
|
||||
|
||||
return engine.search(onResult).then(result => {
|
||||
return <IInternalSearchComplete<IFileIndexProviderStats>>{
|
||||
limitHit: result.isLimitHit,
|
||||
results,
|
||||
stats: result.stats
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public clearCache(cacheKey: string): TPromise<void> {
|
||||
public clearCache(cacheKey: string): void {
|
||||
if (!this.folderCacheKeys.has(cacheKey)) {
|
||||
return TPromise.wrap(undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const expandedKeys = this.folderCacheKeys.get(cacheKey);
|
||||
@@ -621,24 +562,32 @@ export class FileIndexSearchManager {
|
||||
|
||||
this.folderCacheKeys.delete(cacheKey);
|
||||
|
||||
return TPromise.as(undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private preventCancellation<C>(promise: TPromise<C>): TPromise<C> {
|
||||
return new TPromise<C>((c, e) => {
|
||||
// Allow for piled up cancellations to come through first.
|
||||
process.nextTick(() => {
|
||||
promise.then(c, e);
|
||||
});
|
||||
}, () => {
|
||||
// Do not propagate.
|
||||
});
|
||||
private preventCancellation<C>(promise: CancelablePromise<C>): CancelablePromise<C> {
|
||||
return new class implements CancelablePromise<C> {
|
||||
cancel() {
|
||||
// Do nothing
|
||||
}
|
||||
then(resolve, reject) {
|
||||
return promise.then(resolve, reject);
|
||||
}
|
||||
catch(reject?) {
|
||||
return this.then(undefined, reject);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
interface ICacheRow {
|
||||
promise: CancelablePromise<IInternalSearchComplete<IFileIndexProviderStats>>;
|
||||
resolved: boolean;
|
||||
}
|
||||
|
||||
class Cache {
|
||||
|
||||
public resultsToSearchCache: { [searchValue: string]: TPromise<IInternalSearchComplete>; } = Object.create(null);
|
||||
public resultsToSearchCache: { [searchValue: string]: ICacheRow; } = Object.create(null);
|
||||
|
||||
public scorerCache: ScorerCache = Object.create(null);
|
||||
}
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
* 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 path from 'path';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import * as glob from 'vs/base/common/glob';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as extfs from 'vs/base/node/extfs';
|
||||
import { IFileMatch, IFolderQuery, IPatternInfo, IRawSearchQuery, ISearchCompleteStats, ISearchQuery } from 'vs/platform/search/common/search';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IFileQuery, IFolderQuery, IRawFileQuery, IRawQuery, IRawTextQuery, ISearchCompleteStats, ITextQuery } from 'vs/platform/search/common/search';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { FileIndexSearchManager } from 'vs/workbench/api/node/extHostSearch.fileIndex';
|
||||
import { FileSearchManager } from 'vs/workbench/services/search/node/fileSearchManager';
|
||||
import { SearchService } from 'vs/workbench/services/search/node/rawSearchService';
|
||||
import { RipgrepSearchProvider } from 'vs/workbench/services/search/node/ripgrepSearchProvider';
|
||||
import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils';
|
||||
import { isSerializedFileMatch } from 'vs/workbench/services/search/node/search';
|
||||
import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from './extHost.protocol';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IInternalFileMatch, QueryGlobTester, resolvePatternsForProvider, IDirectoryTree, IDirectoryEntry, FileIndexSearchManager } from 'vs/workbench/api/node/extHostSearch.fileIndex';
|
||||
|
||||
export interface ISchemeTransformer {
|
||||
transformOutgoing(scheme: string): string;
|
||||
@@ -25,18 +27,26 @@ export interface ISchemeTransformer {
|
||||
export class ExtHostSearch implements ExtHostSearchShape {
|
||||
|
||||
private readonly _proxy: MainThreadSearchShape;
|
||||
private readonly _fileSearchProvider = new Map<number, vscode.FileSearchProvider>();
|
||||
private readonly _textSearchProvider = new Map<number, vscode.TextSearchProvider>();
|
||||
private readonly _textSearchUsedSchemes = new Set<string>();
|
||||
private readonly _fileSearchProvider = new Map<number, vscode.FileSearchProvider>();
|
||||
private readonly _fileSearchUsedSchemes = new Set<string>();
|
||||
private readonly _fileIndexProvider = new Map<number, vscode.FileIndexProvider>();
|
||||
private readonly _fileIndexUsedSchemes = new Set<string>();
|
||||
private _handlePool: number = 0;
|
||||
|
||||
private _internalFileSearchHandle: number;
|
||||
private _internalFileSearchProvider: SearchService;
|
||||
|
||||
private _fileSearchManager: FileSearchManager;
|
||||
private _fileIndexSearchManager: FileIndexSearchManager;
|
||||
|
||||
constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer, private _extfs = extfs) {
|
||||
constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer, private _logService: ILogService, configService: ExtHostConfiguration, private _extfs = extfs) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadSearch);
|
||||
this._fileSearchManager = new FileSearchManager();
|
||||
this._fileIndexSearchManager = new FileIndexSearchManager();
|
||||
|
||||
registerEHProviders(this, _logService, configService);
|
||||
}
|
||||
|
||||
private _transformScheme(scheme: string): string {
|
||||
@@ -46,76 +56,138 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
||||
return scheme;
|
||||
}
|
||||
|
||||
registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider) {
|
||||
const handle = this._handlePool++;
|
||||
this._fileSearchProvider.set(handle, provider);
|
||||
this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme));
|
||||
return toDisposable(() => {
|
||||
this._fileSearchProvider.delete(handle);
|
||||
this._proxy.$unregisterProvider(handle);
|
||||
});
|
||||
}
|
||||
registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable {
|
||||
if (this._textSearchUsedSchemes.has(scheme)) {
|
||||
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
|
||||
}
|
||||
|
||||
registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider) {
|
||||
this._textSearchUsedSchemes.add(scheme);
|
||||
const handle = this._handlePool++;
|
||||
this._textSearchProvider.set(handle, provider);
|
||||
this._proxy.$registerTextSearchProvider(handle, this._transformScheme(scheme));
|
||||
return toDisposable(() => {
|
||||
this._textSearchUsedSchemes.delete(scheme);
|
||||
this._textSearchProvider.delete(handle);
|
||||
this._proxy.$unregisterProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
registerFileIndexProvider(scheme: string, provider: vscode.FileIndexProvider) {
|
||||
registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider): IDisposable {
|
||||
if (this._fileSearchUsedSchemes.has(scheme)) {
|
||||
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
|
||||
}
|
||||
|
||||
this._fileSearchUsedSchemes.add(scheme);
|
||||
const handle = this._handlePool++;
|
||||
this._fileSearchProvider.set(handle, provider);
|
||||
this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme));
|
||||
return toDisposable(() => {
|
||||
this._fileSearchUsedSchemes.delete(scheme);
|
||||
this._fileSearchProvider.delete(handle);
|
||||
this._proxy.$unregisterProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable {
|
||||
const handle = this._handlePool++;
|
||||
this._internalFileSearchProvider = provider;
|
||||
this._internalFileSearchHandle = handle;
|
||||
this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme));
|
||||
return toDisposable(() => {
|
||||
this._internalFileSearchProvider = null;
|
||||
this._proxy.$unregisterProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
registerFileIndexProvider(scheme: string, provider: vscode.FileIndexProvider): IDisposable {
|
||||
if (this._fileIndexUsedSchemes.has(scheme)) {
|
||||
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
|
||||
}
|
||||
|
||||
this._fileIndexUsedSchemes.add(scheme);
|
||||
const handle = this._handlePool++;
|
||||
this._fileIndexProvider.set(handle, provider);
|
||||
this._proxy.$registerFileIndexProvider(handle, this._transformScheme(scheme));
|
||||
return toDisposable(() => {
|
||||
this._fileIndexUsedSchemes.delete(scheme);
|
||||
this._fileSearchProvider.delete(handle);
|
||||
this._proxy.$unregisterProvider(handle); // TODO@roblou - unregisterFileIndexProvider
|
||||
});
|
||||
}
|
||||
|
||||
$provideFileSearchResults(handle: number, session: number, rawQuery: IRawSearchQuery): TPromise<ISearchCompleteStats> {
|
||||
const provider = this._fileSearchProvider.get(handle);
|
||||
$provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: CancellationToken): Thenable<ISearchCompleteStats> {
|
||||
const query = reviveQuery(rawQuery);
|
||||
if (provider) {
|
||||
return this._fileSearchManager.fileSearch(query, provider, batch => {
|
||||
this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource));
|
||||
});
|
||||
if (handle === this._internalFileSearchHandle) {
|
||||
return this.doInternalFileSearch(handle, session, query, token);
|
||||
} else {
|
||||
const indexProvider = this._fileIndexProvider.get(handle);
|
||||
if (indexProvider) {
|
||||
const provider = this._fileSearchProvider.get(handle);
|
||||
if (provider) {
|
||||
return this._fileSearchManager.fileSearch(query, provider, batch => {
|
||||
this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource));
|
||||
}, token);
|
||||
} else {
|
||||
const indexProvider = this._fileIndexProvider.get(handle);
|
||||
return this._fileIndexSearchManager.fileSearch(query, indexProvider, batch => {
|
||||
this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource));
|
||||
});
|
||||
} else {
|
||||
throw new Error('something went wrong');
|
||||
}, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$clearCache(cacheKey: string): TPromise<void> {
|
||||
// Actually called once per provider.
|
||||
// Only relevant to file index search.
|
||||
return this._fileIndexSearchManager.clearCache(cacheKey);
|
||||
private doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: CancellationToken): Thenable<ISearchCompleteStats> {
|
||||
const onResult = (ev) => {
|
||||
if (isSerializedFileMatch(ev)) {
|
||||
ev = [ev];
|
||||
}
|
||||
|
||||
if (Array.isArray(ev)) {
|
||||
this._proxy.$handleFileMatch(handle, session, ev.map(m => URI.file(m.path)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.message) {
|
||||
this._logService.debug('ExtHostSearch', ev.message);
|
||||
}
|
||||
};
|
||||
|
||||
return this._internalFileSearchProvider.doFileSearch(rawQuery, onResult, token);
|
||||
}
|
||||
|
||||
$provideTextSearchResults(handle: number, session: number, pattern: IPatternInfo, rawQuery: IRawSearchQuery): TPromise<ISearchCompleteStats> {
|
||||
$clearCache(cacheKey: string): Thenable<void> {
|
||||
if (this._internalFileSearchProvider) {
|
||||
this._internalFileSearchProvider.clearCache(cacheKey);
|
||||
}
|
||||
|
||||
this._fileSearchManager.clearCache(cacheKey);
|
||||
this._fileIndexSearchManager.clearCache(cacheKey);
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
$provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: CancellationToken): Thenable<ISearchCompleteStats> {
|
||||
const provider = this._textSearchProvider.get(handle);
|
||||
if (!provider.provideTextSearchResults) {
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const query = reviveQuery(rawQuery);
|
||||
const engine = new TextSearchEngine(pattern, query, provider, this._extfs);
|
||||
return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress));
|
||||
const engine = new TextSearchManager(query, provider, this._extfs);
|
||||
return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token);
|
||||
}
|
||||
}
|
||||
|
||||
function reviveQuery(rawQuery: IRawSearchQuery): ISearchQuery {
|
||||
function registerEHProviders(extHostSearch: ExtHostSearch, logService: ILogService, configService: ExtHostConfiguration) {
|
||||
if (configService.getConfiguration('searchRipgrep').enable || configService.getConfiguration('search').runInExtensionHost) {
|
||||
const outputChannel = new OutputChannel(logService);
|
||||
extHostSearch.registerTextSearchProvider('file', new RipgrepSearchProvider(outputChannel));
|
||||
|
||||
extHostSearch.registerInternalFileSearchProvider('file', new SearchService());
|
||||
}
|
||||
}
|
||||
|
||||
function reviveQuery<U extends IRawQuery>(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery {
|
||||
return {
|
||||
...rawQuery,
|
||||
...<any>rawQuery, // TODO
|
||||
...{
|
||||
folderQueries: rawQuery.folderQueries && rawQuery.folderQueries.map(reviveFolderQuery),
|
||||
extraFileResources: rawQuery.extraFileResources && rawQuery.extraFileResources.map(components => URI.revive(components))
|
||||
@@ -130,585 +202,3 @@ function reviveFolderQuery(rawFolderQuery: IFolderQuery<UriComponents>): IFolder
|
||||
};
|
||||
}
|
||||
|
||||
class TextSearchResultsCollector {
|
||||
private _batchedCollector: BatchedCollector<IFileMatch>;
|
||||
|
||||
private _currentFolderIdx: number;
|
||||
private _currentUri: URI;
|
||||
private _currentFileMatch: IFileMatch;
|
||||
|
||||
constructor(private _onResult: (result: IFileMatch[]) => void) {
|
||||
this._batchedCollector = new BatchedCollector<IFileMatch>(512, items => this.sendItems(items));
|
||||
}
|
||||
|
||||
add(data: vscode.TextSearchResult, folderIdx: number): void {
|
||||
// Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector.
|
||||
// This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search
|
||||
// providers that send results in random order. We could do this step afterwards instead.
|
||||
if (this._currentFileMatch && (this._currentFolderIdx !== folderIdx || resources.isEqual(this._currentUri, data.uri))) {
|
||||
this.pushToCollector();
|
||||
this._currentFileMatch = null;
|
||||
}
|
||||
|
||||
if (!this._currentFileMatch) {
|
||||
this._currentFileMatch = {
|
||||
resource: data.uri,
|
||||
lineMatches: []
|
||||
};
|
||||
}
|
||||
|
||||
// TODO@roblou - line text is sent for every match
|
||||
const matchRange = data.preview.match;
|
||||
this._currentFileMatch.lineMatches.push({
|
||||
lineNumber: data.range.start.line,
|
||||
preview: data.preview.text,
|
||||
offsetAndLengths: [[matchRange.start.character, matchRange.end.character - matchRange.start.character]]
|
||||
});
|
||||
}
|
||||
|
||||
private pushToCollector(): void {
|
||||
const size = this._currentFileMatch ?
|
||||
this._currentFileMatch.lineMatches.reduce((acc, match) => acc + match.offsetAndLengths.length, 0) :
|
||||
0;
|
||||
this._batchedCollector.addItem(this._currentFileMatch, size);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.pushToCollector();
|
||||
this._batchedCollector.flush();
|
||||
}
|
||||
|
||||
private sendItems(items: IFileMatch[]): void {
|
||||
this._onResult(items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every
|
||||
* set of items collected.
|
||||
* But after that point, the callback is called with batches of maxBatchSize.
|
||||
* If the batch isn't filled within some time, the callback is also called.
|
||||
*/
|
||||
class BatchedCollector<T> {
|
||||
private static readonly TIMEOUT = 4000;
|
||||
|
||||
// After START_BATCH_AFTER_COUNT items have been collected, stop flushing on timeout
|
||||
private static readonly START_BATCH_AFTER_COUNT = 50;
|
||||
|
||||
private totalNumberCompleted = 0;
|
||||
private batch: T[] = [];
|
||||
private batchSize = 0;
|
||||
private timeoutHandle: number;
|
||||
|
||||
constructor(private maxBatchSize: number, private cb: (items: T[]) => void) {
|
||||
}
|
||||
|
||||
addItem(item: T, size: number): void {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addItemToBatch(item, size);
|
||||
}
|
||||
|
||||
addItems(items: T[], size: number): void {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.maxBatchSize > 0) {
|
||||
this.addItemsToBatch(items, size);
|
||||
} else {
|
||||
this.cb(items);
|
||||
}
|
||||
}
|
||||
|
||||
private addItemToBatch(item: T, size: number): void {
|
||||
this.batch.push(item);
|
||||
this.batchSize += size;
|
||||
this.onUpdate();
|
||||
}
|
||||
|
||||
private addItemsToBatch(item: T[], size: number): void {
|
||||
this.batch = this.batch.concat(item);
|
||||
this.batchSize += size;
|
||||
this.onUpdate();
|
||||
}
|
||||
|
||||
private onUpdate(): void {
|
||||
if (this.totalNumberCompleted < BatchedCollector.START_BATCH_AFTER_COUNT) {
|
||||
// Flush because we aren't batching yet
|
||||
this.flush();
|
||||
} else if (this.batchSize >= this.maxBatchSize) {
|
||||
// Flush because the batch is full
|
||||
this.flush();
|
||||
} else if (!this.timeoutHandle) {
|
||||
// No timeout running, start a timeout to flush
|
||||
this.timeoutHandle = setTimeout(() => {
|
||||
this.flush();
|
||||
}, BatchedCollector.TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
if (this.batchSize) {
|
||||
this.totalNumberCompleted += this.batchSize;
|
||||
this.cb(this.batch);
|
||||
this.batch = [];
|
||||
this.batchSize = 0;
|
||||
|
||||
if (this.timeoutHandle) {
|
||||
clearTimeout(this.timeoutHandle);
|
||||
this.timeoutHandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextSearchEngine {
|
||||
|
||||
private activeCancellationTokens = new Set<CancellationTokenSource>();
|
||||
private collector: TextSearchResultsCollector;
|
||||
|
||||
private isLimitHit: boolean;
|
||||
private resultCount = 0;
|
||||
private isCanceled: boolean;
|
||||
|
||||
constructor(private pattern: IPatternInfo, private config: ISearchQuery, private provider: vscode.TextSearchProvider, private _extfs: typeof extfs) {
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.isCanceled = true;
|
||||
this.activeCancellationTokens.forEach(t => t.cancel());
|
||||
this.activeCancellationTokens = new Set();
|
||||
}
|
||||
|
||||
public search(onProgress: (matches: IFileMatch[]) => void): TPromise<{ limitHit: boolean }> {
|
||||
const folderQueries = this.config.folderQueries;
|
||||
|
||||
return new TPromise<{ limitHit: boolean }>((resolve, reject) => {
|
||||
this.collector = new TextSearchResultsCollector(onProgress);
|
||||
|
||||
const onResult = (match: vscode.TextSearchResult, folderIdx: number) => {
|
||||
if (this.isCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.resultCount >= this.config.maxResults) {
|
||||
this.isLimitHit = true;
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
if (!this.isLimitHit) {
|
||||
this.resultCount++;
|
||||
this.collector.add(match, folderIdx);
|
||||
}
|
||||
};
|
||||
|
||||
// For each root folder
|
||||
TPromise.join(folderQueries.map((fq, i) => {
|
||||
return this.searchInFolder(fq, r => onResult(r, i));
|
||||
})).then(() => {
|
||||
this.collector.flush();
|
||||
resolve({ limitHit: this.isLimitHit });
|
||||
}, (errs: Error[]) => {
|
||||
const errMsg = errs
|
||||
.map(err => toErrorMessage(err))
|
||||
.filter(msg => !!msg)[0];
|
||||
|
||||
reject(new Error(errMsg));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private searchInFolder(folderQuery: IFolderQuery<URI>, onResult: (result: vscode.TextSearchResult) => void): TPromise<void> {
|
||||
let cancellation = new CancellationTokenSource();
|
||||
return new TPromise((resolve, reject) => {
|
||||
|
||||
const queryTester = new QueryGlobTester(this.config, folderQuery);
|
||||
const testingPs = [];
|
||||
const progress = {
|
||||
report: (result: vscode.TextSearchResult) => {
|
||||
const hasSibling = folderQuery.folder.scheme === 'file' && glob.hasSiblingPromiseFn(() => {
|
||||
return this.readdir(path.dirname(result.uri.fsPath));
|
||||
});
|
||||
|
||||
const relativePath = path.relative(folderQuery.folder.fsPath, result.uri.fsPath);
|
||||
testingPs.push(
|
||||
queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling)
|
||||
.then(included => {
|
||||
if (included) {
|
||||
onResult(result);
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const searchOptions = this.getSearchOptionsForFolder(folderQuery);
|
||||
new TPromise(resolve => process.nextTick(resolve))
|
||||
.then(() => {
|
||||
this.activeCancellationTokens.add(cancellation);
|
||||
return this.provider.provideTextSearchResults(patternInfoToQuery(this.pattern), searchOptions, progress, cancellation.token);
|
||||
})
|
||||
.then(() => {
|
||||
this.activeCancellationTokens.delete(cancellation);
|
||||
return TPromise.join(testingPs);
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
cancellation.dispose();
|
||||
resolve(null);
|
||||
},
|
||||
err => {
|
||||
cancellation.dispose();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private readdir(dirname: string): TPromise<string[]> {
|
||||
return new TPromise((resolve, reject) => {
|
||||
this._extfs.readdir(dirname, (err, files) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(files);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getSearchOptionsForFolder(fq: IFolderQuery<URI>): vscode.TextSearchOptions {
|
||||
const includes = resolvePatternsForProvider(this.config.includePattern, fq.includePattern);
|
||||
const excludes = resolvePatternsForProvider(this.config.excludePattern, fq.excludePattern);
|
||||
|
||||
return {
|
||||
folder: URI.from(fq.folder),
|
||||
excludes,
|
||||
includes,
|
||||
useIgnoreFiles: !this.config.disregardIgnoreFiles,
|
||||
followSymlinks: !this.config.ignoreSymlinks,
|
||||
encoding: this.config.fileEncoding,
|
||||
maxFileSize: this.config.maxFileSize,
|
||||
maxResults: this.config.maxResults
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function patternInfoToQuery(patternInfo: IPatternInfo): vscode.TextSearchQuery {
|
||||
return <vscode.TextSearchQuery>{
|
||||
isCaseSensitive: patternInfo.isCaseSensitive || false,
|
||||
isRegExp: patternInfo.isRegExp || false,
|
||||
isWordMatch: patternInfo.isWordMatch || false,
|
||||
pattern: patternInfo.pattern
|
||||
};
|
||||
}
|
||||
|
||||
class FileSearchEngine {
|
||||
private filePattern: string;
|
||||
private includePattern: glob.ParsedExpression;
|
||||
private maxResults: number;
|
||||
private exists: boolean;
|
||||
private isLimitHit: boolean;
|
||||
private resultCount: number;
|
||||
private isCanceled: boolean;
|
||||
|
||||
private activeCancellationTokens: Set<CancellationTokenSource>;
|
||||
|
||||
private globalExcludePattern: glob.ParsedExpression;
|
||||
|
||||
constructor(private config: ISearchQuery, private provider: vscode.FileSearchProvider) {
|
||||
this.filePattern = config.filePattern;
|
||||
this.includePattern = config.includePattern && glob.parse(config.includePattern);
|
||||
this.maxResults = config.maxResults || null;
|
||||
this.exists = config.exists;
|
||||
this.resultCount = 0;
|
||||
this.isLimitHit = false;
|
||||
this.activeCancellationTokens = new Set<CancellationTokenSource>();
|
||||
|
||||
this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern);
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.isCanceled = true;
|
||||
this.activeCancellationTokens.forEach(t => t.cancel());
|
||||
this.activeCancellationTokens = new Set();
|
||||
}
|
||||
|
||||
public search(_onResult: (match: IInternalFileMatch) => void): TPromise<IInternalSearchComplete> {
|
||||
const folderQueries = this.config.folderQueries;
|
||||
|
||||
return new TPromise((resolve, reject) => {
|
||||
const onResult = (match: IInternalFileMatch) => {
|
||||
this.resultCount++;
|
||||
_onResult(match);
|
||||
};
|
||||
|
||||
// Support that the file pattern is a full path to a file that exists
|
||||
if (this.isCanceled) {
|
||||
return resolve({ limitHit: this.isLimitHit });
|
||||
}
|
||||
|
||||
// For each extra file
|
||||
if (this.config.extraFileResources) {
|
||||
this.config.extraFileResources
|
||||
.forEach(extraFile => {
|
||||
const extraFileStr = extraFile.toString(); // ?
|
||||
const basename = path.basename(extraFileStr);
|
||||
if (this.globalExcludePattern && this.globalExcludePattern(extraFileStr, basename)) {
|
||||
return; // excluded
|
||||
}
|
||||
|
||||
// File: Check for match on file pattern and include pattern
|
||||
this.matchFile(onResult, { base: extraFile, basename });
|
||||
});
|
||||
}
|
||||
|
||||
// For each root folder
|
||||
TPromise.join(folderQueries.map(fq => {
|
||||
return this.searchInFolder(fq, onResult);
|
||||
})).then(() => {
|
||||
resolve({ limitHit: this.isLimitHit });
|
||||
}, (errs: Error[]) => {
|
||||
const errMsg = errs
|
||||
.map(err => toErrorMessage(err))
|
||||
.filter(msg => !!msg)[0];
|
||||
|
||||
reject(new Error(errMsg));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private searchInFolder(fq: IFolderQuery<URI>, onResult: (match: IInternalFileMatch) => void): TPromise<void> {
|
||||
let cancellation = new CancellationTokenSource();
|
||||
return new TPromise((resolve, reject) => {
|
||||
const options = this.getSearchOptionsForFolder(fq);
|
||||
const tree = this.initDirectoryTree();
|
||||
|
||||
const queryTester = new QueryGlobTester(this.config, fq);
|
||||
const noSiblingsClauses = !queryTester.hasSiblingExcludeClauses();
|
||||
|
||||
new TPromise(_resolve => process.nextTick(_resolve))
|
||||
.then(() => {
|
||||
this.activeCancellationTokens.add(cancellation);
|
||||
|
||||
return this.provider.provideFileSearchResults(
|
||||
{
|
||||
pattern: this.config.filePattern || ''
|
||||
},
|
||||
options,
|
||||
cancellation.token);
|
||||
})
|
||||
.then(results => {
|
||||
if (this.isCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (results) {
|
||||
results.forEach(result => {
|
||||
const relativePath = path.relative(fq.folder.fsPath, result.fsPath);
|
||||
|
||||
if (noSiblingsClauses) {
|
||||
const basename = path.basename(result.fsPath);
|
||||
this.matchFile(onResult, { base: fq.folder, relativePath, basename });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Optimize siblings clauses with ripgrep here.
|
||||
this.addDirectoryEntries(tree, fq.folder, relativePath, onResult);
|
||||
});
|
||||
}
|
||||
|
||||
this.activeCancellationTokens.delete(cancellation);
|
||||
if (this.isCanceled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.matchDirectoryTree(tree, queryTester, onResult);
|
||||
return null;
|
||||
}).then(
|
||||
() => {
|
||||
cancellation.dispose();
|
||||
resolve(null);
|
||||
},
|
||||
err => {
|
||||
cancellation.dispose();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getSearchOptionsForFolder(fq: IFolderQuery<URI>): vscode.FileSearchOptions {
|
||||
const includes = resolvePatternsForProvider(this.config.includePattern, fq.includePattern);
|
||||
const excludes = resolvePatternsForProvider(this.config.excludePattern, fq.excludePattern);
|
||||
|
||||
return {
|
||||
folder: fq.folder,
|
||||
excludes,
|
||||
includes,
|
||||
useIgnoreFiles: !this.config.disregardIgnoreFiles,
|
||||
followSymlinks: !this.config.ignoreSymlinks,
|
||||
maxResults: this.config.maxResults
|
||||
};
|
||||
}
|
||||
|
||||
private initDirectoryTree(): IDirectoryTree {
|
||||
const tree: IDirectoryTree = {
|
||||
rootEntries: [],
|
||||
pathToEntries: Object.create(null)
|
||||
};
|
||||
tree.pathToEntries['.'] = tree.rootEntries;
|
||||
return tree;
|
||||
}
|
||||
|
||||
private addDirectoryEntries({ pathToEntries }: IDirectoryTree, base: URI, relativeFile: string, onResult: (result: IInternalFileMatch) => void) {
|
||||
// Support relative paths to files from a root resource (ignores excludes)
|
||||
if (relativeFile === this.filePattern) {
|
||||
const basename = path.basename(this.filePattern);
|
||||
this.matchFile(onResult, { base: base, relativePath: this.filePattern, basename });
|
||||
}
|
||||
|
||||
function add(relativePath: string) {
|
||||
const basename = path.basename(relativePath);
|
||||
const dirname = path.dirname(relativePath);
|
||||
let entries = pathToEntries[dirname];
|
||||
if (!entries) {
|
||||
entries = pathToEntries[dirname] = [];
|
||||
add(dirname);
|
||||
}
|
||||
entries.push({
|
||||
base,
|
||||
relativePath,
|
||||
basename
|
||||
});
|
||||
}
|
||||
|
||||
add(relativeFile);
|
||||
}
|
||||
|
||||
private matchDirectoryTree({ rootEntries, pathToEntries }: IDirectoryTree, queryTester: QueryGlobTester, onResult: (result: IInternalFileMatch) => void) {
|
||||
const self = this;
|
||||
const filePattern = this.filePattern;
|
||||
function matchDirectory(entries: IDirectoryEntry[]) {
|
||||
const hasSibling = glob.hasSiblingFn(() => entries.map(entry => entry.basename));
|
||||
for (let i = 0, n = entries.length; i < n; i++) {
|
||||
const entry = entries[i];
|
||||
const { relativePath, basename } = entry;
|
||||
|
||||
// Check exclude pattern
|
||||
// If the user searches for the exact file name, we adjust the glob matching
|
||||
// to ignore filtering by siblings because the user seems to know what she
|
||||
// is searching for and we want to include the result in that case anyway
|
||||
if (!queryTester.includedInQuerySync(relativePath, basename, filePattern !== basename ? hasSibling : undefined)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sub = pathToEntries[relativePath];
|
||||
if (sub) {
|
||||
matchDirectory(sub);
|
||||
} else {
|
||||
if (relativePath === filePattern) {
|
||||
continue; // ignore file if its path matches with the file pattern because that is already matched above
|
||||
}
|
||||
|
||||
self.matchFile(onResult, entry);
|
||||
}
|
||||
|
||||
if (self.isLimitHit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
matchDirectory(rootEntries);
|
||||
}
|
||||
|
||||
private matchFile(onResult: (result: IInternalFileMatch) => void, candidate: IInternalFileMatch): void {
|
||||
if (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename)) {
|
||||
if (this.exists || (this.maxResults && this.resultCount >= this.maxResults)) {
|
||||
this.isLimitHit = true;
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
if (!this.isLimitHit) {
|
||||
onResult(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IInternalSearchComplete {
|
||||
limitHit: boolean;
|
||||
}
|
||||
|
||||
class FileSearchManager {
|
||||
|
||||
private static readonly BATCH_SIZE = 512;
|
||||
|
||||
fileSearch(config: ISearchQuery, provider: vscode.FileSearchProvider, onBatch: (matches: IFileMatch[]) => void): TPromise<ISearchCompleteStats> {
|
||||
let searchP: TPromise;
|
||||
return new TPromise<ISearchCompleteStats>((c, e) => {
|
||||
const engine = new FileSearchEngine(config, provider);
|
||||
|
||||
const onInternalResult = (batch: IInternalFileMatch[]) => {
|
||||
onBatch(batch.map(m => this.rawMatchToSearchItem(m)));
|
||||
};
|
||||
|
||||
searchP = this.doSearch(engine, FileSearchManager.BATCH_SIZE, onInternalResult).then(
|
||||
result => {
|
||||
c({
|
||||
limitHit: result.limitHit
|
||||
});
|
||||
},
|
||||
e);
|
||||
}, () => {
|
||||
if (searchP) {
|
||||
searchP.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private rawMatchToSearchItem(match: IInternalFileMatch): IFileMatch {
|
||||
if (match.relativePath) {
|
||||
return {
|
||||
resource: resources.joinPath(match.base, match.relativePath)
|
||||
};
|
||||
} else {
|
||||
// extraFileResources
|
||||
return {
|
||||
resource: match.base
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private doSearch(engine: FileSearchEngine, batchSize: number, onResultBatch: (matches: IInternalFileMatch[]) => void): TPromise<IInternalSearchComplete> {
|
||||
return new TPromise((c, e) => {
|
||||
const _onResult = match => {
|
||||
if (match) {
|
||||
batch.push(match);
|
||||
if (batchSize > 0 && batch.length >= batchSize) {
|
||||
onResultBatch(batch);
|
||||
batch = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let batch: IInternalFileMatch[] = [];
|
||||
engine.search(_onResult).then(result => {
|
||||
if (batch.length) {
|
||||
onResultBatch(batch);
|
||||
}
|
||||
|
||||
c(result);
|
||||
}, error => {
|
||||
if (batch.length) {
|
||||
onResultBatch(batch);
|
||||
}
|
||||
|
||||
e(error);
|
||||
});
|
||||
}, () => {
|
||||
engine.cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* 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 { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes';
|
||||
@@ -23,7 +22,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem {
|
||||
private _color: string | ThemeColor;
|
||||
private _command: string;
|
||||
|
||||
private _timeoutHandle: number;
|
||||
private _timeoutHandle: any;
|
||||
private _proxy: MainThreadStatusBarShape;
|
||||
|
||||
private _extensionId: string;
|
||||
@@ -174,7 +173,7 @@ export class ExtHostStatusBar {
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
|
||||
|
||||
let d = this._statusMessage.setMessage(text);
|
||||
let handle: number;
|
||||
let handle: any;
|
||||
|
||||
if (typeof timeoutOrThenable === 'number') {
|
||||
handle = setTimeout(() => d.dispose(), timeoutOrThenable);
|
||||
|
||||
@@ -2,24 +2,36 @@
|
||||
* 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 { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { MainContext, MainThreadStorageShape, IMainContext } from './extHost.protocol';
|
||||
import { MainContext, MainThreadStorageShape, IMainContext, ExtHostStorageShape } from './extHost.protocol';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class ExtHostStorage {
|
||||
export interface IStorageChangeEvent {
|
||||
shared: boolean;
|
||||
key: string;
|
||||
value: object;
|
||||
}
|
||||
|
||||
export class ExtHostStorage implements ExtHostStorageShape {
|
||||
|
||||
private _proxy: MainThreadStorageShape;
|
||||
|
||||
private _onDidChangeStorage = new Emitter<IStorageChangeEvent>();
|
||||
readonly onDidChangeStorage = this._onDidChangeStorage.event;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadStorage);
|
||||
}
|
||||
|
||||
getValue<T>(shared: boolean, key: string, defaultValue?: T): TPromise<T> {
|
||||
getValue<T>(shared: boolean, key: string, defaultValue?: T): Thenable<T> {
|
||||
return this._proxy.$getValue<T>(shared, key).then(value => value || defaultValue);
|
||||
}
|
||||
|
||||
setValue(shared: boolean, key: string, value: any): TPromise<void> {
|
||||
setValue(shared: boolean, key: string, value: object): Thenable<void> {
|
||||
return this._proxy.$setValue(shared, key, value);
|
||||
}
|
||||
|
||||
$acceptValue(shared: boolean, key: string, value: object): void {
|
||||
this._onDidChangeStorage.fire({ shared, key, value });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import * as path from 'path';
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as Objects from 'vs/base/common/objects';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { asThenable } from 'vs/base/common/async';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { win32 } from 'vs/base/node/processes';
|
||||
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import * as tasks from 'vs/workbench/parts/tasks/common/tasks';
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
/*
|
||||
namespace ProblemPattern {
|
||||
@@ -235,14 +237,15 @@ namespace TaskPanelKind {
|
||||
namespace PresentationOptions {
|
||||
export function from(value: vscode.TaskPresentationOptions): tasks.PresentationOptions {
|
||||
if (value === void 0 || value === null) {
|
||||
return { reveal: tasks.RevealKind.Always, echo: true, focus: false, panel: tasks.PanelKind.Shared, showReuseMessage: true };
|
||||
return { reveal: tasks.RevealKind.Always, echo: true, focus: false, panel: tasks.PanelKind.Shared, showReuseMessage: true, clear: false };
|
||||
}
|
||||
return {
|
||||
reveal: TaskRevealKind.from(value.reveal),
|
||||
echo: value.echo === void 0 ? true : !!value.echo,
|
||||
focus: !!value.focus,
|
||||
panel: TaskPanelKind.from(value.panel),
|
||||
showReuseMessage: value.showReuseMessage === void 0 ? true : !!value.showReuseMessage
|
||||
showReuseMessage: value.showReuseMessage === void 0 ? true : !!value.showReuseMessage,
|
||||
clear: value.clear === void 0 ? false : !!value.clear,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -403,7 +406,8 @@ namespace Tasks {
|
||||
command: command,
|
||||
isBackground: !!task.isBackground,
|
||||
problemMatchers: task.problemMatchers.slice(),
|
||||
hasDefinedMatchers: (task as types.Task).hasDefinedMatchers
|
||||
hasDefinedMatchers: (task as types.Task).hasDefinedMatchers,
|
||||
runOptions: (<vscode.Task>task).runOptions ? (<vscode.Task>task).runOptions : { reevaluateOnRerun: true },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
@@ -608,7 +612,7 @@ namespace TaskDTO {
|
||||
if (typeof value.scope === 'number') {
|
||||
scope = value.scope;
|
||||
} else {
|
||||
scope = value.scope.uri.toJSON();
|
||||
scope = value.scope.uri;
|
||||
}
|
||||
}
|
||||
if (!definition || !scope) {
|
||||
@@ -629,7 +633,8 @@ namespace TaskDTO {
|
||||
group: group,
|
||||
presentationOptions: TaskPresentationOptionsDTO.from(value.presentationOptions),
|
||||
problemMatchers: value.problemMatchers,
|
||||
hasDefinedMatchers: (value as types.Task).hasDefinedMatchers
|
||||
hasDefinedMatchers: (value as types.Task).hasDefinedMatchers,
|
||||
runOptions: (<vscode.Task>value).runOptions ? (<vscode.Task>value).runOptions : { reevaluateOnRerun: true },
|
||||
};
|
||||
return result;
|
||||
}
|
||||
@@ -794,8 +799,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
} else {
|
||||
let dto = TaskDTO.from(task, extension);
|
||||
if (dto === void 0) {
|
||||
// {{ SQL CARBON EDIT }} - Add type assertion to fix build break
|
||||
return Promise.reject<vscode.TaskExecution>(new Error('Task is not valid'));
|
||||
return Promise.reject(new Error('Task is not valid'));
|
||||
}
|
||||
return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task));
|
||||
}
|
||||
@@ -807,7 +811,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return result;
|
||||
}
|
||||
|
||||
public terminateTask(execution: vscode.TaskExecution): TPromise<void> {
|
||||
public terminateTask(execution: vscode.TaskExecution): Thenable<void> {
|
||||
if (!(execution instanceof TaskExecutionImpl)) {
|
||||
throw new Error('No valid task execution provided');
|
||||
}
|
||||
@@ -864,12 +868,12 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $provideTasks(handle: number, validTypes: { [key: string]: boolean; }): TPromise<tasks.TaskSet> {
|
||||
public $provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<tasks.TaskSet> {
|
||||
let handler = this._handlers.get(handle);
|
||||
if (!handler) {
|
||||
return TPromise.wrapError<tasks.TaskSet>(new Error('no handler found'));
|
||||
return Promise.reject(new Error('no handler found'));
|
||||
}
|
||||
return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => {
|
||||
return asThenable(() => handler.provider.provideTasks(CancellationToken.None)).then(value => {
|
||||
let sanitized: vscode.Task[] = [];
|
||||
for (let task of value) {
|
||||
if (task.definition && validTypes[task.definition.type] === true) {
|
||||
@@ -888,9 +892,12 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} disable debug related method
|
||||
public $resolveVariables(uriComponents: UriComponents, variables: string[]): any {
|
||||
public $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Thenable<{ process?: string, variables: { [key: string]: string; } }> {
|
||||
// let uri: URI = URI.revive(uriComponents);
|
||||
// let result: { [key: string]: string; } = Object.create(null);
|
||||
// let result = {
|
||||
// process: undefined as string,
|
||||
// variables: Object.create(null)
|
||||
// };
|
||||
// let workspaceFolder = this._workspaceService.resolveWorkspaceFolder(uri);
|
||||
// let resolver = new ExtHostVariableResolverService(this._workspaceService, this._editorService, this._configurationService);
|
||||
// let ws: IWorkspaceFolder = {
|
||||
@@ -901,11 +908,25 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
// throw new Error('Not implemented');
|
||||
// }
|
||||
// };
|
||||
// for (let variable of variables) {
|
||||
// result[variable] = resolver.resolve(ws, variable);
|
||||
// for (let variable of toResolve.variables) {
|
||||
// result.variables[variable] = resolver.resolve(ws, variable);
|
||||
// }
|
||||
// return result;
|
||||
return undefined;
|
||||
// if (toResolve.process !== void 0) {
|
||||
// let paths: string[] | undefined = undefined;
|
||||
// if (toResolve.process.path !== void 0) {
|
||||
// paths = toResolve.process.path.split(path.delimiter);
|
||||
// for (let i = 0; i < paths.length; i++) {
|
||||
// paths[i] = resolver.resolve(ws, paths[i]);
|
||||
// }
|
||||
// }
|
||||
// result.process = win32.findExecutable(
|
||||
// resolver.resolve(ws, toResolve.process.name),
|
||||
// toResolve.process.cwd !== void 0 ? resolver.resolve(ws, toResolve.process.cwd) : undefined,
|
||||
// paths
|
||||
// );
|
||||
// }
|
||||
// return Promise.resolve(result);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private nextHandle(): number {
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
* 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 * as os from 'os';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/parts/terminal/node/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
@@ -14,6 +13,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY } from 'vs/workbench/parts/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/parts/terminal/node/terminalProcess';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
|
||||
@@ -77,7 +77,9 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
private readonly _onData: Emitter<string> = new Emitter<string>();
|
||||
public get onDidWriteData(): Event<string> {
|
||||
// Tell the main side to start sending data if it's not already
|
||||
this._proxy.$registerOnDataListener(this._id);
|
||||
this._idPromise.then(c => {
|
||||
this._proxy.$registerOnDataListener(this._id);
|
||||
});
|
||||
return this._onData && this._onData.event;
|
||||
}
|
||||
|
||||
@@ -113,6 +115,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public get processId(): Thenable<number> {
|
||||
return this._pidPromise;
|
||||
}
|
||||
@@ -226,6 +232,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
private _terminals: ExtHostTerminal[] = [];
|
||||
private _terminalProcesses: { [id: number]: TerminalProcess } = {};
|
||||
private _terminalRenderers: ExtHostTerminalRenderer[] = [];
|
||||
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
@@ -289,11 +296,11 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
|
||||
public $acceptTerminalProcessData(id: number, data: string): void {
|
||||
// TODO: Queue requests, currently the first 100ms of data may get missed
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
terminal._fireOnData(data);
|
||||
}
|
||||
this._getTerminalByIdEventually(id).then(terminal => {
|
||||
if (terminal) {
|
||||
terminal._fireOnData(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void {
|
||||
@@ -310,6 +317,13 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalTitleChange(id: number, name: string): void {
|
||||
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
|
||||
if (extHostTerminal) {
|
||||
extHostTerminal.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalClosed(id: number): void {
|
||||
const index = this._getTerminalObjectIndexById(this.terminals, id);
|
||||
if (index === null) {
|
||||
@@ -351,7 +365,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, cols: number, rows: number): void {
|
||||
public $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number): void {
|
||||
// TODO: This function duplicates a lot of TerminalProcessManager.createProcess, ideally
|
||||
// they would be merged into a single implementation.
|
||||
|
||||
@@ -369,10 +383,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
shellLaunchConfig.args = shellArgsConfigValue;
|
||||
}
|
||||
|
||||
// TODO: Base the cwd on the last active workspace root
|
||||
// const lastActiveWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot('file');
|
||||
// this.initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, lastActiveWorkspaceRootUri, this._configHelper);
|
||||
const initialCwd = os.homedir();
|
||||
// TODO: @daniel
|
||||
const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents);
|
||||
const initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, activeWorkspaceRootUri, terminalConfig.cwd);
|
||||
|
||||
// TODO: Pull in and resolve config settings
|
||||
// // Resolve env vars from config and shell
|
||||
@@ -415,8 +428,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptProcessShutdown(id: number): void {
|
||||
this._terminalProcesses[id].shutdown();
|
||||
public $acceptProcessShutdown(id: number, immediate: boolean): void {
|
||||
this._terminalProcesses[id].shutdown(immediate);
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
@@ -431,6 +444,17 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
|
||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||
if (!this._getTerminalPromises[id]) {
|
||||
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
|
||||
} else {
|
||||
this._getTerminalPromises[id].then(c => {
|
||||
return this._createGetTerminalPromise(id, retries);
|
||||
});
|
||||
}
|
||||
return this._getTerminalPromises[id];
|
||||
}
|
||||
|
||||
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||
return new Promise(c => {
|
||||
if (retries === 0) {
|
||||
c(undefined);
|
||||
@@ -443,9 +467,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
} else {
|
||||
// This should only be needed immediately after createTerminalRenderer is called as
|
||||
// the ExtHostTerminal has not yet been iniitalized
|
||||
setTimeout(() => {
|
||||
c(this._getTerminalByIdEventually(id, retries - 1));
|
||||
}, 200);
|
||||
timeout(200).then(() => c(this._getTerminalByIdEventually(id, retries - 1)));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -464,7 +486,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal | ExtHostTerminalRenderer>(array: T[], id: number): number {
|
||||
let index: number = null;
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
if (thisId === id) {
|
||||
|
||||
@@ -2,21 +2,18 @@
|
||||
* 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 { ok } from 'vs/base/common/assert';
|
||||
import { readonly, illegalArgument } from 'vs/base/common/errors';
|
||||
import { illegalArgument, readonly } from 'vs/base/common/errors';
|
||||
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import { Selection, Range, Position, EndOfLine, TextEditorRevealType, TextEditorLineNumbersStyle, SnippetString } from './extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as TypeConverters from './extHostTypeConverters';
|
||||
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';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, MainThreadTextEditorsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNumbersStyle, TextEditorRevealType } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class TextEditorDecorationType implements vscode.TextEditorDecorationType {
|
||||
|
||||
@@ -28,7 +25,7 @@ export class TextEditorDecorationType implements vscode.TextEditorDecorationType
|
||||
constructor(proxy: MainThreadTextEditorsShape, options: vscode.DecorationRenderOptions) {
|
||||
this.key = TextEditorDecorationType._Keys.nextId();
|
||||
this._proxy = proxy;
|
||||
this._proxy.$registerTextEditorDecorationType(this.key, <any>/* URI vs Uri */ options);
|
||||
this._proxy.$registerTextEditorDecorationType(this.key, TypeConverters.DecorationRenderOptions.from(options));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -79,7 +76,7 @@ export class TextEditorEdit {
|
||||
}
|
||||
|
||||
replace(location: Position | Range | Selection, value: string): void {
|
||||
let range: Range = null;
|
||||
let range: Range | null = null;
|
||||
|
||||
if (location instanceof Position) {
|
||||
range = new Range(location, location);
|
||||
@@ -97,7 +94,7 @@ export class TextEditorEdit {
|
||||
}
|
||||
|
||||
delete(location: Range | Selection): void {
|
||||
let range: Range = null;
|
||||
let range: Range | null = null;
|
||||
|
||||
if (location instanceof Range) {
|
||||
range = location;
|
||||
@@ -322,6 +319,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
private _visibleRanges: Range[];
|
||||
private _viewColumn: vscode.ViewColumn;
|
||||
private _disposed: boolean = false;
|
||||
private _hasDecorationsForKey: { [key: string]: boolean; };
|
||||
|
||||
get id(): string { return this._id; }
|
||||
|
||||
@@ -337,6 +335,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
this._options = new ExtHostTextEditorOptions(this._proxy, this._id, options);
|
||||
this._visibleRanges = visibleRanges;
|
||||
this._viewColumn = viewColumn;
|
||||
this._hasDecorationsForKey = Object.create(null);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -436,6 +435,16 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
}
|
||||
|
||||
setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
|
||||
const willBeEmpty = (ranges.length === 0);
|
||||
if (willBeEmpty && !this._hasDecorationsForKey[decorationType.key]) {
|
||||
// avoid no-op call to the renderer
|
||||
return;
|
||||
}
|
||||
if (willBeEmpty) {
|
||||
delete this._hasDecorationsForKey[decorationType.key];
|
||||
} else {
|
||||
this._hasDecorationsForKey[decorationType.key] = true;
|
||||
}
|
||||
this._runOnProxy(
|
||||
() => {
|
||||
if (TypeConverters.isDecorationOptionsArr(ranges)) {
|
||||
@@ -473,7 +482,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
);
|
||||
}
|
||||
|
||||
private _trySetSelection(): TPromise<vscode.TextEditor> {
|
||||
private _trySetSelection(): Thenable<vscode.TextEditor> {
|
||||
let selection = this._selections.map(TypeConverters.Selection.from);
|
||||
return this._runOnProxy(() => this._proxy.$trySetSelections(this._id, selection));
|
||||
}
|
||||
@@ -487,19 +496,19 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
|
||||
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
|
||||
if (this._disposed) {
|
||||
return TPromise.wrapError<boolean>(new Error('TextEditor#edit not possible on closed editors'));
|
||||
return Promise.reject(new Error('TextEditor#edit not possible on closed editors'));
|
||||
}
|
||||
let edit = new TextEditorEdit(this._documentData.document, options);
|
||||
callback(edit);
|
||||
return this._applyEdit(edit);
|
||||
}
|
||||
|
||||
private _applyEdit(editBuilder: TextEditorEdit): TPromise<boolean> {
|
||||
private _applyEdit(editBuilder: TextEditorEdit): Thenable<boolean> {
|
||||
let editData = editBuilder.finalize();
|
||||
|
||||
// return when there is nothing to do
|
||||
if (editData.edits.length === 0 && !editData.setEndOfLine) {
|
||||
return TPromise.wrap(true);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
// check that the edits are not overlapping (i.e. illegal)
|
||||
@@ -526,7 +535,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
|
||||
if (nextRangeStart.isBefore(rangeEnd)) {
|
||||
// overlapping ranges
|
||||
return TPromise.wrapError<boolean>(
|
||||
return Promise.reject(
|
||||
new Error('Overlapping ranges are not allowed!')
|
||||
);
|
||||
}
|
||||
@@ -550,7 +559,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
|
||||
insertSnippet(snippet: SnippetString, where?: Position | Position[] | Range | Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Thenable<boolean> {
|
||||
if (this._disposed) {
|
||||
return TPromise.wrapError<boolean>(new Error('TextEditor#insertSnippet not possible on closed editors'));
|
||||
return Promise.reject(new Error('TextEditor#insertSnippet not possible on closed editors'));
|
||||
}
|
||||
let ranges: IRange[];
|
||||
|
||||
@@ -580,10 +589,10 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
|
||||
// ---- util
|
||||
|
||||
private _runOnProxy(callback: () => TPromise<any>): TPromise<ExtHostTextEditor> {
|
||||
private _runOnProxy(callback: () => Thenable<any>): Thenable<ExtHostTextEditor> {
|
||||
if (this._disposed) {
|
||||
console.warn('TextEditor is closed/disposed');
|
||||
return TPromise.as(undefined);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return callback().then(() => this, err => {
|
||||
if (!(err instanceof Error && err.name === 'DISPOSED')) {
|
||||
@@ -594,7 +603,7 @@ export class ExtHostTextEditor implements vscode.TextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
function warnOnError(promise: TPromise<any>): void {
|
||||
function warnOnError(promise: Thenable<any>): void {
|
||||
promise.then(null, (err) => {
|
||||
console.warn(err);
|
||||
});
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
* 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 { Event, Emitter } from 'vs/base/common/event';
|
||||
import { toThenable } from 'vs/base/common/async';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { TextEditorSelectionChangeKind } from './extHostTypes';
|
||||
import * as TypeConverters from './extHostTypeConverters';
|
||||
import { TextEditorDecorationType, ExtHostTextEditor } from './extHostTextEditor';
|
||||
import { ExtHostDocumentsAndEditors } from './extHostDocumentsAndEditors';
|
||||
import { MainContext, MainThreadTextEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IMainContext, IEditorPropertiesChangeData } from './extHost.protocol';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/node/extHostTextEditor';
|
||||
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/node/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
@@ -53,10 +50,10 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
return this._extHostDocumentsAndEditors.allEditors();
|
||||
}
|
||||
|
||||
showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): TPromise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, options: { column: vscode.ViewColumn, preserveFocus: boolean, pinned: boolean }): TPromise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): TPromise<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): TPromise<vscode.TextEditor> {
|
||||
showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): Thenable<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, options: { column: vscode.ViewColumn, preserveFocus: boolean, pinned: boolean }): Thenable<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor>;
|
||||
showTextDocument(document: vscode.TextDocument, columnOrOptions: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
|
||||
let options: ITextDocumentShowOptions;
|
||||
if (typeof columnOrOptions === 'number') {
|
||||
options = {
|
||||
@@ -90,7 +87,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
return new TextEditorDecorationType(this._proxy, options);
|
||||
}
|
||||
|
||||
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): TPromise<boolean> {
|
||||
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): Thenable<boolean> {
|
||||
const dto = TypeConverters.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
|
||||
return this._proxy.$tryApplyWorkspaceEdit(dto);
|
||||
}
|
||||
@@ -150,6 +147,6 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
}
|
||||
|
||||
getDiffInformation(id: string): Thenable<vscode.LineChange[]> {
|
||||
return toThenable(this._proxy.$getDiffInformation(id));
|
||||
return Promise.resolve(this._proxy.$getDiffInformation(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,50 @@
|
||||
* 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 { localize } from 'vs/nls';
|
||||
import * as vscode from 'vscode';
|
||||
import { basename } from 'vs/base/common/paths';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
|
||||
import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views';
|
||||
import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel, IRevealOptions } 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';
|
||||
import { asThenable } from 'vs/base/common/async';
|
||||
import { TreeItemCollapsibleState, ThemeIcon, MarkdownString } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { isUndefinedOrNull, isString } from 'vs/base/common/types';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtensionDescription, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import * as typeConvert from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import * as sqlops from 'sqlops';
|
||||
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
|
||||
export type TreeItemHandle = string;
|
||||
|
||||
function toTreeItemLabel(label: any, extension: IExtensionDescription): ITreeItemLabel {
|
||||
if (isString(label)) {
|
||||
return { label };
|
||||
}
|
||||
|
||||
if (label
|
||||
&& typeof label === 'object'
|
||||
&& typeof label.label === 'string') {
|
||||
checkProposedApiEnabled(extension);
|
||||
let highlights: [number, number][] = void 0;
|
||||
if (Array.isArray(label.highlights)) {
|
||||
highlights = (<[number, number][]>label.highlights).filter((highlight => highlight.length === 2 && typeof highlight[0] === 'number' && typeof highlight[1] === 'number'));
|
||||
highlights = highlights.length ? highlights : void 0;
|
||||
}
|
||||
return { label: label.label, highlights };
|
||||
}
|
||||
|
||||
return void 0;
|
||||
}
|
||||
|
||||
|
||||
export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
|
||||
private treeViews: Map<string, ExtHostTreeView<any>> = new Map<string, ExtHostTreeView<any>>();
|
||||
@@ -42,16 +65,17 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
});
|
||||
}
|
||||
|
||||
registerTreeDataProvider<T>(id: string, treeDataProvider: vscode.TreeDataProvider<T>): vscode.Disposable {
|
||||
const treeView = this.createTreeView(id, { treeDataProvider });
|
||||
registerTreeDataProvider<T>(id: string, treeDataProvider: vscode.TreeDataProvider<T>, extension: IExtensionDescription): vscode.Disposable {
|
||||
const treeView = this.createTreeView(id, { treeDataProvider }, extension);
|
||||
return { dispose: () => treeView.dispose() };
|
||||
}
|
||||
|
||||
createTreeView<T>(viewId: string, options: { treeDataProvider: vscode.TreeDataProvider<T> }): vscode.TreeView<T> {
|
||||
createTreeView<T>(viewId: string, options: vscode.TreeViewOptions<T>, extension: IExtensionDescription): vscode.TreeView<T> {
|
||||
if (!options || !options.treeDataProvider) {
|
||||
throw new Error('Options with treeDataProvider is mandatory');
|
||||
}
|
||||
const treeView = this.createExtHostTreeViewer(viewId, options.treeDataProvider);
|
||||
|
||||
const treeView = this.createExtHostTreeView(viewId, options, extension);
|
||||
return {
|
||||
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
|
||||
get onDidExpandElement() { return treeView.onDidExpandElement; },
|
||||
@@ -59,7 +83,9 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
get onDidChangeSelection() { return treeView.onDidChangeSelection; },
|
||||
get visible() { return treeView.visible; },
|
||||
get onDidChangeVisibility() { return treeView.onDidChangeVisibility; },
|
||||
reveal: (element: T, options?: { select?: boolean, focus?: boolean }): Thenable<void> => {
|
||||
get message() { return treeView.message; },
|
||||
set message(message: string | MarkdownString) { checkProposedApiEnabled(extension); treeView.message = message; },
|
||||
reveal: (element: T, options?: IRevealOptions): Thenable<void> => {
|
||||
return treeView.reveal(element, options);
|
||||
},
|
||||
dispose: () => {
|
||||
@@ -69,10 +95,10 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
};
|
||||
}
|
||||
|
||||
$getChildren(treeViewId: string, treeItemHandle?: string): TPromise<ITreeItem[]> {
|
||||
$getChildren(treeViewId: string, treeItemHandle?: string): Thenable<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 Promise.reject(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
|
||||
}
|
||||
return treeView.getChildren(treeItemHandle);
|
||||
}
|
||||
@@ -101,8 +127,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
|
||||
treeView.setVisible(isVisible);
|
||||
}
|
||||
|
||||
private createExtHostTreeViewer<T>(id: string, dataProvider: vscode.TreeDataProvider<T>): ExtHostTreeView<T> {
|
||||
const treeView = new ExtHostTreeView<T>(id, dataProvider, this._proxy, this.commands.converter, this.logService);
|
||||
private createExtHostTreeView<T>(id: string, options: vscode.TreeViewOptions<T>, extension: IExtensionDescription): ExtHostTreeView<T> {
|
||||
const treeView = new ExtHostTreeView<T>(id, options, this._proxy, this.commands.converter, this.logService, extension);
|
||||
this.treeViews.set(id, treeView);
|
||||
return treeView;
|
||||
}
|
||||
@@ -126,7 +152,9 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
private static LABEL_HANDLE_PREFIX = '0';
|
||||
private static ID_HANDLE_PREFIX = '1';
|
||||
|
||||
private roots: TreeNode[] = null;
|
||||
private readonly dataProvider: vscode.TreeDataProvider<T>;
|
||||
|
||||
private roots: TreeNode[] | null = null;
|
||||
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
|
||||
@@ -149,40 +177,41 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
private _onDidChangeVisibility: Emitter<vscode.TreeViewVisibilityChangeEvent> = this._register(new Emitter<vscode.TreeViewVisibilityChangeEvent>());
|
||||
readonly onDidChangeVisibility: Event<vscode.TreeViewVisibilityChangeEvent> = this._onDidChangeVisibility.event;
|
||||
|
||||
private refreshPromise: TPromise<void> = TPromise.as(null);
|
||||
private refreshPromise: Promise<void> = Promise.resolve(null);
|
||||
|
||||
constructor(private viewId: string, private dataProvider: vscode.TreeDataProvider<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService) {
|
||||
constructor(private viewId: string, options: vscode.TreeViewOptions<T>, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) {
|
||||
super();
|
||||
this.dataProvider = options.treeDataProvider;
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (this.proxy) {
|
||||
this.proxy.$registerTreeViewDataProvider(viewId);
|
||||
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll });
|
||||
}
|
||||
if (this.dataProvider.onDidChangeTreeData) {
|
||||
let refreshingPromise, promiseCallback;
|
||||
this._register(debounceEvent<T, T[]>(this.dataProvider.onDidChangeTreeData, (last, current) => {
|
||||
if (!refreshingPromise) {
|
||||
// New refresh has started
|
||||
refreshingPromise = new TPromise((c, e) => promiseCallback = c);
|
||||
refreshingPromise = new Promise(c => promiseCallback = c);
|
||||
this.refreshPromise = this.refreshPromise.then(() => refreshingPromise);
|
||||
}
|
||||
return last ? [...last, current] : [current];
|
||||
}, 200)(elements => {
|
||||
const _promiseCallback = promiseCallback;
|
||||
refreshingPromise = null;
|
||||
this.refresh(elements);
|
||||
this.refresh(elements).then(() => _promiseCallback());
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
getChildren(parentHandle?: TreeItemHandle): TPromise<ITreeItem[]> {
|
||||
getChildren(parentHandle?: TreeItemHandle): Thenable<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 Promise.resolve([]);
|
||||
}
|
||||
|
||||
const childrenNodes = this.getChildrenNodes(parentHandle); // Get it from cache
|
||||
return (childrenNodes ? TPromise.as(childrenNodes) : this.fetchChildrenNodes(parentElement))
|
||||
return (childrenNodes ? Promise.resolve(childrenNodes) : this.fetchChildrenNodes(parentElement))
|
||||
.then(nodes => nodes.map(n => n.item));
|
||||
}
|
||||
|
||||
@@ -190,18 +219,29 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return this.elements.get(treeItemHandle);
|
||||
}
|
||||
|
||||
reveal(element: T, options?: { select?: boolean, focus?: boolean }): TPromise<void> {
|
||||
reveal(element: T, options?: IRevealOptions): Promise<void> {
|
||||
options = options ? options : { select: true, focus: false };
|
||||
const select = isUndefinedOrNull(options.select) ? true : options.select;
|
||||
const focus = isUndefinedOrNull(options.focus) ? false : options.focus;
|
||||
const expand = isUndefinedOrNull(options.expand) ? false : options.expand;
|
||||
|
||||
if (typeof this.dataProvider.getParent !== 'function') {
|
||||
return TPromise.wrapError(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`));
|
||||
return Promise.reject(new Error(`Required registered TreeDataProvider to implement 'getParent' method to access 'reveal' method`));
|
||||
}
|
||||
return this.refreshPromise
|
||||
.then(() => 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), { select, focus })), error => this.logService.error(error));
|
||||
.then(treeNode => this.proxy.$reveal(this.viewId, treeNode.item, parentChain.map(p => p.item), { select, focus, expand })), error => this.logService.error(error));
|
||||
}
|
||||
|
||||
private _message: string | MarkdownString;
|
||||
get message(): string | MarkdownString {
|
||||
return this._message;
|
||||
}
|
||||
|
||||
set message(message: string | MarkdownString) {
|
||||
this._message = message;
|
||||
this.proxy.$setMessage(this.viewId, typeConvert.MarkdownString.fromStrict(this._message));
|
||||
}
|
||||
|
||||
setExpanded(treeItemHandle: TreeItemHandle, expanded: boolean): void {
|
||||
@@ -230,11 +270,11 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected resolveUnknownParentChain(element: T): TPromise<TreeNode[]> {
|
||||
protected resolveUnknownParentChain(element: T): Thenable<TreeNode[]> {
|
||||
return this.resolveParent(element)
|
||||
.then((parent) => {
|
||||
if (!parent) {
|
||||
return TPromise.as([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return this.resolveUnknownParentChain(parent)
|
||||
.then(result => this.resolveTreeNode(parent, result[result.length - 1])
|
||||
@@ -245,17 +285,21 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private resolveParent(element: T): TPromise<T> {
|
||||
private resolveParent(element: T): Thenable<T> {
|
||||
const node = this.nodes.get(element);
|
||||
if (node) {
|
||||
return TPromise.as(node.parent ? this.elements.get(node.parent.item.handle) : null);
|
||||
return Promise.resolve(node.parent ? this.elements.get(node.parent.item.handle) : null);
|
||||
}
|
||||
return asWinJsPromise(() => this.dataProvider.getParent(element));
|
||||
return asThenable(() => this.dataProvider.getParent(element));
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected resolveTreeNode(element: T, parent?: TreeNode): TPromise<TreeNode> {
|
||||
return asWinJsPromise(() => this.dataProvider.getTreeItem(element))
|
||||
protected resolveTreeNode(element: T, parent?: TreeNode): Thenable<TreeNode> {
|
||||
const node = this.nodes.get(element);
|
||||
if (node) {
|
||||
return Promise.resolve(node);
|
||||
}
|
||||
return asThenable(() => this.dataProvider.getTreeItem(element))
|
||||
.then(extTreeItem => this.createHandle(element, extTreeItem, parent, true))
|
||||
.then(handle => this.getChildren(parent ? parent.item.handle : null)
|
||||
.then(() => {
|
||||
@@ -263,7 +307,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
if (cachedElement) {
|
||||
const node = this.nodes.get(cachedElement);
|
||||
if (node) {
|
||||
return TPromise.as(node);
|
||||
return Promise.resolve(node);
|
||||
}
|
||||
}
|
||||
throw new Error(`Cannot resolve tree item for element ${handle}`);
|
||||
@@ -284,32 +328,32 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return this.roots;
|
||||
}
|
||||
|
||||
private fetchChildrenNodes(parentElement?: T): TPromise<TreeNode[]> {
|
||||
private fetchChildrenNodes(parentElement?: T): Thenable<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(
|
||||
return asThenable(() => this.dataProvider.getChildren(parentElement))
|
||||
.then(elements => Promise.all(
|
||||
(elements || [])
|
||||
.filter(element => !!element)
|
||||
.map(element => asWinJsPromise(() => this.dataProvider.getTreeItem(element))
|
||||
.map(element => asThenable(() => this.dataProvider.getTreeItem(element))
|
||||
.then(extTreeItem => extTreeItem ? this.createAndRegisterTreeNode(element, extTreeItem, parentNode) : null))))
|
||||
.then(nodes => nodes.filter(n => !!n));
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
private refresh(elements: T[]): void {
|
||||
private refresh(elements: T[]): Thenable<void> {
|
||||
const hasRoot = elements.some(element => !element);
|
||||
if (hasRoot) {
|
||||
this.clearAll(); // clear cache
|
||||
this.proxy.$refresh(this.viewId);
|
||||
return this.proxy.$refresh(this.viewId);
|
||||
} else {
|
||||
const handlesToRefresh = this.getHandlesToRefresh(elements);
|
||||
if (handlesToRefresh.length) {
|
||||
this.refreshHandles(handlesToRefresh);
|
||||
return this.refreshHandles(handlesToRefresh);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -344,9 +388,9 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected refreshHandles(itemHandles: TreeItemHandle[]): TPromise<void> {
|
||||
protected refreshHandles(itemHandles: TreeItemHandle[]): Promise<void> {
|
||||
const itemsToRefresh: { [treeItemHandle: string]: ITreeItem } = {};
|
||||
return TPromise.join(itemHandles.map(treeItemHandle =>
|
||||
return Promise.all(itemHandles.map(treeItemHandle =>
|
||||
this.refreshNode(treeItemHandle)
|
||||
.then(node => {
|
||||
if (node) {
|
||||
@@ -357,11 +401,11 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected refreshNode(treeItemHandle: TreeItemHandle): TPromise<TreeNode> {
|
||||
protected refreshNode(treeItemHandle: TreeItemHandle): Thenable<TreeNode> {
|
||||
const extElement = this.getExtensionElement(treeItemHandle);
|
||||
const existing = this.nodes.get(extElement);
|
||||
this.clearChildren(extElement); // clear children cache
|
||||
return asWinJsPromise(() => this.dataProvider.getTreeItem(extElement))
|
||||
return asThenable(() => this.dataProvider.getTreeItem(extElement))
|
||||
.then(extTreeItem => {
|
||||
if (extTreeItem) {
|
||||
const newNode = this.createTreeNode(extElement, extTreeItem, existing.parent);
|
||||
@@ -392,14 +436,15 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
protected createTreeItem(element: T, extensionTreeItem: vscode.TreeItem, parent?: TreeNode): ITreeItem {
|
||||
protected createTreeItem(element: T, extensionTreeItem: sqlops.TreeItem, parent?: TreeNode): sqlITreeItem {
|
||||
|
||||
const handle = this.createHandle(element, extensionTreeItem, parent);
|
||||
const icon = this.getLightIconPath(extensionTreeItem);
|
||||
const item = {
|
||||
handle,
|
||||
parentHandle: parent ? parent.item.handle : void 0,
|
||||
label: extensionTreeItem.label,
|
||||
label: toTreeItemLabel(extensionTreeItem.label, this.extension),
|
||||
description: extensionTreeItem.description,
|
||||
resourceUri: extensionTreeItem.resourceUri,
|
||||
tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : void 0,
|
||||
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
|
||||
@@ -407,7 +452,10 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
icon,
|
||||
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
|
||||
themeIcon: extensionTreeItem.iconPath instanceof ThemeIcon ? { id: extensionTreeItem.iconPath.id } : void 0,
|
||||
collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState
|
||||
collapsibleState: isUndefinedOrNull(extensionTreeItem.collapsibleState) ? TreeItemCollapsibleState.None : extensionTreeItem.collapsibleState,
|
||||
// {{SQL CARBON EDIT}}
|
||||
payload: extensionTreeItem.payload,
|
||||
childProvider: extensionTreeItem.childProvider
|
||||
};
|
||||
|
||||
return item;
|
||||
@@ -418,8 +466,9 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return `${ExtHostTreeView.ID_HANDLE_PREFIX}/${id}`;
|
||||
}
|
||||
|
||||
const treeItemLabel = toTreeItemLabel(label, this.extension);
|
||||
const prefix: string = parent ? parent.item.handle : ExtHostTreeView.LABEL_HANDLE_PREFIX;
|
||||
let elementId = label ? label : resourceUri ? basename(resourceUri.path) : '';
|
||||
let elementId = treeItemLabel ? treeItemLabel.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) || []);
|
||||
@@ -440,7 +489,7 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return handle;
|
||||
}
|
||||
|
||||
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
|
||||
private getLightIconPath(extensionTreeItem: vscode.TreeItem): URI {
|
||||
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon)) {
|
||||
if (typeof extensionTreeItem.iconPath === 'string'
|
||||
|| extensionTreeItem.iconPath instanceof URI) {
|
||||
@@ -451,18 +500,18 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
|
||||
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): URI {
|
||||
if (extensionTreeItem.iconPath && !(extensionTreeItem.iconPath instanceof ThemeIcon) && extensionTreeItem.iconPath['dark']) {
|
||||
return this.getIconPath(extensionTreeItem.iconPath['dark']);
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
private getIconPath(iconPath: string | URI): string {
|
||||
private getIconPath(iconPath: string | URI): URI {
|
||||
if (iconPath instanceof URI) {
|
||||
return iconPath.toString();
|
||||
return iconPath;
|
||||
}
|
||||
return URI.file(iconPath).toString();
|
||||
return URI.file(iconPath);
|
||||
}
|
||||
|
||||
private addNodeToCache(element: T, node: TreeNode): void {
|
||||
@@ -545,4 +594,4 @@ export class ExtHostTreeView<T> extends Disposable {
|
||||
dispose() {
|
||||
this.clearAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,29 +2,32 @@
|
||||
* 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 modes from 'vs/editor/common/modes';
|
||||
import * as types from './extHostTypes';
|
||||
import * as search from 'vs/workbench/parts/search/common/search';
|
||||
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
|
||||
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLineSequence } from 'vs/editor/common/model';
|
||||
import { IDecorationOptions, IThemeDecorationRenderOptions, IDecorationRenderOptions, IContentDecorationRenderOptions } from 'vs/editor/common/editorCommon';
|
||||
import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import * as vscode from 'vscode';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ProgressLocation as MainProgressLocation } from 'vs/workbench/services/progress/common/progress';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import * as htmlContent from 'vs/base/common/htmlContent';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
|
||||
import { WorkspaceEditDto, ResourceTextEditDto, ResourceFileEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { isString, isNumber } from 'vs/base/common/types';
|
||||
import * as marked from 'vs/base/common/marked/marked';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
import { cloneAndChange } from 'vs/base/common/objects';
|
||||
import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
|
||||
|
||||
export interface PositionLike {
|
||||
line: number;
|
||||
@@ -43,14 +46,14 @@ export interface SelectionLike extends RangeLike {
|
||||
export namespace Selection {
|
||||
|
||||
export function to(selection: ISelection): types.Selection {
|
||||
let { selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn } = selection;
|
||||
let start = new types.Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
|
||||
let end = new types.Position(positionLineNumber - 1, positionColumn - 1);
|
||||
const { selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn } = selection;
|
||||
const start = new types.Position(selectionStartLineNumber - 1, selectionStartColumn - 1);
|
||||
const end = new types.Position(positionLineNumber - 1, positionColumn - 1);
|
||||
return new types.Selection(start, end);
|
||||
}
|
||||
|
||||
export function from(selection: SelectionLike): ISelection {
|
||||
let { anchor, active } = selection;
|
||||
const { anchor, active } = selection;
|
||||
return {
|
||||
selectionStartLineNumber: anchor.line + 1,
|
||||
selectionStartColumn: anchor.character + 1,
|
||||
@@ -65,7 +68,7 @@ export namespace Range {
|
||||
if (!range) {
|
||||
return undefined;
|
||||
}
|
||||
let { start, end } = range;
|
||||
const { start, end } = range;
|
||||
return {
|
||||
startLineNumber: start.line + 1,
|
||||
startColumn: start.character + 1,
|
||||
@@ -78,7 +81,7 @@ export namespace Range {
|
||||
if (!range) {
|
||||
return undefined;
|
||||
}
|
||||
let { startLineNumber, startColumn, endLineNumber, endColumn } = range;
|
||||
const { startLineNumber, startColumn, endLineNumber, endColumn } = range;
|
||||
return new types.Range(startLineNumber - 1, startColumn - 1, endLineNumber - 1, endColumn - 1);
|
||||
}
|
||||
}
|
||||
@@ -108,7 +111,7 @@ export namespace Diagnostic {
|
||||
...Range.from(value.range),
|
||||
message: value.message,
|
||||
source: value.source,
|
||||
code: String(value.code),
|
||||
code: isString(value.code) || isNumber(value.code) ? String(value.code) : void 0,
|
||||
severity: DiagnosticSeverity.from(value.severity),
|
||||
relatedInformation: value.relatedInformation && value.relatedInformation.map(DiagnosticRelatedInformation.from),
|
||||
tags: Array.isArray(value.tags) ? value.tags.map(DiagnosticTag.from) : undefined,
|
||||
@@ -210,17 +213,61 @@ export namespace MarkdownString {
|
||||
}
|
||||
|
||||
export function from(markup: vscode.MarkdownString | vscode.MarkedString): htmlContent.IMarkdownString {
|
||||
let res: htmlContent.IMarkdownString;
|
||||
if (isCodeblock(markup)) {
|
||||
const { language, value } = markup;
|
||||
return { value: '```' + language + '\n' + value + '\n```\n' };
|
||||
res = { value: '```' + language + '\n' + value + '\n```\n' };
|
||||
} else if (htmlContent.isMarkdownString(markup)) {
|
||||
return markup;
|
||||
res = markup;
|
||||
} else if (typeof markup === 'string') {
|
||||
return { value: <string>markup };
|
||||
res = { value: <string>markup };
|
||||
} else {
|
||||
return { value: '' };
|
||||
res = { value: '' };
|
||||
}
|
||||
|
||||
// extract uris into a separate object
|
||||
res.uris = Object.create(null);
|
||||
let renderer = new marked.Renderer();
|
||||
renderer.image = renderer.link = (href: string): string => {
|
||||
try {
|
||||
let uri = URI.parse(href, true);
|
||||
uri = uri.with({ query: _uriMassage(uri.query, res.uris) });
|
||||
res.uris[href] = uri;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return '';
|
||||
};
|
||||
marked(res.value, { renderer });
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function _uriMassage(part: string, bucket: { [n: string]: UriComponents }): string {
|
||||
if (!part) {
|
||||
return part;
|
||||
}
|
||||
let data: any;
|
||||
try {
|
||||
data = parse(decodeURIComponent(part));
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
if (!data) {
|
||||
return part;
|
||||
}
|
||||
data = cloneAndChange(data, value => {
|
||||
if (value instanceof URI) {
|
||||
let key = `__uri_${Math.random().toString(16).slice(2, 8)}`;
|
||||
bucket[key] = value;
|
||||
return key;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
return encodeURIComponent(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function to(value: htmlContent.IMarkdownString): vscode.MarkdownString {
|
||||
const ret = new htmlContent.MarkdownString(value.value);
|
||||
ret.isTrusted = value.isTrusted;
|
||||
@@ -253,21 +300,142 @@ export function fromRangeOrRangeWithMessage(ranges: vscode.Range[] | vscode.Deco
|
||||
}
|
||||
}
|
||||
|
||||
export const TextEdit = {
|
||||
function pathOrURIToURI(value: string | URI): URI {
|
||||
if (typeof value === 'undefined') {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return URI.file(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
from(edit: vscode.TextEdit): modes.TextEdit {
|
||||
export namespace ThemableDecorationAttachmentRenderOptions {
|
||||
export function from(options: vscode.ThemableDecorationAttachmentRenderOptions): IContentDecorationRenderOptions {
|
||||
if (typeof options === 'undefined') {
|
||||
return options;
|
||||
}
|
||||
return {
|
||||
contentText: options.contentText,
|
||||
contentIconPath: pathOrURIToURI(options.contentIconPath),
|
||||
border: options.border,
|
||||
borderColor: <string | types.ThemeColor>options.borderColor,
|
||||
fontStyle: options.fontStyle,
|
||||
fontWeight: options.fontWeight,
|
||||
textDecoration: options.textDecoration,
|
||||
color: <string | types.ThemeColor>options.color,
|
||||
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
|
||||
margin: options.margin,
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ThemableDecorationRenderOptions {
|
||||
export function from(options: vscode.ThemableDecorationRenderOptions): IThemeDecorationRenderOptions {
|
||||
if (typeof options === 'undefined') {
|
||||
return options;
|
||||
}
|
||||
return {
|
||||
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
|
||||
outline: options.outline,
|
||||
outlineColor: <string | types.ThemeColor>options.outlineColor,
|
||||
outlineStyle: options.outlineStyle,
|
||||
outlineWidth: options.outlineWidth,
|
||||
border: options.border,
|
||||
borderColor: <string | types.ThemeColor>options.borderColor,
|
||||
borderRadius: options.borderRadius,
|
||||
borderSpacing: options.borderSpacing,
|
||||
borderStyle: options.borderStyle,
|
||||
borderWidth: options.borderWidth,
|
||||
fontStyle: options.fontStyle,
|
||||
fontWeight: options.fontWeight,
|
||||
textDecoration: options.textDecoration,
|
||||
cursor: options.cursor,
|
||||
color: <string | types.ThemeColor>options.color,
|
||||
opacity: options.opacity,
|
||||
letterSpacing: options.letterSpacing,
|
||||
gutterIconPath: pathOrURIToURI(options.gutterIconPath),
|
||||
gutterIconSize: options.gutterIconSize,
|
||||
overviewRulerColor: <string | types.ThemeColor>options.overviewRulerColor,
|
||||
before: ThemableDecorationAttachmentRenderOptions.from(options.before),
|
||||
after: ThemableDecorationAttachmentRenderOptions.from(options.after),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace DecorationRangeBehavior {
|
||||
export function from(value: types.DecorationRangeBehavior): TrackedRangeStickiness {
|
||||
if (typeof value === 'undefined') {
|
||||
return value;
|
||||
}
|
||||
switch (value) {
|
||||
case types.DecorationRangeBehavior.OpenOpen:
|
||||
return TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;
|
||||
case types.DecorationRangeBehavior.ClosedClosed:
|
||||
return TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;
|
||||
case types.DecorationRangeBehavior.OpenClosed:
|
||||
return TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;
|
||||
case types.DecorationRangeBehavior.ClosedOpen:
|
||||
return TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace DecorationRenderOptions {
|
||||
export function from(options: vscode.DecorationRenderOptions): IDecorationRenderOptions {
|
||||
return {
|
||||
isWholeLine: options.isWholeLine,
|
||||
rangeBehavior: DecorationRangeBehavior.from(options.rangeBehavior),
|
||||
overviewRulerLane: options.overviewRulerLane,
|
||||
light: ThemableDecorationRenderOptions.from(options.light),
|
||||
dark: ThemableDecorationRenderOptions.from(options.dark),
|
||||
|
||||
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
|
||||
outline: options.outline,
|
||||
outlineColor: <string | types.ThemeColor>options.outlineColor,
|
||||
outlineStyle: options.outlineStyle,
|
||||
outlineWidth: options.outlineWidth,
|
||||
border: options.border,
|
||||
borderColor: <string | types.ThemeColor>options.borderColor,
|
||||
borderRadius: options.borderRadius,
|
||||
borderSpacing: options.borderSpacing,
|
||||
borderStyle: options.borderStyle,
|
||||
borderWidth: options.borderWidth,
|
||||
fontStyle: options.fontStyle,
|
||||
fontWeight: options.fontWeight,
|
||||
textDecoration: options.textDecoration,
|
||||
cursor: options.cursor,
|
||||
color: <string | types.ThemeColor>options.color,
|
||||
opacity: options.opacity,
|
||||
letterSpacing: options.letterSpacing,
|
||||
gutterIconPath: pathOrURIToURI(options.gutterIconPath),
|
||||
gutterIconSize: options.gutterIconSize,
|
||||
overviewRulerColor: <string | types.ThemeColor>options.overviewRulerColor,
|
||||
before: ThemableDecorationAttachmentRenderOptions.from(options.before),
|
||||
after: ThemableDecorationAttachmentRenderOptions.from(options.after),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TextEdit {
|
||||
|
||||
export function from(edit: vscode.TextEdit): modes.TextEdit {
|
||||
return <modes.TextEdit>{
|
||||
text: edit.newText,
|
||||
eol: EndOfLine.from(edit.newEol),
|
||||
range: Range.from(edit.range)
|
||||
};
|
||||
},
|
||||
to(edit: modes.TextEdit): types.TextEdit {
|
||||
let result = new types.TextEdit(Range.to(edit.range), edit.text);
|
||||
}
|
||||
|
||||
export function to(edit: modes.TextEdit): types.TextEdit {
|
||||
const result = new types.TextEdit(Range.to(edit.range), edit.text);
|
||||
result.newEol = EndOfLine.to(edit.eol);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): WorkspaceEditDto {
|
||||
@@ -278,7 +446,7 @@ export namespace WorkspaceEdit {
|
||||
const [uri, uriOrEdits] = entry;
|
||||
if (Array.isArray(uriOrEdits)) {
|
||||
// text edits
|
||||
let doc = documents ? documents.getDocument(uri.toString()) : undefined;
|
||||
const doc = documents ? documents.getDocument(uri.toString()) : undefined;
|
||||
result.edits.push(<ResourceTextEditDto>{ resource: uri, modelVersionId: doc && doc.version, edits: uriOrEdits.map(TextEdit.from) });
|
||||
} else {
|
||||
// resource edits
|
||||
@@ -340,11 +508,11 @@ export namespace SymbolKind {
|
||||
_fromMapping[types.SymbolKind.TypeParameter] = modes.SymbolKind.TypeParameter;
|
||||
|
||||
export function from(kind: vscode.SymbolKind): modes.SymbolKind {
|
||||
return _fromMapping[kind] || modes.SymbolKind.Property;
|
||||
return typeof _fromMapping[kind] === 'number' ? _fromMapping[kind] : modes.SymbolKind.Property;
|
||||
}
|
||||
|
||||
export function to(kind: modes.SymbolKind): vscode.SymbolKind {
|
||||
for (let k in _fromMapping) {
|
||||
for (const k in _fromMapping) {
|
||||
if (_fromMapping[k] === kind) {
|
||||
return Number(k);
|
||||
}
|
||||
@@ -374,7 +542,7 @@ export namespace WorkspaceSymbol {
|
||||
|
||||
export namespace DocumentSymbol {
|
||||
export function from(info: vscode.DocumentSymbol): modes.DocumentSymbol {
|
||||
let result: modes.DocumentSymbol = {
|
||||
const result: modes.DocumentSymbol = {
|
||||
name: info.name,
|
||||
detail: info.detail,
|
||||
range: Range.from(info.range),
|
||||
@@ -387,7 +555,7 @@ export namespace DocumentSymbol {
|
||||
return result;
|
||||
}
|
||||
export function to(info: modes.DocumentSymbol): vscode.DocumentSymbol {
|
||||
let result = new types.DocumentSymbol(
|
||||
const result = new types.DocumentSymbol(
|
||||
info.name,
|
||||
info.detail,
|
||||
SymbolKind.to(info.kind),
|
||||
@@ -401,17 +569,18 @@ export namespace DocumentSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
export const location = {
|
||||
from(value: vscode.Location): modes.Location {
|
||||
export namespace location {
|
||||
export function from(value: vscode.Location): modes.Location {
|
||||
return {
|
||||
range: value.range && Range.from(value.range),
|
||||
uri: value.uri
|
||||
};
|
||||
},
|
||||
to(value: modes.Location): types.Location {
|
||||
}
|
||||
|
||||
export function to(value: modes.Location): types.Location {
|
||||
return new types.Location(value.uri, Range.to(value.range));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export namespace DefinitionLink {
|
||||
export function from(value: vscode.Location | vscode.DefinitionLink): modes.DefinitionLink {
|
||||
@@ -455,13 +624,13 @@ export namespace DocumentHighlight {
|
||||
}
|
||||
|
||||
export namespace CompletionTriggerKind {
|
||||
export function from(kind: modes.SuggestTriggerKind) {
|
||||
export function to(kind: modes.CompletionTriggerKind) {
|
||||
switch (kind) {
|
||||
case modes.SuggestTriggerKind.TriggerCharacter:
|
||||
case modes.CompletionTriggerKind.TriggerCharacter:
|
||||
return types.CompletionTriggerKind.TriggerCharacter;
|
||||
case modes.SuggestTriggerKind.TriggerForIncompleteCompletions:
|
||||
case modes.CompletionTriggerKind.TriggerForIncompleteCompletions:
|
||||
return types.CompletionTriggerKind.TriggerForIncompleteCompletions;
|
||||
case modes.SuggestTriggerKind.Invoke:
|
||||
case modes.CompletionTriggerKind.Invoke:
|
||||
default:
|
||||
return types.CompletionTriggerKind.Invoke;
|
||||
}
|
||||
@@ -469,85 +638,100 @@ export namespace CompletionTriggerKind {
|
||||
}
|
||||
|
||||
export namespace CompletionContext {
|
||||
export function from(context: modes.SuggestContext): types.CompletionContext {
|
||||
export function to(context: modes.CompletionContext): types.CompletionContext {
|
||||
return {
|
||||
triggerKind: CompletionTriggerKind.from(context.triggerKind),
|
||||
triggerKind: CompletionTriggerKind.to(context.triggerKind),
|
||||
triggerCharacter: context.triggerCharacter
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const CompletionItemKind = {
|
||||
export namespace CompletionItemKind {
|
||||
|
||||
from(kind: types.CompletionItemKind): modes.SuggestionType {
|
||||
export function from(kind: types.CompletionItemKind): modes.CompletionItemKind {
|
||||
switch (kind) {
|
||||
case types.CompletionItemKind.Method: return 'method';
|
||||
case types.CompletionItemKind.Function: return 'function';
|
||||
case types.CompletionItemKind.Constructor: return 'constructor';
|
||||
case types.CompletionItemKind.Field: return 'field';
|
||||
case types.CompletionItemKind.Variable: return 'variable';
|
||||
case types.CompletionItemKind.Class: return 'class';
|
||||
case types.CompletionItemKind.Interface: return 'interface';
|
||||
case types.CompletionItemKind.Struct: return 'struct';
|
||||
case types.CompletionItemKind.Module: return 'module';
|
||||
case types.CompletionItemKind.Property: return 'property';
|
||||
case types.CompletionItemKind.Unit: return 'unit';
|
||||
case types.CompletionItemKind.Value: return 'value';
|
||||
case types.CompletionItemKind.Constant: return 'constant';
|
||||
case types.CompletionItemKind.Enum: return 'enum';
|
||||
case types.CompletionItemKind.EnumMember: return 'enum-member';
|
||||
case types.CompletionItemKind.Keyword: return 'keyword';
|
||||
case types.CompletionItemKind.Snippet: return 'snippet';
|
||||
case types.CompletionItemKind.Text: return 'text';
|
||||
case types.CompletionItemKind.Color: return 'color';
|
||||
case types.CompletionItemKind.File: return 'file';
|
||||
case types.CompletionItemKind.Reference: return 'reference';
|
||||
case types.CompletionItemKind.Folder: return 'folder';
|
||||
case types.CompletionItemKind.Event: return 'event';
|
||||
case types.CompletionItemKind.Operator: return 'operator';
|
||||
case types.CompletionItemKind.TypeParameter: return 'type-parameter';
|
||||
}
|
||||
return 'property';
|
||||
},
|
||||
|
||||
to(type: modes.SuggestionType): types.CompletionItemKind {
|
||||
if (!type) {
|
||||
return types.CompletionItemKind.Property;
|
||||
} else {
|
||||
return types.CompletionItemKind[type.charAt(0).toUpperCase() + type.substr(1)];
|
||||
case types.CompletionItemKind.Method: return modes.CompletionItemKind.Method;
|
||||
case types.CompletionItemKind.Function: return modes.CompletionItemKind.Function;
|
||||
case types.CompletionItemKind.Constructor: return modes.CompletionItemKind.Constructor;
|
||||
case types.CompletionItemKind.Field: return modes.CompletionItemKind.Field;
|
||||
case types.CompletionItemKind.Variable: return modes.CompletionItemKind.Variable;
|
||||
case types.CompletionItemKind.Class: return modes.CompletionItemKind.Class;
|
||||
case types.CompletionItemKind.Interface: return modes.CompletionItemKind.Interface;
|
||||
case types.CompletionItemKind.Struct: return modes.CompletionItemKind.Struct;
|
||||
case types.CompletionItemKind.Module: return modes.CompletionItemKind.Module;
|
||||
case types.CompletionItemKind.Property: return modes.CompletionItemKind.Property;
|
||||
case types.CompletionItemKind.Unit: return modes.CompletionItemKind.Unit;
|
||||
case types.CompletionItemKind.Value: return modes.CompletionItemKind.Value;
|
||||
case types.CompletionItemKind.Constant: return modes.CompletionItemKind.Constant;
|
||||
case types.CompletionItemKind.Enum: return modes.CompletionItemKind.Enum;
|
||||
case types.CompletionItemKind.EnumMember: return modes.CompletionItemKind.EnumMember;
|
||||
case types.CompletionItemKind.Keyword: return modes.CompletionItemKind.Keyword;
|
||||
case types.CompletionItemKind.Snippet: return modes.CompletionItemKind.Snippet;
|
||||
case types.CompletionItemKind.Text: return modes.CompletionItemKind.Text;
|
||||
case types.CompletionItemKind.Color: return modes.CompletionItemKind.Color;
|
||||
case types.CompletionItemKind.File: return modes.CompletionItemKind.File;
|
||||
case types.CompletionItemKind.Reference: return modes.CompletionItemKind.Reference;
|
||||
case types.CompletionItemKind.Folder: return modes.CompletionItemKind.Folder;
|
||||
case types.CompletionItemKind.Event: return modes.CompletionItemKind.Event;
|
||||
case types.CompletionItemKind.Operator: return modes.CompletionItemKind.Operator;
|
||||
case types.CompletionItemKind.TypeParameter: return modes.CompletionItemKind.TypeParameter;
|
||||
}
|
||||
return modes.CompletionItemKind.Property;
|
||||
}
|
||||
};
|
||||
|
||||
export namespace Suggest {
|
||||
export function to(kind: modes.CompletionItemKind): types.CompletionItemKind {
|
||||
switch (kind) {
|
||||
case modes.CompletionItemKind.Method: return types.CompletionItemKind.Method;
|
||||
case modes.CompletionItemKind.Function: return types.CompletionItemKind.Function;
|
||||
case modes.CompletionItemKind.Constructor: return types.CompletionItemKind.Constructor;
|
||||
case modes.CompletionItemKind.Field: return types.CompletionItemKind.Field;
|
||||
case modes.CompletionItemKind.Variable: return types.CompletionItemKind.Variable;
|
||||
case modes.CompletionItemKind.Class: return types.CompletionItemKind.Class;
|
||||
case modes.CompletionItemKind.Interface: return types.CompletionItemKind.Interface;
|
||||
case modes.CompletionItemKind.Struct: return types.CompletionItemKind.Struct;
|
||||
case modes.CompletionItemKind.Module: return types.CompletionItemKind.Module;
|
||||
case modes.CompletionItemKind.Property: return types.CompletionItemKind.Property;
|
||||
case modes.CompletionItemKind.Unit: return types.CompletionItemKind.Unit;
|
||||
case modes.CompletionItemKind.Value: return types.CompletionItemKind.Value;
|
||||
case modes.CompletionItemKind.Constant: return types.CompletionItemKind.Constant;
|
||||
case modes.CompletionItemKind.Enum: return types.CompletionItemKind.Enum;
|
||||
case modes.CompletionItemKind.EnumMember: return types.CompletionItemKind.EnumMember;
|
||||
case modes.CompletionItemKind.Keyword: return types.CompletionItemKind.Keyword;
|
||||
case modes.CompletionItemKind.Snippet: return types.CompletionItemKind.Snippet;
|
||||
case modes.CompletionItemKind.Text: return types.CompletionItemKind.Text;
|
||||
case modes.CompletionItemKind.Color: return types.CompletionItemKind.Color;
|
||||
case modes.CompletionItemKind.File: return types.CompletionItemKind.File;
|
||||
case modes.CompletionItemKind.Reference: return types.CompletionItemKind.Reference;
|
||||
case modes.CompletionItemKind.Folder: return types.CompletionItemKind.Folder;
|
||||
case modes.CompletionItemKind.Event: return types.CompletionItemKind.Event;
|
||||
case modes.CompletionItemKind.Operator: return types.CompletionItemKind.Operator;
|
||||
case modes.CompletionItemKind.TypeParameter: return types.CompletionItemKind.TypeParameter;
|
||||
}
|
||||
return types.CompletionItemKind.Property;
|
||||
}
|
||||
}
|
||||
|
||||
export function to(position: types.Position, suggestion: modes.ISuggestion): types.CompletionItem {
|
||||
export namespace CompletionItem {
|
||||
|
||||
export function to(suggestion: modes.CompletionItem): types.CompletionItem {
|
||||
const result = new types.CompletionItem(suggestion.label);
|
||||
result.insertText = suggestion.insertText;
|
||||
result.kind = CompletionItemKind.to(suggestion.type);
|
||||
result.kind = CompletionItemKind.to(suggestion.kind);
|
||||
result.detail = suggestion.detail;
|
||||
result.documentation = htmlContent.isMarkdownString(suggestion.documentation) ? MarkdownString.to(suggestion.documentation) : suggestion.documentation;
|
||||
result.sortText = suggestion.sortText;
|
||||
result.filterText = suggestion.filterText;
|
||||
result.preselect = suggestion.preselect;
|
||||
|
||||
// 'overwrite[Before|After]'-logic
|
||||
let overwriteBefore = (typeof suggestion.overwriteBefore === 'number') ? suggestion.overwriteBefore : 0;
|
||||
let startPosition = new types.Position(position.line, Math.max(0, position.character - overwriteBefore));
|
||||
let endPosition = position;
|
||||
if (typeof suggestion.overwriteAfter === 'number') {
|
||||
endPosition = new types.Position(position.line, position.character + suggestion.overwriteAfter);
|
||||
}
|
||||
result.range = new types.Range(startPosition, endPosition);
|
||||
|
||||
result.commitCharacters = suggestion.commitCharacters;
|
||||
result.range = Range.to(suggestion.range);
|
||||
result.keepWhitespace = Boolean(suggestion.insertTextRules & modes.CompletionItemInsertTextRule.KeepWhitespace);
|
||||
// 'inserText'-logic
|
||||
if (suggestion.snippetType === 'textmate') {
|
||||
if (suggestion.insertTextRules & modes.CompletionItemInsertTextRule.InsertAsSnippet) {
|
||||
result.insertText = new types.SnippetString(suggestion.insertText);
|
||||
} else {
|
||||
result.insertText = suggestion.insertText;
|
||||
result.textEdit = new types.TextEdit(result.range, result.insertText);
|
||||
}
|
||||
|
||||
// TODO additionalEdits, command
|
||||
|
||||
return result;
|
||||
@@ -623,7 +807,7 @@ export namespace DocumentLink {
|
||||
|
||||
export namespace ColorPresentation {
|
||||
export function to(colorPresentation: modes.IColorPresentation): types.ColorPresentation {
|
||||
let cp = new types.ColorPresentation(colorPresentation.label);
|
||||
const cp = new types.ColorPresentation(colorPresentation.label);
|
||||
if (colorPresentation.textEdit) {
|
||||
cp.textEdit = TextEdit.to(colorPresentation.textEdit);
|
||||
}
|
||||
@@ -701,7 +885,7 @@ export namespace ProgressLocation {
|
||||
|
||||
export namespace FoldingRange {
|
||||
export function from(r: vscode.FoldingRange): modes.FoldingRange {
|
||||
let range: modes.FoldingRange = { start: r.start + 1, end: r.end + 1 };
|
||||
const range: modes.FoldingRange = { start: r.start + 1, end: r.end + 1 };
|
||||
if (r.kind) {
|
||||
range.kind = FoldingRangeKind.from(r.kind);
|
||||
}
|
||||
@@ -743,7 +927,11 @@ export namespace TextEditorOptions {
|
||||
|
||||
export namespace GlobPattern {
|
||||
|
||||
export function from(pattern: vscode.GlobPattern): string | IRelativePattern {
|
||||
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern {
|
||||
if (pattern instanceof types.RelativePattern) {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (typeof pattern === 'string') {
|
||||
return pattern;
|
||||
}
|
||||
@@ -780,3 +968,51 @@ export namespace LanguageSelector {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace LogLevel {
|
||||
export function from(extLevel: types.LogLevel): _MainLogLevel {
|
||||
switch (extLevel) {
|
||||
case types.LogLevel.Trace:
|
||||
return _MainLogLevel.Trace;
|
||||
case types.LogLevel.Debug:
|
||||
return _MainLogLevel.Debug;
|
||||
case types.LogLevel.Info:
|
||||
return _MainLogLevel.Info;
|
||||
case types.LogLevel.Warning:
|
||||
return _MainLogLevel.Warning;
|
||||
case types.LogLevel.Error:
|
||||
return _MainLogLevel.Error;
|
||||
case types.LogLevel.Critical:
|
||||
return _MainLogLevel.Critical;
|
||||
case types.LogLevel.Critical:
|
||||
return _MainLogLevel.Critical;
|
||||
case types.LogLevel.Off:
|
||||
return _MainLogLevel.Off;
|
||||
}
|
||||
|
||||
return _MainLogLevel.Info;
|
||||
}
|
||||
|
||||
export function to(mainLevel: _MainLogLevel): types.LogLevel {
|
||||
switch (mainLevel) {
|
||||
case _MainLogLevel.Trace:
|
||||
return types.LogLevel.Trace;
|
||||
case _MainLogLevel.Debug:
|
||||
return types.LogLevel.Debug;
|
||||
case _MainLogLevel.Info:
|
||||
return types.LogLevel.Info;
|
||||
case _MainLogLevel.Warning:
|
||||
return types.LogLevel.Warning;
|
||||
case _MainLogLevel.Error:
|
||||
return types.LogLevel.Error;
|
||||
case _MainLogLevel.Critical:
|
||||
return types.LogLevel.Critical;
|
||||
case _MainLogLevel.Critical:
|
||||
return types.LogLevel.Critical;
|
||||
case _MainLogLevel.Off:
|
||||
return types.LogLevel.Off;
|
||||
}
|
||||
|
||||
return types.LogLevel.Info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
* 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 crypto from 'crypto';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import * as vscode from 'vscode';
|
||||
import { isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
@@ -14,14 +13,16 @@ import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { relative } from 'path';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { coalesce, equals } from 'vs/base/common/arrays';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export class Disposable {
|
||||
|
||||
static from(...disposables: { dispose(): any }[]): Disposable {
|
||||
static from(...inDisposables: { dispose(): any }[]): Disposable {
|
||||
let disposables: ReadonlyArray<{ dispose(): any }> | undefined = inDisposables;
|
||||
return new Disposable(function () {
|
||||
if (disposables) {
|
||||
for (let disposable of disposables) {
|
||||
for (const disposable of disposables) {
|
||||
if (disposable && typeof disposable.dispose === 'function') {
|
||||
disposable.dispose();
|
||||
}
|
||||
@@ -31,7 +32,7 @@ export class Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private _callOnDispose: Function;
|
||||
private _callOnDispose?: Function;
|
||||
|
||||
constructor(callOnDispose: Function) {
|
||||
this._callOnDispose = callOnDispose;
|
||||
@@ -48,9 +49,13 @@ export class Disposable {
|
||||
export class Position {
|
||||
|
||||
static Min(...positions: Position[]): Position {
|
||||
let result = positions.pop();
|
||||
for (let p of positions) {
|
||||
if (p.isBefore(result)) {
|
||||
if (positions.length === 0) {
|
||||
throw new TypeError();
|
||||
}
|
||||
let result = positions[0];
|
||||
for (let i = 1; i < positions.length; i++) {
|
||||
let p = positions[i];
|
||||
if (p.isBefore(result!)) {
|
||||
result = p;
|
||||
}
|
||||
}
|
||||
@@ -58,9 +63,13 @@ export class Position {
|
||||
}
|
||||
|
||||
static Max(...positions: Position[]): Position {
|
||||
let result = positions.pop();
|
||||
for (let p of positions) {
|
||||
if (p.isAfter(result)) {
|
||||
if (positions.length === 0) {
|
||||
throw new TypeError();
|
||||
}
|
||||
let result = positions[0];
|
||||
for (let i = 1; i < positions.length; i++) {
|
||||
let p = positions[i];
|
||||
if (p.isAfter(result!)) {
|
||||
result = p;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +164,7 @@ export class Position {
|
||||
|
||||
translate(change: { lineDelta?: number; characterDelta?: number; }): Position;
|
||||
translate(lineDelta?: number, characterDelta?: number): Position;
|
||||
translate(lineDeltaOrChange: number | { lineDelta?: number; characterDelta?: number; }, characterDelta: number = 0): Position {
|
||||
translate(lineDeltaOrChange: number | undefined | { lineDelta?: number; characterDelta?: number; }, characterDelta: number = 0): Position {
|
||||
|
||||
if (lineDeltaOrChange === null || characterDelta === null) {
|
||||
throw illegalArgument();
|
||||
@@ -179,7 +188,7 @@ export class Position {
|
||||
|
||||
with(change: { line?: number; character?: number; }): Position;
|
||||
with(line?: number, character?: number): Position;
|
||||
with(lineOrChange: number | { line?: number; character?: number; }, character: number = this.character): Position {
|
||||
with(lineOrChange: number | undefined | { line?: number; character?: number; }, character: number = this.character): Position {
|
||||
|
||||
if (lineOrChange === null || character === null) {
|
||||
throw illegalArgument();
|
||||
@@ -235,8 +244,8 @@ export class Range {
|
||||
constructor(start: Position, end: Position);
|
||||
constructor(startLine: number, startColumn: number, endLine: number, endColumn: number);
|
||||
constructor(startLineOrStart: number | Position, startColumnOrEnd: number | Position, endLine?: number, endColumn?: number) {
|
||||
let start: Position;
|
||||
let end: Position;
|
||||
let start: Position | undefined;
|
||||
let end: Position | undefined;
|
||||
|
||||
if (typeof startLineOrStart === 'number' && typeof startColumnOrEnd === 'number' && typeof endLine === 'number' && typeof endColumn === 'number') {
|
||||
start = new Position(startLineOrStart, startColumnOrEnd);
|
||||
@@ -280,7 +289,7 @@ export class Range {
|
||||
return this._start.isEqual(other._start) && this._end.isEqual(other._end);
|
||||
}
|
||||
|
||||
intersection(other: Range): Range {
|
||||
intersection(other: Range): Range | undefined {
|
||||
let start = Position.Max(other.start, this._start);
|
||||
let end = Position.Min(other.end, this._end);
|
||||
if (start.isAfter(end)) {
|
||||
@@ -313,7 +322,7 @@ export class Range {
|
||||
|
||||
with(change: { start?: Position, end?: Position }): Range;
|
||||
with(start?: Position, end?: Position): Range;
|
||||
with(startOrChange: Position | { start?: Position, end?: Position }, end: Position = this.end): Range {
|
||||
with(startOrChange: Position | undefined | { start?: Position, end?: Position }, end: Position = this.end): Range {
|
||||
|
||||
if (startOrChange === null || end === null) {
|
||||
throw illegalArgument();
|
||||
@@ -372,8 +381,8 @@ export class Selection extends Range {
|
||||
constructor(anchor: Position, active: Position);
|
||||
constructor(anchorLine: number, anchorColumn: number, activeLine: number, activeColumn: number);
|
||||
constructor(anchorLineOrAnchor: number | Position, anchorColumnOrActive: number | Position, activeLine?: number, activeColumn?: number) {
|
||||
let anchor: Position;
|
||||
let active: Position;
|
||||
let anchor: Position | undefined;
|
||||
let active: Position | undefined;
|
||||
|
||||
if (typeof anchorLineOrAnchor === 'number' && typeof anchorColumnOrActive === 'number' && typeof activeLine === 'number' && typeof activeColumn === 'number') {
|
||||
anchor = new Position(anchorLineOrAnchor, anchorColumnOrActive);
|
||||
@@ -438,7 +447,7 @@ export class TextEdit {
|
||||
}
|
||||
|
||||
static setEndOfLine(eol: EndOfLine): TextEdit {
|
||||
let ret = new TextEdit(undefined, undefined);
|
||||
let ret = new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), '');
|
||||
ret.newEol = eol;
|
||||
return ret;
|
||||
}
|
||||
@@ -504,8 +513,8 @@ export interface IFileOperationOptions {
|
||||
|
||||
export interface IFileOperation {
|
||||
_type: 1;
|
||||
from: URI;
|
||||
to: URI;
|
||||
from?: URI;
|
||||
to?: URI;
|
||||
options?: IFileOperationOptions;
|
||||
}
|
||||
|
||||
@@ -558,7 +567,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
for (let i = 0; i < this._edits.length; i++) {
|
||||
const element = this._edits[i];
|
||||
if (element._type === 2 && element.uri.toString() === uri.toString()) {
|
||||
this._edits[i] = undefined;
|
||||
this._edits[i] = undefined!; // will be coalesced down below
|
||||
}
|
||||
}
|
||||
this._edits = coalesce(this._edits);
|
||||
@@ -579,9 +588,6 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
res.push(candidate.edit);
|
||||
}
|
||||
}
|
||||
if (res.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -600,8 +606,8 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
return values(textEdits);
|
||||
}
|
||||
|
||||
_allEntries(): ([URI, TextEdit[]] | [URI, URI, IFileOperationOptions])[] {
|
||||
let res: ([URI, TextEdit[]] | [URI, URI, IFileOperationOptions])[] = [];
|
||||
_allEntries(): ([URI, TextEdit[]] | [URI?, URI?, IFileOperationOptions?])[] {
|
||||
let res: ([URI, TextEdit[]] | [URI?, URI?, IFileOperationOptions?])[] = [];
|
||||
for (let edit of this._edits) {
|
||||
if (edit._type === 1) {
|
||||
res.push([edit.from, edit.to, edit.options]);
|
||||
@@ -771,6 +777,18 @@ export class DiagnosticRelatedInformation {
|
||||
this.location = location;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
static isEqual(a: DiagnosticRelatedInformation, b: DiagnosticRelatedInformation): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a.message === b.message
|
||||
&& a.location.range.isEqual(b.location.range)
|
||||
&& a.location.uri.toString() === b.location.uri.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export class Diagnostic {
|
||||
@@ -798,12 +816,29 @@ export class Diagnostic {
|
||||
code: this.code,
|
||||
};
|
||||
}
|
||||
|
||||
static isEqual(a: Diagnostic | undefined, b: Diagnostic | undefined): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a.message === b.message
|
||||
&& a.severity === b.severity
|
||||
&& a.code === b.code
|
||||
&& a.severity === b.severity
|
||||
&& a.source === b.source
|
||||
&& a.range.isEqual(b.range)
|
||||
&& equals(a.tags, b.tags)
|
||||
&& equals(a.relatedInformation, b.relatedInformation, DiagnosticRelatedInformation.isEqual);
|
||||
}
|
||||
}
|
||||
|
||||
export class Hover {
|
||||
|
||||
public contents: vscode.MarkdownString[] | vscode.MarkedString[];
|
||||
public range: Range;
|
||||
public range: Range | undefined;
|
||||
|
||||
constructor(
|
||||
contents: vscode.MarkdownString | vscode.MarkedString | vscode.MarkdownString[] | vscode.MarkedString[],
|
||||
@@ -878,10 +913,16 @@ export enum SymbolKind {
|
||||
|
||||
export class SymbolInformation {
|
||||
|
||||
static validate(candidate: SymbolInformation): void {
|
||||
if (!candidate.name) {
|
||||
throw new Error('name must not be falsy');
|
||||
}
|
||||
}
|
||||
|
||||
name: string;
|
||||
location: Location;
|
||||
kind: SymbolKind;
|
||||
containerName: string;
|
||||
containerName: string | undefined;
|
||||
|
||||
constructor(name: string, kind: SymbolKind, containerName: string, location: Location);
|
||||
constructor(name: string, kind: SymbolKind, range: Range, uri?: URI, containerName?: string);
|
||||
@@ -897,8 +938,10 @@ export class SymbolInformation {
|
||||
if (locationOrUri instanceof Location) {
|
||||
this.location = locationOrUri;
|
||||
} else if (rangeOrContainer instanceof Range) {
|
||||
this.location = new Location(locationOrUri, rangeOrContainer);
|
||||
this.location = new Location(locationOrUri!, rangeOrContainer);
|
||||
}
|
||||
|
||||
SymbolInformation.validate(this);
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
@@ -912,6 +955,19 @@ export class SymbolInformation {
|
||||
}
|
||||
|
||||
export class DocumentSymbol {
|
||||
|
||||
static validate(candidate: DocumentSymbol): void {
|
||||
if (!candidate.name) {
|
||||
throw new Error('name must not be falsy');
|
||||
}
|
||||
if (!candidate.range.contains(candidate.selectionRange)) {
|
||||
throw new Error('selectionRange must be contained in fullRange');
|
||||
}
|
||||
if (candidate.children) {
|
||||
candidate.children.forEach(DocumentSymbol.validate);
|
||||
}
|
||||
}
|
||||
|
||||
name: string;
|
||||
detail: string;
|
||||
kind: SymbolKind;
|
||||
@@ -927,9 +983,7 @@ export class DocumentSymbol {
|
||||
this.selectionRange = selectionRange;
|
||||
this.children = [];
|
||||
|
||||
if (!this.range.contains(this.selectionRange)) {
|
||||
throw new Error('selectionRange must be contained in fullRange');
|
||||
}
|
||||
DocumentSymbol.validate(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,7 +1041,7 @@ export class CodeLens {
|
||||
|
||||
range: Range;
|
||||
|
||||
command: vscode.Command;
|
||||
command: vscode.Command | undefined;
|
||||
|
||||
constructor(range: Range, command?: vscode.Command) {
|
||||
this.range = range;
|
||||
@@ -1031,10 +1085,10 @@ export class MarkdownString {
|
||||
|
||||
export class ParameterInformation {
|
||||
|
||||
label: string;
|
||||
label: string | [number, number];
|
||||
documentation?: string | MarkdownString;
|
||||
|
||||
constructor(label: string, documentation?: string | MarkdownString) {
|
||||
constructor(label: string | [number, number], documentation?: string | MarkdownString) {
|
||||
this.label = label;
|
||||
this.documentation = documentation;
|
||||
}
|
||||
@@ -1064,6 +1118,12 @@ export class SignatureHelp {
|
||||
}
|
||||
}
|
||||
|
||||
export enum SignatureHelpTriggerKind {
|
||||
Invoke = 1,
|
||||
TriggerCharacter = 2,
|
||||
ContentChange = 3,
|
||||
}
|
||||
|
||||
export enum CompletionTriggerKind {
|
||||
Invoke = 0,
|
||||
TriggerCharacter = 1,
|
||||
@@ -1106,14 +1166,16 @@ export enum CompletionItemKind {
|
||||
export class CompletionItem implements vscode.CompletionItem {
|
||||
|
||||
label: string;
|
||||
kind: CompletionItemKind;
|
||||
kind: CompletionItemKind | undefined;
|
||||
detail: string;
|
||||
documentation: string | MarkdownString;
|
||||
sortText: string;
|
||||
filterText: string;
|
||||
preselect: boolean;
|
||||
insertText: string | SnippetString;
|
||||
keepWhitespace?: boolean;
|
||||
range: Range;
|
||||
commitCharacters: string[];
|
||||
textEdit: TextEdit;
|
||||
additionalTextEdits: TextEdit[];
|
||||
command: vscode.Command;
|
||||
@@ -1126,7 +1188,7 @@ export class CompletionItem implements vscode.CompletionItem {
|
||||
toJSON(): any {
|
||||
return {
|
||||
label: this.label,
|
||||
kind: CompletionItemKind[this.kind],
|
||||
kind: this.kind && CompletionItemKind[this.kind],
|
||||
detail: this.detail,
|
||||
documentation: this.documentation,
|
||||
sortText: this.sortText,
|
||||
@@ -1365,7 +1427,7 @@ export class ProcessExecution implements vscode.ProcessExecution {
|
||||
|
||||
private _process: string;
|
||||
private _args: string[];
|
||||
private _options: vscode.ProcessExecutionOptions;
|
||||
private _options: vscode.ProcessExecutionOptions | undefined;
|
||||
|
||||
constructor(process: string, options?: vscode.ProcessExecutionOptions);
|
||||
constructor(process: string, args: string[], options?: vscode.ProcessExecutionOptions);
|
||||
@@ -1410,11 +1472,11 @@ export class ProcessExecution implements vscode.ProcessExecution {
|
||||
this._args = value;
|
||||
}
|
||||
|
||||
get options(): vscode.ProcessExecutionOptions {
|
||||
get options(): vscode.ProcessExecutionOptions | undefined {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
set options(value: vscode.ProcessExecutionOptions) {
|
||||
set options(value: vscode.ProcessExecutionOptions | undefined) {
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
@@ -1438,7 +1500,7 @@ export class ShellExecution implements vscode.ShellExecution {
|
||||
private _commandLine: string;
|
||||
private _command: string | vscode.ShellQuotedString;
|
||||
private _args: (string | vscode.ShellQuotedString)[];
|
||||
private _options: vscode.ShellExecutionOptions;
|
||||
private _options: vscode.ShellExecutionOptions | undefined;
|
||||
|
||||
constructor(commandLine: string, options?: vscode.ShellExecutionOptions);
|
||||
constructor(command: string | vscode.ShellQuotedString, args: (string | vscode.ShellQuotedString)[], options?: vscode.ShellExecutionOptions);
|
||||
@@ -1492,11 +1554,11 @@ export class ShellExecution implements vscode.ShellExecution {
|
||||
this._args = value || [];
|
||||
}
|
||||
|
||||
get options(): vscode.ShellExecutionOptions {
|
||||
get options(): vscode.ShellExecutionOptions | undefined {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
set options(value: vscode.ShellExecutionOptions) {
|
||||
set options(value: vscode.ShellExecutionOptions | undefined) {
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
@@ -1531,18 +1593,23 @@ export enum TaskScope {
|
||||
|
||||
export class Task implements vscode.Task {
|
||||
|
||||
private __id: string;
|
||||
private static ProcessType: string = 'process';
|
||||
private static ShellType: string = 'shell';
|
||||
private static EmptyType: string = '$empty';
|
||||
|
||||
private __id: string | undefined;
|
||||
|
||||
private _definition: vscode.TaskDefinition;
|
||||
private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder;
|
||||
private _scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined;
|
||||
private _name: string;
|
||||
private _execution: ProcessExecution | ShellExecution;
|
||||
private _execution: ProcessExecution | ShellExecution | undefined;
|
||||
private _problemMatchers: string[];
|
||||
private _hasDefinedMatchers: boolean;
|
||||
private _isBackground: boolean;
|
||||
private _source: string;
|
||||
private _group: TaskGroup;
|
||||
private _group: TaskGroup | undefined;
|
||||
private _presentationOptions: vscode.TaskPresentationOptions;
|
||||
private _runOptions: vscode.RunOptions;
|
||||
|
||||
constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]);
|
||||
constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]);
|
||||
@@ -1578,13 +1645,15 @@ export class Task implements vscode.Task {
|
||||
this._hasDefinedMatchers = false;
|
||||
}
|
||||
this._isBackground = false;
|
||||
this._presentationOptions = Object.create(null);
|
||||
this._runOptions = Object.create(null);
|
||||
}
|
||||
|
||||
get _id(): string {
|
||||
get _id(): string | undefined {
|
||||
return this.__id;
|
||||
}
|
||||
|
||||
set _id(value: string) {
|
||||
set _id(value: string | undefined) {
|
||||
this.__id = value;
|
||||
}
|
||||
|
||||
@@ -1594,17 +1663,25 @@ export class Task implements vscode.Task {
|
||||
}
|
||||
this.__id = undefined;
|
||||
this._scope = undefined;
|
||||
this._definition = undefined;
|
||||
this.computeDefinitionBasedOnExecution();
|
||||
}
|
||||
|
||||
private computeDefinitionBasedOnExecution(): void {
|
||||
if (this._execution instanceof ProcessExecution) {
|
||||
this._definition = {
|
||||
type: 'process',
|
||||
type: Task.ProcessType,
|
||||
id: this._execution.computeId()
|
||||
};
|
||||
} else if (this._execution instanceof ShellExecution) {
|
||||
this._definition = {
|
||||
type: 'shell',
|
||||
type: Task.ShellType,
|
||||
id: this._execution.computeId()
|
||||
};
|
||||
} else {
|
||||
this._definition = {
|
||||
type: Task.EmptyType,
|
||||
id: generateUuid()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1620,7 +1697,7 @@ export class Task implements vscode.Task {
|
||||
this._definition = value;
|
||||
}
|
||||
|
||||
get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder {
|
||||
get scope(): vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined {
|
||||
return this._scope;
|
||||
}
|
||||
|
||||
@@ -1641,16 +1718,20 @@ export class Task implements vscode.Task {
|
||||
this._name = value;
|
||||
}
|
||||
|
||||
get execution(): ProcessExecution | ShellExecution {
|
||||
get execution(): ProcessExecution | ShellExecution | undefined {
|
||||
return this._execution;
|
||||
}
|
||||
|
||||
set execution(value: ProcessExecution | ShellExecution) {
|
||||
set execution(value: ProcessExecution | ShellExecution | undefined) {
|
||||
if (value === null) {
|
||||
value = undefined;
|
||||
}
|
||||
this.clear();
|
||||
this._execution = value;
|
||||
let type = this._definition.type;
|
||||
if (Task.EmptyType === type || Task.ProcessType === type || Task.ShellType === type) {
|
||||
this.computeDefinitionBasedOnExecution();
|
||||
}
|
||||
}
|
||||
|
||||
get problemMatchers(): string[] {
|
||||
@@ -1659,13 +1740,15 @@ export class Task implements vscode.Task {
|
||||
|
||||
set problemMatchers(value: string[]) {
|
||||
if (!Array.isArray(value)) {
|
||||
this.clear();
|
||||
this._problemMatchers = [];
|
||||
this._hasDefinedMatchers = false;
|
||||
return;
|
||||
} else {
|
||||
this.clear();
|
||||
this._problemMatchers = value;
|
||||
this._hasDefinedMatchers = true;
|
||||
}
|
||||
this.clear();
|
||||
this._problemMatchers = value;
|
||||
this._hasDefinedMatchers = true;
|
||||
}
|
||||
|
||||
get hasDefinedMatchers(): boolean {
|
||||
@@ -1696,14 +1779,13 @@ export class Task implements vscode.Task {
|
||||
this._source = value;
|
||||
}
|
||||
|
||||
get group(): TaskGroup {
|
||||
get group(): TaskGroup | undefined {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
set group(value: TaskGroup) {
|
||||
if (value === void 0 || value === null) {
|
||||
this._group = undefined;
|
||||
return;
|
||||
set group(value: TaskGroup | undefined) {
|
||||
if (value === null) {
|
||||
value = undefined;
|
||||
}
|
||||
this.clear();
|
||||
this._group = value;
|
||||
@@ -1714,12 +1796,24 @@ export class Task implements vscode.Task {
|
||||
}
|
||||
|
||||
set presentationOptions(value: vscode.TaskPresentationOptions) {
|
||||
if (value === null) {
|
||||
value = undefined;
|
||||
if (value === null || value === undefined) {
|
||||
value = Object.create(null);
|
||||
}
|
||||
this.clear();
|
||||
this._presentationOptions = value;
|
||||
}
|
||||
|
||||
get runOptions(): vscode.RunOptions {
|
||||
return this._runOptions;
|
||||
}
|
||||
|
||||
set runOptions(value: vscode.RunOptions) {
|
||||
if (value === null || value === undefined) {
|
||||
value = Object.create(null);
|
||||
}
|
||||
this.clear();
|
||||
this._runOptions = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1731,16 +1825,16 @@ export enum ProgressLocation {
|
||||
|
||||
export class TreeItem {
|
||||
|
||||
label?: string;
|
||||
label?: string | vscode.TreeItemLabel;
|
||||
resourceUri?: URI;
|
||||
iconPath?: string | URI | { light: string | URI; dark: string | URI };
|
||||
command?: vscode.Command;
|
||||
contextValue?: string;
|
||||
tooltip?: string;
|
||||
|
||||
constructor(label: string, collapsibleState?: vscode.TreeItemCollapsibleState)
|
||||
constructor(label: string | vscode.TreeItemLabel, collapsibleState?: vscode.TreeItemCollapsibleState)
|
||||
constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState)
|
||||
constructor(arg1: string | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
|
||||
constructor(arg1: string | vscode.TreeItemLabel | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) {
|
||||
if (arg1 instanceof URI) {
|
||||
this.resourceUri = arg1;
|
||||
} else {
|
||||
@@ -1785,6 +1879,8 @@ export enum ConfigurationTarget {
|
||||
|
||||
export class RelativePattern implements IRelativePattern {
|
||||
base: string;
|
||||
baseFolder?: URI;
|
||||
|
||||
pattern: string;
|
||||
|
||||
constructor(base: vscode.WorkspaceFolder | string, pattern: string) {
|
||||
@@ -1798,7 +1894,13 @@ export class RelativePattern implements IRelativePattern {
|
||||
throw illegalArgument('pattern');
|
||||
}
|
||||
|
||||
this.base = typeof base === 'string' ? base : base.uri.fsPath;
|
||||
if (typeof base === 'string') {
|
||||
this.base = base;
|
||||
} else {
|
||||
this.baseFolder = base.uri;
|
||||
this.base = base.uri.fsPath;
|
||||
}
|
||||
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@@ -1809,6 +1911,8 @@ export class RelativePattern implements IRelativePattern {
|
||||
|
||||
export class Breakpoint {
|
||||
|
||||
private _id: string | undefined;
|
||||
|
||||
readonly enabled: boolean;
|
||||
readonly condition?: string;
|
||||
readonly hitCondition?: string;
|
||||
@@ -1826,6 +1930,13 @@ export class Breakpoint {
|
||||
this.logMessage = logMessage;
|
||||
}
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
if (!this._id) {
|
||||
this._id = generateUuid();
|
||||
}
|
||||
return this._id;
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceBreakpoint extends Breakpoint {
|
||||
@@ -1857,10 +1968,31 @@ export class FunctionBreakpoint extends Breakpoint {
|
||||
export class DebugAdapterExecutable implements vscode.DebugAdapterExecutable {
|
||||
readonly command: string;
|
||||
readonly args: string[];
|
||||
readonly options?: vscode.DebugAdapterExecutableOptions;
|
||||
|
||||
constructor(command: string, args?: string[]) {
|
||||
constructor(command: string, args: string[], options?: vscode.DebugAdapterExecutableOptions) {
|
||||
this.command = command;
|
||||
this.args = args;
|
||||
this.args = args || [];
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
export class DebugAdapterServer implements vscode.DebugAdapterServer {
|
||||
readonly port: number;
|
||||
readonly host?: string;
|
||||
|
||||
constructor(port: number, host?: string) {
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
export class DebugAdapterImplementation implements vscode.DebugAdapterImplementation {
|
||||
readonly implementation: any;
|
||||
|
||||
constructor(transport: any) {
|
||||
this.implementation = transport;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { MainContext, IMainContext, ExtHostUrlsShape, MainThreadUrlsShape } from './extHost.protocol';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export class ExtHostUrls implements ExtHostUrlsShape {
|
||||
@@ -42,16 +40,18 @@ export class ExtHostUrls implements ExtHostUrlsShape {
|
||||
});
|
||||
}
|
||||
|
||||
$handleExternalUri(handle: number, uri: UriComponents): TPromise<void> {
|
||||
$handleExternalUri(handle: number, uri: UriComponents): Thenable<void> {
|
||||
const handler = this.handlers.get(handle);
|
||||
|
||||
if (!handler) {
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
try {
|
||||
handler.handleUri(URI.revive(uri));
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
}
|
||||
|
||||
asWinJsPromise(_ => handler.handleUri(URI.revive(uri)))
|
||||
.done(null, onUnexpectedError);
|
||||
|
||||
return TPromise.as(null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/shared/editor';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState } from './extHost.protocol';
|
||||
import { Disposable } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
@@ -239,7 +239,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
public createWebview(
|
||||
extensionLocation: URI,
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean },
|
||||
@@ -252,7 +252,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
};
|
||||
|
||||
const handle = ExtHostWebviews.newHandle();
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, options, extensionLocation);
|
||||
this._proxy.$createWebviewPanel(handle, viewType, title, webviewShowOptions, options, extension.id, extension.extensionLocation);
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options);
|
||||
const panel = new ExtHostWebviewPanel(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
@@ -292,14 +292,16 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
newState: WebviewPanelViewState
|
||||
): void {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (panel) {
|
||||
const viewColumn = typeConverters.ViewColumn.to(newState.position);
|
||||
if (panel.active !== newState.active || panel.visible !== newState.visible || panel.viewColumn !== viewColumn) {
|
||||
panel._setActive(newState.active);
|
||||
panel._setVisible(newState.visible);
|
||||
panel._setViewColumn(viewColumn);
|
||||
panel._onDidChangeViewStateEmitter.fire({ webviewPanel: panel });
|
||||
}
|
||||
if (!panel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewColumn = typeConverters.ViewColumn.to(newState.position);
|
||||
if (panel.active !== newState.active || panel.visible !== newState.visible || panel.viewColumn !== viewColumn) {
|
||||
panel._setActive(newState.active);
|
||||
panel._setVisible(newState.visible);
|
||||
panel._setViewColumn(viewColumn);
|
||||
panel._onDidChangeViewStateEmitter.fire({ webviewPanel: panel });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +311,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
panel.dispose();
|
||||
this._webviewPanels.delete(handle);
|
||||
}
|
||||
return TPromise.as(void 0);
|
||||
return Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
$deserializeWebviewPanel(
|
||||
@@ -322,7 +324,7 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
|
||||
): Thenable<void> {
|
||||
const serializer = this._serializers.get(viewType);
|
||||
if (!serializer) {
|
||||
return TPromise.wrapError(new Error(`No serializer found for '${viewType}'`));
|
||||
return Promise.reject(new Error(`No serializer found for '${viewType}'`));
|
||||
}
|
||||
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, options);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* 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 { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext } from './extHost.protocol';
|
||||
|
||||
@@ -2,24 +2,25 @@
|
||||
* 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 { posix, relative, join } from 'path';
|
||||
import { delta as arrayDelta } from 'vs/base/common/arrays';
|
||||
import { join, relative } from 'path';
|
||||
import { delta as arrayDelta, mapArrayOrNot } from 'vs/base/common/arrays';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { Counter } from 'vs/base/common/numbers';
|
||||
import { normalize } from 'vs/base/common/paths';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { basenameOrAuthority, isEqual } from 'vs/base/common/resources';
|
||||
import { basenameOrAuthority, dirname, isEqual } from 'vs/base/common/resources';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IQueryOptions, IRawFileMatch2 } from 'vs/platform/search/common/search';
|
||||
import { IRawFileMatch2, resultIsMatch } from 'vs/platform/search/common/search';
|
||||
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { Range } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { Range, RelativePattern } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/parts/search/common/queryBuilder';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostWorkspaceShape, IMainContext, IWorkspaceData, MainContext, MainThreadMessageServiceShape, MainThreadWorkspaceShape } from './extHost.protocol';
|
||||
@@ -107,8 +108,8 @@ class ExtHostWorkspaceImpl extends Workspace {
|
||||
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
|
||||
private readonly _structure = TernarySearchTree.forPaths<vscode.WorkspaceFolder>();
|
||||
|
||||
private constructor(id: string, name: string, folders: vscode.WorkspaceFolder[]) {
|
||||
super(id, name, folders.map(f => new WorkspaceFolder(f)));
|
||||
private constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[]) {
|
||||
super(id, folders.map(f => new WorkspaceFolder(f)));
|
||||
|
||||
// setup the workspace folder data structure
|
||||
folders.forEach(folder => {
|
||||
@@ -117,6 +118,10 @@ class ExtHostWorkspaceImpl extends Workspace {
|
||||
});
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get workspaceFolders(): vscode.WorkspaceFolder[] {
|
||||
return this._workspaceFolders.slice(0);
|
||||
}
|
||||
@@ -124,7 +129,7 @@ class ExtHostWorkspaceImpl extends Workspace {
|
||||
getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder {
|
||||
if (resolveParent && this._structure.get(uri.toString())) {
|
||||
// `uri` is a workspace folder so we check for its parent
|
||||
uri = uri.with({ path: posix.dirname(uri.path) });
|
||||
uri = dirname(uri);
|
||||
}
|
||||
return this._structure.findSubstr(uri.toString());
|
||||
}
|
||||
@@ -136,8 +141,6 @@ class ExtHostWorkspaceImpl extends Workspace {
|
||||
|
||||
export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
|
||||
private static _requestIdPool = 0;
|
||||
|
||||
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
|
||||
private readonly _proxy: MainThreadWorkspaceShape;
|
||||
|
||||
@@ -148,12 +151,13 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
|
||||
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
|
||||
|
||||
private readonly _activeSearchCallbacks = [];
|
||||
private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
data: IWorkspaceData,
|
||||
private _logService: ILogService
|
||||
private _logService: ILogService,
|
||||
private _requestIdProvider: Counter
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
this._messageService = mainContext.getProxy(MainContext.MainThreadMessageService);
|
||||
@@ -166,6 +170,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
return this._actualWorkspace;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this._actualWorkspace ? this._actualWorkspace.name : undefined;
|
||||
}
|
||||
|
||||
private get _actualWorkspace(): ExtHostWorkspaceImpl {
|
||||
return this._unconfirmedWorkspace || this._confirmedWorkspace;
|
||||
}
|
||||
@@ -329,28 +337,27 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
this._unconfirmedWorkspace = undefined;
|
||||
|
||||
// Events
|
||||
// {{SQL CARBON EDIT}} - fix build break Argument of type 'Readonly<...
|
||||
this._onDidChangeWorkspace.fire({
|
||||
added: added,
|
||||
removed: removed
|
||||
});
|
||||
this._onDidChangeWorkspace.fire(Object.freeze({
|
||||
added,
|
||||
removed
|
||||
}));
|
||||
}
|
||||
|
||||
// --- search ---
|
||||
|
||||
findFiles(include: vscode.GlobPattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: string, token?: vscode.CancellationToken): Thenable<vscode.Uri[]> {
|
||||
findFiles(include: string | RelativePattern, exclude: vscode.GlobPattern, maxResults: number, extensionId: string, token: vscode.CancellationToken = CancellationToken.None): Thenable<vscode.Uri[]> {
|
||||
this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId}, entryPoint: findFiles`);
|
||||
|
||||
const requestId = ExtHostWorkspace._requestIdPool++;
|
||||
|
||||
let includePattern: string;
|
||||
let includeFolder: string;
|
||||
let includeFolder: URI;
|
||||
if (include) {
|
||||
if (typeof include === 'string') {
|
||||
includePattern = include;
|
||||
} else {
|
||||
includePattern = include.pattern;
|
||||
includeFolder = include.base;
|
||||
|
||||
// include.base must be an absolute path
|
||||
includeFolder = include.baseFolder || URI.file(include.base);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,17 +372,18 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
}
|
||||
}
|
||||
|
||||
const result = this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, requestId);
|
||||
if (token) {
|
||||
token.onCancellationRequested(() => this._proxy.$cancelSearch(requestId));
|
||||
if (token && token.isCancellationRequested) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return result.then(data => Array.isArray(data) ? data.map(URI.revive) : []);
|
||||
|
||||
return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token)
|
||||
.then(data => Array.isArray(data) ? data.map(URI.revive) : []);
|
||||
}
|
||||
|
||||
findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: string, token?: vscode.CancellationToken) {
|
||||
findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: string, token: vscode.CancellationToken = CancellationToken.None): Thenable<vscode.TextSearchComplete> {
|
||||
this._logService.trace(`extHostWorkspace#findTextInFiles: textSearch, extension: ${extensionId}, entryPoint: findTextInFiles`);
|
||||
|
||||
const requestId = ExtHostWorkspace._requestIdPool++;
|
||||
const requestId = this._requestIdProvider.getNext();
|
||||
|
||||
const globPatternToString = (pattern: vscode.GlobPattern | string) => {
|
||||
if (typeof pattern === 'string') {
|
||||
@@ -385,12 +393,23 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
return join(pattern.base, pattern.pattern);
|
||||
};
|
||||
|
||||
const queryOptions: IQueryOptions = {
|
||||
const previewOptions: vscode.TextSearchPreviewOptions = typeof options.previewOptions === 'undefined' ?
|
||||
{
|
||||
matchLines: 100,
|
||||
charsPerLine: 10000
|
||||
} :
|
||||
options.previewOptions;
|
||||
|
||||
const queryOptions: ITextQueryBuilderOptions = {
|
||||
ignoreSymlinks: typeof options.followSymlinks === 'boolean' ? !options.followSymlinks : undefined,
|
||||
disregardIgnoreFiles: typeof options.useIgnoreFiles === 'boolean' ? !options.useIgnoreFiles : undefined,
|
||||
disregardGlobalIgnoreFiles: typeof options.useGlobalIgnoreFiles === 'boolean' ? !options.useGlobalIgnoreFiles : undefined,
|
||||
disregardExcludeSettings: options.exclude === null,
|
||||
fileEncoding: options.encoding,
|
||||
maxResults: options.maxResults,
|
||||
previewOptions,
|
||||
afterContext: options.afterContext,
|
||||
beforeContext: options.beforeContext,
|
||||
|
||||
includePattern: options.include && globPatternToString(options.include),
|
||||
excludePattern: options.exclude && globPatternToString(options.exclude)
|
||||
@@ -403,33 +422,42 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
return;
|
||||
}
|
||||
|
||||
p.lineMatches.forEach(lineMatch => {
|
||||
lineMatch.offsetAndLengths.forEach(offsetAndLength => {
|
||||
const range = new Range(lineMatch.lineNumber, offsetAndLength[0], lineMatch.lineNumber, offsetAndLength[0] + offsetAndLength[1]);
|
||||
callback({
|
||||
uri: URI.revive(p.resource),
|
||||
preview: { text: lineMatch.preview, match: range },
|
||||
range
|
||||
const uri = URI.revive(p.resource);
|
||||
p.results.forEach(result => {
|
||||
if (resultIsMatch(result)) {
|
||||
callback(<vscode.TextSearchMatch>{
|
||||
uri,
|
||||
preview: {
|
||||
text: result.preview.text,
|
||||
matches: mapArrayOrNot(
|
||||
result.preview.matches,
|
||||
m => new Range(m.startLineNumber, m.startColumn, m.endLineNumber, m.endColumn))
|
||||
},
|
||||
ranges: mapArrayOrNot(
|
||||
result.ranges,
|
||||
r => new Range(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn))
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback(<vscode.TextSearchContext>{
|
||||
uri,
|
||||
text: result.text,
|
||||
lineNumber: result.lineNumber
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (token) {
|
||||
token.onCancellationRequested(() => {
|
||||
isCanceled = true;
|
||||
this._proxy.$cancelSearch(requestId);
|
||||
});
|
||||
if (token.isCancellationRequested) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return this._proxy.$startTextSearch(query, queryOptions, requestId).then(
|
||||
() => {
|
||||
delete this._activeSearchCallbacks[requestId];
|
||||
},
|
||||
err => {
|
||||
delete this._activeSearchCallbacks[requestId];
|
||||
return TPromise.wrapError(err);
|
||||
});
|
||||
return this._proxy.$startTextSearch(query, queryOptions, requestId, token).then(result => {
|
||||
delete this._activeSearchCallbacks[requestId];
|
||||
return result;
|
||||
}, err => {
|
||||
delete this._activeSearchCallbacks[requestId];
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
$handleTextSearchResult(result: IRawFileMatch2, requestId: number): void {
|
||||
@@ -441,4 +469,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape {
|
||||
saveAll(includeUntitled?: boolean): Thenable<boolean> {
|
||||
return this._proxy.$saveAll(includeUntitled);
|
||||
}
|
||||
|
||||
resolveProxy(url: string): Thenable<string> {
|
||||
return this._proxy.$resolveProxy(url);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user