Keep the fix small, keep ext host side command

This commit is contained in:
Johannes Rieken
2015-11-20 14:49:04 +01:00
parent b4c961cfe1
commit 75750e3915
5 changed files with 20 additions and 466 deletions

View File

@@ -18,7 +18,6 @@ import {PluginHostStatusBar} from 'vs/workbench/api/browser/pluginHostStatusBar'
import {PluginHostCommands} from 'vs/workbench/api/common/pluginHostCommands';
import {ExtHostOutputService} from 'vs/workbench/api/browser/extHostOutputService';
import {LanguageFeatures} from 'vs/workbench/api/common/languageFeatures';
import {ExtHostLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {PluginHostMessageService} from 'vs/workbench/api/common/pluginHostMessageService';
import {PluginHostTelemetryService} from 'vs/workbench/api/common/pluginHostTelemetry';
import {PluginHostEditors} from 'vs/workbench/api/common/pluginHostEditors';
@@ -252,7 +251,6 @@ export class PluginHostAPIImplementation {
const languages = new ExtHostLanguages(this._threadService);
const pluginHostDiagnostics = new PluginHostDiagnostics(this._threadService);
const features = LanguageFeatures.createExtensionHostInstances(this._threadService);
const languageFeatures = this._threadService.getRemotable(ExtHostLanguageFeatures);
this.languages = {
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
@@ -268,7 +266,7 @@ export class PluginHostAPIImplementation {
return features.codeActions.register(selector, provider);
},
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return languageFeatures.registerCodeLensProvider(selector, provider);
return features.codeLens.register(selector, provider);
},
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
return features.definition.register(selector, provider);
@@ -286,7 +284,7 @@ export class PluginHostAPIImplementation {
return features.rename.register(selector, provider);
},
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
return languageFeatures.registerDocumentSymbolProvider(selector, provider);
return features.documentSymbols.register(selector, provider);
},
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
return features.workspaceSymbols.register(provider);

View File

@@ -1,303 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import Event, {Emitter} from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import {TPromise} from 'vs/base/common/winjs.base';
import {sequence} from 'vs/base/common/async';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import * as vscode from 'vscode';
import * as TypeConverters from 'vs/workbench/api/common/pluginHostTypeConverters';
import {Position, Range, SymbolKind, DocumentHighlightKind, Disposable, Diagnostic, DiagnosticSeverity, Location, SignatureHelp, CompletionItemKind} from 'vs/workbench/api/common/pluginHostTypes';
import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {CancellationTokenSource} from 'vs/base/common/cancellation';
import {PluginHostModelService} from 'vs/workbench/api/common/pluginHostDocuments';
import {IMarkerService, IMarker} from 'vs/platform/markers/common/markers';
import {PluginHostCommands, MainThreadCommands} from 'vs/workbench/api/common/pluginHostCommands';
import DeclarationRegistry from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import ExtraInfoRegistry from 'vs/editor/contrib/hover/common/hover';
import DocumentHighlighterRegistry from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
import ReferenceSearchRegistry from 'vs/editor/contrib/referenceSearch/common/referenceSearch';
import QuickFixRegistry from 'vs/editor/contrib/quickFix/common/quickFix';
import QuickOutlineRegistry, {IOutlineEntry, IOutlineSupport} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import LanguageFeatureRegistry from 'vs/editor/common/modes/languageFeatureRegistry';
import {NavigateTypesSupportRegistry, INavigateTypesSupport, ITypeBearing} from 'vs/workbench/parts/search/common/search'
import {RenameRegistry} from 'vs/editor/contrib/rename/common/rename';
import {FormatRegistry, FormatOnTypeRegistry} from 'vs/editor/contrib/format/common/format';
import {CodeLensRegistry} from 'vs/editor/contrib/codelens/common/codelens';
import {ParameterHintsRegistry} from 'vs/editor/contrib/parameterHints/common/parameterHints';
import {SuggestRegistry} from 'vs/editor/contrib/suggest/common/suggest';
function isThenable<T>(obj: any): obj is Thenable<T> {
return obj && typeof obj['then'] === 'function';
}
function asWinJsPromise<T>(callback: (token: vscode.CancellationToken) => T | Thenable<T>): TPromise<T> {
let source = new CancellationTokenSource();
return new TPromise<T>((resolve, reject) => {
let item = callback(source.token);
if (isThenable<T>(item)) {
item.then(resolve, reject);
} else {
resolve(item);
}
}, () => {
source.cancel();
});
}
export class AbstractExtHostSupport<P> {
protected _provider: P;
protected _documents: PluginHostModelService;
constructor(provider: P, documents: PluginHostModelService) {
this._provider = provider;
this._documents = documents;
}
protected getDocument(resource: URI): vscode.TextDocument {
return this._documents.getDocument(resource);
}
}
// ---- outline support
export class ExtHostOutlineSupport extends AbstractExtHostSupport<vscode.DocumentSymbolProvider> implements IOutlineSupport {
getOutline(resource: URI): TPromise<IOutlineEntry[]>{
let doc = this.getDocument(resource);
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
if (Array.isArray(value)) {
return value.map(ExtHostOutlineSupport._convertSymbolInfo);
}
});
}
private static _convertSymbolInfo(symbol: vscode.SymbolInformation): IOutlineEntry {
return <IOutlineEntry>{
type: TypeConverters.fromSymbolKind(symbol.kind),
range: TypeConverters.fromRange(symbol.location.range),
containerLabel: symbol.containerName,
label: symbol.name,
icon: undefined,
};
}
}
// ---- code lens suppot
export class ExtHostCodeLensSupport extends AbstractExtHostSupport<vscode.CodeLensProvider> implements modes.ICodeLensSupport {
private _cache: { [resource: string]: [string, vscode.CodeLens][] } = Object.create(null);
private _providerCanResolveLens: boolean;
constructor(provider: vscode.CodeLensProvider, documents: PluginHostModelService) {
super(provider, documents);
this._providerCanResolveLens = typeof provider.resolveCodeLens === 'function';
}
findCodeLensSymbols(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
delete this._cache[resource.toString()];
let doc = this.getDocument(resource);
return asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(value => {
if (!Array.isArray(value)) {
return;
}
let result: modes.ICodeLensSymbol[] = [];
for (let i = 0; i < value.length; i++) {
let lens = value[i];
if (!this._providerCanResolveLens && !lens.isResolved) {
lens.command = {
title: '<<Lens has NO command and provider does NOT implement resolveCodeLens>>',
command: 'missing'
};
}
let id = 'code_lense_#' + i;
let key = resource.toString();
if (i === 0) {
this._cache[key] = [];
}
this._cache[key].push([id, lens]);
result.push({
id,
range: TypeConverters.fromRange(lens.range)
});
}
return result;
});
}
resolveCodeLensSymbol(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICommand> {
let lens: vscode.CodeLens;
let tuples = this._cache[resource.toString()];
if (tuples) {
for (let tuple of tuples) {
if (tuple[0] === symbol.id) {
lens = tuple[1];
}
}
}
if (!lens) {
return;
}
let resolve: TPromise<vscode.CodeLens>;
if (typeof this._provider.resolveCodeLens !== 'function') {
resolve = TPromise.as(lens);
} else {
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
}
return resolve.then(newLens => {
lens = newLens || lens;
if (lens.command) {
return {
id: lens.command.command,
title: lens.command.title,
arguments: lens.command.arguments
}
}
});
}
}
export type LanguageSupport = ExtHostOutlineSupport | ExtHostCodeLensSupport;
@Remotable.PluginHostContext('ExtHostLanguageFeatures')
export class ExtHostLanguageFeatures {
protected _provider: { [handle: number]: LanguageSupport } = Object.create(null);
protected _proxy: MainThreadLanguageFeatures;
protected _documents: PluginHostModelService;
private _handlePool = 0;
constructor( @IThreadService threadService: IThreadService) {
this._proxy = threadService.getRemotable(MainThreadLanguageFeatures);
this._documents = threadService.getRemotable(PluginHostModelService);
}
// --- outline aka document symbols
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider): vscode.Disposable {
const handle = this._nextHandle();
this._provider[handle] = new ExtHostOutlineSupport(provider, this._documents);
this._proxy.$registerOutlineSupport(handle, selector);
return this._createDisposable(handle);
}
$getOutline(handle: number, resource: URI): TPromise<IOutlineEntry[]> {
let provider = this._provider[handle];
if (provider instanceof ExtHostOutlineSupport) {
return provider.getOutline(resource);
} else {
return this._missingProvider();
}
}
// --- code lens
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
const handle = this._nextHandle();
this._provider[handle] = new ExtHostCodeLensSupport(provider, this._documents);
this._proxy.$registerCodeLensSupport(handle, selector);
return this._createDisposable(handle);
}
$findCodeLensSymbols(handle: number, resource: URI): TPromise<modes.ICodeLensSymbol[]> {
let provider = this._provider[handle];
if (provider instanceof ExtHostCodeLensSupport) {
return provider.findCodeLensSymbols(resource);
} else {
return this._missingProvider();
}
}
$resolveCodeLensSymbol(handle: number, resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICommand> {
let provider = this._provider[handle];
if (provider instanceof ExtHostCodeLensSupport) {
return provider.resolveCodeLensSymbol(resource, symbol);
} else {
return this._missingProvider();
}
}
// ---- utils
private _nextHandle(): number {
return this._handlePool++;
}
private _createDisposable(handle: number): vscode.Disposable {
return new Disposable(() => {
delete this._provider[handle];
this._proxy.$unregister(handle);
});
}
private _missingProvider():TPromise<any> {
return TPromise.wrapError<any>('missing provider');
}
}
@Remotable.MainContext('MainThreadLanguageFeatures')
export class MainThreadLanguageFeatures {
protected _disposables: { [handle: number]: IDisposable } = Object.create(null);
protected _proxy: ExtHostLanguageFeatures;
constructor( @IThreadService threadService: IThreadService) {
this._proxy = threadService.getRemotable(ExtHostLanguageFeatures);
}
$unregister(handle: number): TPromise<void> {
if (this._disposables[handle]) {
this._disposables[handle].dispose();
delete this._disposables[handle];
}
return undefined;
}
// --- outline
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise<void>{
let disposable = QuickOutlineRegistry.register(selector, <IOutlineSupport>{
getOutline: (resource: URI) => {
return this._proxy.$getOutline(handle, resource);
}
});
this._disposables[handle] = disposable;
return undefined;
}
// --- code lens
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector): TPromise<void> {
let disposable = CodeLensRegistry.register(selector, <modes.ICodeLensSupport>{
findCodeLensSymbols:(resource: URI) => {
return this._proxy.$findCodeLensSymbols(handle, resource);
},
resolveCodeLensSymbol:(resource: URI, symbol) => {
return this._proxy.$resolveCodeLensSymbol(handle, resource, symbol);
}
});
return undefined;
}
}

