Skip to content

Commit

Permalink
support double click gesture on inlay hints, API polish, #16221
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Feb 5, 2022
1 parent 0d74195 commit 627d465
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ class TypeScriptInlayHintsProvider extends Disposable implements vscode.InlayHin

return response.body.map(hint => {
const result = new vscode.InlayHint(
hint.text,
Position.fromLocation(hint.position),
hint.text,
hint.kind && fromProtocolInlayHintKind(hint.kind)
);
result.paddingLeft = hint.whitespaceBefore;
Expand Down
1 change: 1 addition & 0 deletions src/vs/editor/common/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,7 @@ export interface InlayHintLabelPart {
export interface InlayHint {
label: string | InlayHintLabelPart[];
tooltip?: string | IMarkdownString;
command?: Command;
position: IPosition;
kind: InlayHintKind;
paddingLeft?: boolean;
Expand Down
39 changes: 30 additions & 9 deletions src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export class InlayHintsController implements IEditorContribution {

// mouse gestures
this._sessionDisposables.add(this._installLinkGesture());
this._sessionDisposables.add(this._installDblClickGesture());
this._sessionDisposables.add(this._installContextMenu());
}

Expand Down Expand Up @@ -264,21 +265,29 @@ export class InlayHintsController implements IEditorContribution {
this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, part.location);
} else if (languages.Command.is(part.command)) {
// command -> execute it
try {
await this._commandService.executeCommand(part.command.id, ...(part.command.arguments ?? []));
} catch (err) {
this._notificationService.notify({
severity: Severity.Error,
source: label.item.provider.displayName,
message: err
});
}
await this._invokeCommand(part.command, label.item);
}
}
});
return gesture;
}

private _installDblClickGesture(): IDisposable {
return this._editor.onMouseUp(async e => {
if (e.event.detail !== 2) {
return;
}
const part = this._getInlayHintLabelPart(e);
if (!part) {
return;
}
await part.item.resolve(CancellationToken.None);
if (part.item.hint.command) {
await this._invokeCommand(part.item.hint.command, part.item);
}
});
}

