diff --git a/src/vs/editor/contrib/inlineHints/inlineHintsController.ts b/src/vs/editor/contrib/inlineHints/inlineHintsController.ts index 9cc48a27c8c..0a5d3dd6622 100644 --- a/src/vs/editor/contrib/inlineHints/inlineHintsController.ts +++ b/src/vs/editor/contrib/inlineHints/inlineHintsController.ts @@ -21,6 +21,11 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Range } from 'vs/editor/common/core/range'; import { LanguageFeatureRequestDelays } from 'vs/editor/common/modes/languageFeatureRegistry'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { URI } from 'vs/base/common/uri'; +import { IRange } from 'vs/base/common/range'; +import { assertType } from 'vs/base/common/types'; +import { ITextModelService } from 'vs/editor/common/services/resolverService'; const MAX_DECORATORS = 500; @@ -199,3 +204,19 @@ export class InlineHintsController implements IEditorContribution { } registerEditorContribution(InlineHintsController.ID, InlineHintsController); + +CommandsRegistry.registerCommand('_executeInlineHintProvider', async (accessor, ...args: [URI, IRange]): Promise => { + + const [uri, range] = args; + assertType(URI.isUri(uri)); + assertType(Range.isIRange(range)); + + const ref = await accessor.get(ITextModelService).createModelReference(uri); + try { + const data = await getInlineHints(ref.object.textEditorModel, [Range.lift(range)], CancellationToken.None); + return flatten(data.map(item => item.list)).sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); + + } finally { + ref.dispose(); + } +}); diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 972664cdeba..94c23b401b2 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -271,6 +271,14 @@ const newCommands: ApiCommand[] = [ return []; }) ), + // --- inline hints + new ApiCommand( + 'vscode.executeInlineHintProvider', '_executeInlineHintProvider', 'Execute inline hints provider', + [ApiCommandArgument.Uri, ApiCommandArgument.Range], + new ApiCommandResult('A promise that resolves to an array of InlineHint objects', result => { + return result.map(typeConverters.InlineHint.to); + }) + ), // --- notebooks new ApiCommand( 'vscode.resolveNotebookContentProviders', '_resolveNotebookContentProvider', 'Resolve Notebook Content Providers', diff --git a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts index 47db11d1a7b..0cc30aa021e 100644 --- a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts @@ -35,6 +35,7 @@ import { NullApiDeprecationService } from 'vs/workbench/api/common/extHostApiDep import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; +import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import 'vs/editor/contrib/codeAction/codeAction'; import 'vs/editor/contrib/codelens/codelens'; @@ -48,7 +49,7 @@ import 'vs/editor/contrib/parameterHints/provideSignatureHelp'; import 'vs/editor/contrib/smartSelect/smartSelect'; import 'vs/editor/contrib/suggest/suggest'; import 'vs/editor/contrib/rename/rename'; -import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; +import 'vs/editor/contrib/inlineHints/inlineHintsController'; const defaultSelector = { scheme: 'far' }; const model: ITextModel = createTextModel( @@ -1141,6 +1142,85 @@ suite('ExtHostLanguageFeatureCommands', function () { }); }); + // --- inline hints + + test('Inline Hints, back and forth', async function () { + disposables.push(extHost.registerInlineHintsProvider(nullExtensionDescription, defaultSelector, { + provideInlineHints() { + return [new types.InlineHint('Foo', new types.Range(0, 1, 2, 3), undefined, true, false)]; + } + })); + + await rpcProtocol.sync(); + + const value = await commands.executeCommand('vscode.executeInlineHintProvider', model.uri, new types.Range(0, 0, 20, 20)); + assert.strictEqual(value.length, 1); + + const [first] = value; + assert.strictEqual(first.text, 'Foo'); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 1); + assert.strictEqual(first.range.end.line, 2); + assert.strictEqual(first.range.end.character, 3); + }); + + test('Inline Hints, merge', async function () { + disposables.push(extHost.registerInlineHintsProvider(nullExtensionDescription, defaultSelector, { + provideInlineHints() { + return [new types.InlineHint('Bar', new types.Range(10, 11, 12, 13), undefined, true, false)]; + } + })); + + disposables.push(extHost.registerInlineHintsProvider(nullExtensionDescription, defaultSelector, { + provideInlineHints() { + return [new types.InlineHint('Foo', new types.Range(0, 1, 2, 3), undefined, true, false)]; + } + })); + + await rpcProtocol.sync(); + + const value = await commands.executeCommand('vscode.executeInlineHintProvider', model.uri, new types.Range(0, 0, 20, 20)); + assert.strictEqual(value.length, 2); + + const [first, second] = value; + assert.strictEqual(first.text, 'Foo'); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 1); + assert.strictEqual(first.range.end.line, 2); + assert.strictEqual(first.range.end.character, 3); + + assert.strictEqual(second.text, 'Bar'); + assert.strictEqual(second.range.start.line, 10); + assert.strictEqual(second.range.start.character, 11); + assert.strictEqual(second.range.end.line, 12); + assert.strictEqual(second.range.end.character, 13); + }); + + test('Inline Hints, bad provider', async function () { + disposables.push(extHost.registerInlineHintsProvider(nullExtensionDescription, defaultSelector, { + provideInlineHints() { + return [new types.InlineHint('Foo', new types.Range(0, 1, 2, 3), undefined, true, false)]; + } + })); + disposables.push(extHost.registerInlineHintsProvider(nullExtensionDescription, defaultSelector, { + provideInlineHints() { + throw new Error(); + } + })); + + await rpcProtocol.sync(); + + const value = await commands.executeCommand('vscode.executeInlineHintProvider', model.uri, new types.Range(0, 0, 20, 20)); + assert.strictEqual(value.length, 1); + + const [first] = value; + assert.strictEqual(first.text, 'Foo'); + assert.strictEqual(first.range.start.line, 0); + assert.strictEqual(first.range.start.character, 1); + assert.strictEqual(first.range.end.line, 2); + assert.strictEqual(first.range.end.character, 3); + }); + // --- selection ranges test('Selection Range, back and forth', async function () {