View File

@@ -58,8 +58,8 @@ export abstract class AbstractMainThreadFeature<T> {
private _id: string;
protected _commands: PluginHostCommands;
protected _handlePool = 0;
protected _disposable: { [handle: number]: IDisposable } = Object.create(null);
protected _refCount = 0;
protected _disposable: IDisposable;
protected _registry: LanguageFeatureRegistry<T>;
constructor(id: string, registry: LanguageFeatureRegistry<T>, @IThreadService threadService: IThreadService) {
@@ -72,16 +72,16 @@ export abstract class AbstractMainThreadFeature<T> {
return TPromise.as(this._id);
}
_register(selector: vscode.DocumentSelector): TPromise<number> {
const handle = this._handlePool++;
this._disposable[handle] = this._registry.register(selector, <any> this);
return TPromise.as(handle);
_register(selector: vscode.DocumentSelector): TPromise<any> {
if (this._refCount++ === 0) {
this._disposable = this._registry.register(selector, <any> this);
}
return undefined;
}
_unregister(handle: number): TPromise<any> {
if (this._disposable[handle]) {
this._disposable[handle].dispose();
delete this._disposable[handle];
_unregister(): TPromise<any> {
if (--this._refCount === 0) {
this._disposable.dispose();
}
return undefined;
}
@@ -112,11 +112,11 @@ export abstract class AbstractExtensionHostFeature<T, P extends AbstractMainThre
register(selector: vscode.DocumentSelector, provider: T): vscode.Disposable {
let disposable = this._registry.register(selector, provider);
let handle = this._proxy._register(selector);
let registered = this._proxy._register(selector);
return new Disposable(() => {
disposable.dispose(); // remove locally
handle.then(value => this._proxy._unregister(value));
registered.then(() => this._proxy._unregister());
});
}
@@ -721,11 +721,11 @@ export class ExtHostFormatOnType extends AbstractExtensionHostFeature<FormatOnTy
register(selector: vscode.DocumentSelector, provider: FormatOnTypeEntry): vscode.Disposable {
let disposable = this._registry.register(selector, provider);
let handle = this._proxy._register(selector, provider.triggerCharacters);
let registered = this._proxy._register(selector, provider.triggerCharacters);
return new Disposable(() => {
disposable.dispose();
handle.then(value => this._proxy._unregister(value));
registered.then(() => this._proxy._unregister());
});
}
@@ -792,11 +792,11 @@ export class ExtHostSignatureHelp extends AbstractExtensionHostFeature<Signature
register(selector: vscode.DocumentSelector, entry: SignatureHelpEntry): vscode.Disposable {
let disposable = this._registry.register(selector, entry);
let handle = this._proxy._register(selector, entry.triggerCharacters);
let registered = this._proxy._register(selector, entry.triggerCharacters);
return new Disposable(() => {
disposable.dispose();
handle.then(value => this._proxy._unregister(value));
registered.then(() => this._proxy._unregister());
});
}
@@ -908,10 +908,10 @@ export class ExtHostCompletions extends AbstractExtensionHostFeature<CompletionI
register(selector: vscode.DocumentSelector, entry: CompletionItemEnty): vscode.Disposable {
let disposable = this._registry.register(selector, entry);
let handle = this._proxy._register(selector, entry.triggerCharacters);
let registered = this._proxy._register(selector, entry.triggerCharacters);
return new Disposable(() => {
disposable.dispose();
handle.then(value => this._proxy._unregister(value));
registered.then(() => this._proxy._unregister());
});
}