experiment with InlayHintLabelPart and source location as "anchor action",

https://github.com/microsoft/vscode/issues/129528
This commit is contained in:
Johannes Rieken
2022-01-07 20:38:54 +01:00
parent 9867820ed9
commit 2586299c42
13 changed files with 267 additions and 100 deletions

View File

@@ -1276,6 +1276,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// proposed api types
InlayHint: extHostTypes.InlayHint,
InlayHintLabelPart: extHostTypes.InlayHintLabelPart,
InlayHintKind: extHostTypes.InlayHintKind,
RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError,
ResolvedAuthority: extHostTypes.ResolvedAuthority,

View File

@@ -1504,7 +1504,7 @@ export interface ISignatureHelpContextDto {
export interface IInlayHintDto {
cacheId?: ChainedCacheId;
label: string;
label: string | modes.InlayHintLabelPart[];
tooltip?: string | IMarkdownString;
position: IPosition;
kind: modes.InlayHintKind;

View File

@@ -332,8 +332,8 @@ const newCommands: ApiCommand[] = [
new ApiCommand(
'vscode.executeInlayHintProvider', '_executeInlayHintProvider', 'Execute inlay hints provider',
[ApiCommandArgument.Uri, ApiCommandArgument.Range],
new ApiCommandResult<modes.InlayHint[], vscode.InlayHint[]>('A promise that resolves to an array of Inlay objects', result => {
return result.map(typeConverters.InlayHint.to);
new ApiCommandResult<modes.InlayHint[], vscode.InlayHint[]>('A promise that resolves to an array of Inlay objects', (result, args, converter) => {
return result.map(typeConverters.InlayHint.to.bind(undefined, converter));
})
),
// --- notebooks

View File

@@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { mixin } from 'vs/base/common/objects';
import type * as vscode from 'vscode';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit } from 'vs/workbench/api/common/extHostTypes';
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, InlayHintKind, Location } from 'vs/workbench/api/common/extHostTypes';
import { ISingleEditOperation } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/languages';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
@@ -1173,9 +1173,11 @@ class SignatureHelpAdapter {
class InlayHintsAdapter {
private _cache = new Cache<vscode.InlayHint>('InlayHints');
private readonly _disposables = new Map<number, DisposableStore>();
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _commands: CommandsConverter,
private readonly _provider: vscode.InlayHintsProvider,
) { }
@@ -1192,21 +1194,13 @@ class InlayHintsAdapter {
// of results as they will leak
return undefined;
}
if (typeof this._provider.resolveInlayHint !== 'function') {
// no resolve -> no caching
return { hints: hints.map(typeConvert.InlayHint.from) };
} else {
// cache links for future resolving
const pid = this._cache.add(hints);
const result: extHostProtocol.IInlayHintsDto = { hints: [], cacheId: pid };
for (let i = 0; i < hints.length; i++) {
const dto: extHostProtocol.IInlayHintDto = typeConvert.InlayHint.from(hints[i]);
dto.cacheId = [pid, i];
result.hints.push(dto);
}
return result;
const pid = this._cache.add(hints);
this._disposables.set(pid, new DisposableStore());
const result: extHostProtocol.IInlayHintsDto = { hints: [], cacheId: pid };
for (let i = 0; i < hints.length; i++) {
result.hints.push(this._convertInlayHint(hints[i], [pid, i]));
}
return result;
}
async resolveInlayHint(id: extHostProtocol.ChainedCacheId, token: CancellationToken) {
@@ -1221,12 +1215,51 @@ class InlayHintsAdapter {
if (!hint) {
return undefined;
}
return typeConvert.InlayHint.from(hint);
if (token.isCancellationRequested) {
return undefined;
}
return this._convertInlayHint(hint, id);
}
releaseHints(id: number): any {
this._disposables.get(id)?.dispose();
this._disposables.delete(id);
this._cache.delete(id);
}
private _convertInlayHint(hint: vscode.InlayHint, id: extHostProtocol.ChainedCacheId): extHostProtocol.IInlayHintDto {
const disposables = this._disposables.get(id[0]);
if (!disposables) {
throw Error('DisposableStore is missing...');
}
const result: extHostProtocol.IInlayHintDto = {
label: '', // fill-in below
cacheId: id,
tooltip: hint.tooltip && typeConvert.MarkdownString.from(hint.tooltip),
position: typeConvert.Position.from(hint.position),
kind: typeConvert.InlayHintKind.from(hint.kind ?? InlayHintKind.Other),
whitespaceBefore: hint.whitespaceBefore,
whitespaceAfter: hint.whitespaceAfter,
};
if (typeof hint.label === 'string') {
result.label = hint.label;
} else {
result.label = hint.label.map(part => {
let r: modes.InlayHintLabelPart = { label: part.label };
r.collapsible = part.collapsible;
if (Location.isLocation(part.action)) {
r.action = typeConvert.location.from(part.action);
} else if (part.action) {
r.action = this._commands.toInternal(part.action, disposables);
}
return r;
});
}
return result;
}
}
class LinkProviderAdapter {
@@ -2030,7 +2063,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
registerInlayHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable {
const eventHandle = typeof provider.onDidChangeInlayHints === 'function' ? this._nextHandle() : undefined;
const handle = this._addNewAdapter(new InlayHintsAdapter(this._documents, provider), extension);
const handle = this._addNewAdapter(new InlayHintsAdapter(this._documents, this._commands.converter, provider), extension);
this._proxy.$registerInlayHintsProvider(handle, this._transformDocumentSelector(selector), typeof provider.resolveInlayHint === 'function', eventHandle);
let result = this._createDisposable(handle);

View File

@@ -1152,20 +1152,9 @@ export namespace SignatureHelp {
export namespace InlayHint {
export function from(hint: vscode.InlayHint): modes.InlayHint {
return {
label: hint.text,
tooltip: hint.tooltip && MarkdownString.from(hint.tooltip),
position: Position.from(hint.position),
kind: InlayHintKind.from(hint.kind ?? types.InlayHintKind.Other),
whitespaceBefore: hint.whitespaceBefore,
whitespaceAfter: hint.whitespaceAfter,
};
}
export function to(hint: modes.InlayHint): vscode.InlayHint {
export function to(converter: CommandsConverter, hint: modes.InlayHint): vscode.InlayHint {
const res = new types.InlayHint(
hint.label,
typeof hint.label === 'string' ? hint.label : hint.label.map(InlayHintLabelPart.to.bind(undefined, converter)),
Position.to(hint.position),
InlayHintKind.to(hint.kind)
);
@@ -1176,6 +1165,20 @@ export namespace InlayHint {
}
}
export namespace InlayHintLabelPart {
export function to(converter: CommandsConverter, part: modes.InlayHintLabelPart): types.InlayHintLabelPart {
const result = new types.InlayHintLabelPart(part.label);
result.collapsible = part.collapsible;
if (modes.Command.is(part.action)) {
result.action = converter.fromInternal(part.action);
} else if (part.action) {
result.action = location.to(part.action);
}
return result;
}
}
export namespace InlayHintKind {
export function from(kind: vscode.InlayHintKind): modes.InlayHintKind {
return kind;

View File

@@ -873,7 +873,7 @@ export enum DiagnosticSeverity {
@es5ClassCompat
export class Location {
static isLocation(thing: any): thing is Location {
static isLocation(thing: any): thing is vscode.Location {
if (thing instanceof Location) {
return true;
}
@@ -1421,16 +1421,29 @@ export enum InlayHintKind {
}
@es5ClassCompat
export class InlayHint {
text: string;
export class InlayHintLabelPart {
label: string;
collapsible?: boolean;
action?: vscode.Command | Location; // invokes provider
constructor(label: string) {
this.label = label;
}
toString(): string {
return this.label;
}
}
@es5ClassCompat
export class InlayHint implements vscode.InlayHint {
label: string | InlayHintLabelPart[];
tooltip?: string | vscode.MarkdownString;
position: Position;
kind?: vscode.InlayHintKind;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
constructor(text: string, position: Position, kind?: vscode.InlayHintKind) {
this.text = text;
constructor(label: string | InlayHintLabelPart[], position: Position, kind?: vscode.InlayHintKind) {
this.label = label;
this.position = position;
this.kind = kind;
}