api proposal, add call hierarchy contrib

This commit is contained in:
Johannes Rieken
2019-03-14 16:14:43 +01:00
parent 1b66cd7fb7
commit 2f89a79efe
12 changed files with 255 additions and 4 deletions

View File

@@ -357,6 +357,10 @@ export function createApiFactory(
registerSelectionRangeProvider(selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
return extHostLanguageFeatures.registerSelectionRangeProvider(extension, selector, provider);
},
registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerCallHierarchyProvider(extension, selector, provider);
},
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
}
@@ -831,7 +835,9 @@ export function createApiFactory(
Uri: URI,
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// functions
// proposed
CallHierarchyDirection: extHostTypes.CallHierarchyDirection,
CallHierarchyItem: extHostTypes.CallHierarchyItem
};
};
}

View File

@@ -46,6 +46,7 @@ import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityReso
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IRemoteConsoleLog } from 'vs/base/node/console';
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -335,6 +336,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerDocumentColorProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerFoldingRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerSelectionRangeProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerCallHierarchyProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$setLanguageConfiguration(handle: number, languageId: string, configuration: ISerializedLanguageConfiguration): void;
}
@@ -951,6 +953,8 @@ export interface ExtHostLanguageFeaturesShape {
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<modes.SelectionRange[][]>;
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<callHierarchy.CallHierarchyItem | undefined>;
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]>;
}
export interface ExtHostQuickOpenShape {

View File

@@ -29,6 +29,8 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtHostWebview } from 'vs/workbench/api/node/extHostWebview';
import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset';
import { generateUuid } from 'vs/base/common/uuid';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { LRUCache } from 'vs/base/common/map';
// --- adapter
@@ -964,11 +966,65 @@ class SelectionRangeAdapter {
}
}
class CallHierarchyAdapter {
// todo@joh keep object (heap service, lifecycle)
private readonly _cache = new LRUCache<number, vscode.CallHierarchyItem>(1000, 0.8);
private _idPool = 0;
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.CallHierarchyItemProvider
) { }
provideCallHierarchyItem(resource: URI, pos: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
const document = this._documents.getDocument(resource);
const position = typeConvert.Position.to(pos);
return asPromise(() => this._provider.provideCallHierarchyItem(document, position, token)).then(item => {
if (!item) {
return undefined;
}
return this._fromItem(item);
});
}
resolveCallHierarchyItem(item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
return asPromise(() => this._provider.resolveCallHierarchyItem(
this._cache.get(item._id),
direction as number, token) // todo@joh proper convert
).then(data => {
if (!data) {
return [];
}
return data.map(tuple => {
return <[callHierarchy.CallHierarchyItem, modes.Location[]]>[
this._fromItem(tuple[0]),
tuple[1].map(typeConvert.location.from)
];
});
});
}
private _fromItem(item: vscode.CallHierarchyItem, _id: number = this._idPool++): callHierarchy.CallHierarchyItem {
const res = <callHierarchy.CallHierarchyItem>{
_id,
name: item.name,
detail: item.detail,
kind: typeConvert.SymbolKind.from(item.kind),
range: typeConvert.Range.from(item.range),
selectionRange: typeConvert.Range.from(item.selectionRange),
};
this._cache.set(_id, item);
return res;
}
}
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
| ColorProviderAdapter | FoldingProviderAdapter | CodeInsetAdapter | DeclarationAdapter | SelectionRangeAdapter;
| ColorProviderAdapter | FoldingProviderAdapter | CodeInsetAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter;
class AdapterData {
constructor(
@@ -1416,6 +1472,22 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, SelectionRangeAdapter, adapter => adapter.provideSelectionRanges(URI.revive(resource), positions, token));
}
// --- call hierarchy
registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable {
const handle = this._addNewAdapter(new CallHierarchyAdapter(this._documents, provider), extension);
this._proxy.$registerCallHierarchyProvider(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}
$provideCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallHierarchyItem(URI.revive(resource), position, token));
}
$resolveCallHierarchyItem(handle: number, item: callHierarchy.CallHierarchyItem, direction: callHierarchy.CallHierarchyDirection, token: CancellationToken): Promise<[callHierarchy.CallHierarchyItem, modes.Location[]][]> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.resolveCallHierarchyItem(item, direction, token));
}
// --- configuration
private static _serializeRegExp(regExp: RegExp): ISerializedRegExp {

View File

@@ -883,7 +883,6 @@ export namespace TextDocumentSaveReason {
}
}
export namespace EndOfLine {
export function from(eol: vscode.EndOfLine): EndOfLineSequence | undefined {

View File

@@ -1111,6 +1111,27 @@ export class SelectionRange {
}
export enum CallHierarchyDirection {
CallsFrom = 1,
CallsTo = 2,
}
export class CallHierarchyItem {
kind: SymbolKind;
name: string;
detail?: string;
range: Range;
selectionRange: Range;
constructor(kind: SymbolKind, name: string, detail: string | undefined = undefined, range: Range, selectionRange: Range) {
this.kind = kind;
this.name = name;
this.detail = detail;
this.range = range;
this.selectionRange = selectionRange;
}
}
@es5ClassCompat
export class CodeLens {