private _installContextMenu(): IDisposable {
return this._editor.onContextMenu(async e => {
if (!(e.event.target instanceof HTMLElement)) {
Expand All @@ -302,6 +311,18 @@ export class InlayHintsController implements IEditorContribution {
return undefined;
}

private async _invokeCommand(command: languages.Command, item: InlayHintItem) {
try {
await this._commandService.executeCommand(command.id, ...(command.arguments ?? []));
} catch (err) {
this._notificationService.notify({
severity: Severity.Error,
source: item.provider.displayName,
message: err
});
}
}

private _cacheHintsForFastRestore(model: ITextModel): void {
const items = new Map<InlayHintItem, InlayHintItem>();
for (const [id, obj] of this._decorationsMetadata) {
Expand Down
1 change: 1 addition & 0 deletions src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6910,6 +6910,7 @@ declare namespace monaco.languages {
export interface InlayHint {
label: string | InlayHintLabelPart[];
tooltip?: string | IMarkdownString;
command?: Command;
position: IPosition;
kind: InlayHintKind;
paddingLeft?: boolean;
Expand Down
9 changes: 5 additions & 4 deletions src/vs/workbench/api/common/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ class InlayHintsAdapter {
}

private _isValidInlayHint(hint: vscode.InlayHint, range?: vscode.Range): boolean {
if (hint.label.length === 0 || Array.isArray(hint.label) && hint.label.every(part => part.label.length === 0)) {
if (hint.label.length === 0 || Array.isArray(hint.label) && hint.label.every(part => part.value.length === 0)) {
console.log('INVALID inlay hint, empty label', hint);
return false;
}
Expand All @@ -1257,7 +1257,8 @@ class InlayHintsAdapter {
const result: extHostProtocol.IInlayHintDto = {
label: '', // fill-in below
cacheId: id,
tooltip: hint.tooltip && typeConvert.MarkdownString.from(hint.tooltip),
tooltip: typeConvert.MarkdownString.fromStrict(hint.tooltip),
command: hint.command && this._commands.toInternal(hint.command, disposables),
position: typeConvert.Position.from(hint.position),
kind: typeConvert.InlayHintKind.from(hint.kind ?? InlayHintKind.Other),
paddingLeft: hint.paddingLeft,
Expand All @@ -1268,8 +1269,8 @@ class InlayHintsAdapter {
result.label = hint.label;
} else {
result.label = hint.label.map(part => {
let result: languages.InlayHintLabelPart = { label: part.label };
result.tooltip = part.tooltip && typeConvert.MarkdownString.from(part.tooltip);
let result: languages.InlayHintLabelPart = { label: part.value };
result.tooltip = typeConvert.MarkdownString.fromStrict(part.tooltip);
if (Location.isLocation(part.location)) {
result.location = typeConvert.location.from(part.location);
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/common/extHostStatusBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
color = ExtHostStatusBarEntry.ALLOWED_BACKGROUND_COLORS.get(this._backgroundColor.id);
}

const tooltip = this._tooltip ? MarkdownString.fromStrict(this._tooltip) : undefined;
const tooltip = MarkdownString.fromStrict(this._tooltip);

// Set to status bar
this.#proxy.$setEntry(this._entryId, id, name, this._text, tooltip, this._command?.internal, color,
Expand Down
9 changes: 5 additions & 4 deletions src/vs/workbench/api/common/extHostTypeConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ export namespace MarkdownString {
return result;
}

export function fromStrict(value: string | vscode.MarkdownString): undefined | string | htmlContent.IMarkdownString {
export function fromStrict(value: string | vscode.MarkdownString | undefined | null): undefined | string | htmlContent.IMarkdownString {
if (!value) {
return undefined;
}
Expand Down Expand Up @@ -1110,7 +1110,7 @@ export namespace ParameterInformation {
export function from(info: types.ParameterInformation): languages.ParameterInformation {
return {
label: info.label,
documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined
documentation: MarkdownString.fromStrict(info.documentation)
};
}
export function to(info: languages.ParameterInformation): types.ParameterInformation {
Expand All @@ -1126,7 +1126,7 @@ export namespace SignatureInformation {
export function from(info: types.SignatureInformation): languages.SignatureInformation {
return {
label: info.label,
documentation: info.documentation ? MarkdownString.fromStrict(info.documentation) : undefined,
documentation: MarkdownString.fromStrict(info.documentation),
parameters: Array.isArray(info.parameters) ? info.parameters.map(ParameterInformation.from) : [],
activeParameter: info.activeParameter,
};
Expand Down Expand Up @@ -1165,11 +1165,12 @@ export namespace InlayHint {

export function to(converter: Command.ICommandsConverter, hint: languages.InlayHint): vscode.InlayHint {
const res = new types.InlayHint(
typeof hint.label === 'string' ? hint.label : hint.label.map(InlayHintLabelPart.to.bind(undefined, converter)),
Position.to(hint.position),
typeof hint.label === 'string' ? hint.label : hint.label.map(InlayHintLabelPart.to.bind(undefined, converter)),
InlayHintKind.to(hint.kind)
);
res.tooltip = htmlContent.isMarkdownString(hint.tooltip) ? MarkdownString.to(hint.tooltip) : hint.tooltip;
res.command = hint.command && converter.fromInternal(hint.command);
res.paddingLeft = hint.paddingLeft;
res.paddingRight = hint.paddingRight;
return res;
Expand Down
11 changes: 6 additions & 5 deletions src/vs/workbench/api/common/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1432,13 +1432,13 @@ export enum InlayHintKind {
@es5ClassCompat
export class InlayHintLabelPart {

label: string;
value: string;
tooltip?: string | vscode.MarkdownString;
location?: Location;
command?: vscode.Command;

constructor(label: string) {
this.label = label;
constructor(value: string) {
this.value = value;
}
}

Expand All @@ -1451,10 +1451,11 @@ export class InlayHint implements vscode.InlayHint {
kind?: vscode.InlayHintKind;
paddingLeft?: boolean;
paddingRight?: boolean;
command?: vscode.Command;

constructor(label: string | InlayHintLabelPart[], position: Position, kind?: vscode.InlayHintKind) {
this.label = label;
constructor(position: Position, label: string | InlayHintLabelPart[], kind?: vscode.InlayHintKind) {
this.position = position;
this.label = label;
this.kind = kind;
}
}
Expand Down
30 changes: 25 additions & 5 deletions src/vs/workbench/api/test/browser/extHostApiCommands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import 'vs/editor/contrib/rename/browser/rename';
import 'vs/editor/contrib/inlayHints/browser/inlayHintsController';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
import { assertType } from 'vs/base/common/types';

function assertRejects(fn: () => Promise<any>, message: string = 'Expected rejection') {
return fn().then(() => assert.ok(false, message), _err => assert.ok(true));
Expand Down Expand Up @@ -1250,7 +1251,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('Inlay Hints, back and forth', async function () {
disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{
provideInlayHints() {
return [new types.InlayHint('Foo', new types.Position(0, 1))];
return [new types.InlayHint(new types.Position(0, 1), 'Foo')];
}
}));

Expand All @@ -1268,13 +1269,21 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('Inline Hints, merge', async function () {
disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{
provideInlayHints() {
return [new types.InlayHint('Bar', new types.Position(10, 11))];
const part = new types.InlayHintLabelPart('Bar');
part.tooltip = 'part_tooltip';
part.command = { command: 'cmd', title: 'part' };
const hint = new types.InlayHint(new types.Position(10, 11), [part]);
hint.tooltip = 'hint_tooltip';
hint.command = { command: 'cmd', title: 'hint' };
hint.paddingLeft = true;
hint.paddingRight = false;
return [hint];
}
}));

disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{
provideInlayHints() {
const hint = new types.InlayHint('Foo', new types.Position(0, 1), types.InlayHintKind.Parameter);
const hint = new types.InlayHint(new types.Position(0, 1), 'Foo', types.InlayHintKind.Parameter);
return [hint];
}
}));
Expand All @@ -1289,15 +1298,26 @@ suite('ExtHostLanguageFeatureCommands', function () {
assert.strictEqual(first.position.line, 0);
assert.strictEqual(first.position.character, 1);

assert.strictEqual(second.label, 'Bar');
assert.strictEqual(second.position.line, 10);
assert.strictEqual(second.position.character, 11);
assert.strictEqual(second.paddingLeft, true);
assert.strictEqual(second.paddingRight, false);
assert.strictEqual(second.tooltip, 'hint_tooltip');
assert.strictEqual(second.command?.command, 'cmd');
assert.strictEqual(second.command?.title, 'hint');

const label = (<types.InlayHintLabelPart[]>second.label)[0];
assertType(label instanceof types.InlayHintLabelPart);
assert.strictEqual(label.value, 'Bar');
assert.strictEqual(label.tooltip, 'part_tooltip');
assert.strictEqual(label.command?.command, 'cmd');
assert.strictEqual(label.command?.title, 'part');
});

test('Inline Hints, bad provider', async function () {
disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{
provideInlayHints() {
return [new types.InlayHint('Foo', new types.Position(0, 1))];
return [new types.InlayHint(new types.Position(0, 1), 'Foo')];
}
}));
disposables.push(extHost.registerInlayHintsProvider(nullExtensionDescription, defaultSelector, <vscode.InlayHintsProvider>{
Expand Down
Loading

0 comments on commit 627d465

Please sign in to comment.