diff --git a/extensions/typescript-language-features/src/languageFeatures/inlineHints.ts b/extensions/typescript-language-features/src/languageFeatures/inlineHints.ts index 4f10c8c6975..66668b254c0 100644 --- a/extensions/typescript-language-features/src/languageFeatures/inlineHints.ts +++ b/extensions/typescript-language-features/src/languageFeatures/inlineHints.ts @@ -14,14 +14,17 @@ class TypeScriptInlineHintsProvider implements vscode.InlineHintsProvider { private readonly client: ITypeScriptServiceClient ) { } - async provideInlineHints(model: vscode.TextDocument, token: vscode.CancellationToken): Promise { + async provideInlineHints(model: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): Promise { const filepath = this.client.toOpenedFilePath(model); if (!filepath) { return []; } + const start = model.offsetAt(range.start); + const length = model.offsetAt(range.end) - start; + try { - const response = await this.client.execute('provideInlineHints', { file: filepath }, token); + const response = await this.client.execute('provideInlineHints', { file: filepath, start, length }, token); if (response.type !== 'response' || !response.success || !response.body) { return []; } diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 64358348349..07d0f0dfd11 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -18,8 +18,20 @@ export namespace Experimental { ProvideInlineHints = 'ProvideInlineHints' } - export interface ProvideInlineHintsRequest extends Proto.FileRequest { + export interface ProvideInlineHintsArgs extends Proto.FileRequestArgs { + /** + * Start position of the span. + */ + start: number; + /** + * Length of the span. + */ + length: number; + } + + export interface ProvideInlineHintsRequest extends Proto.Request { command: CommandTypes.ProvideInlineHints; + arguments: ProvideInlineHintsArgs; } interface HintItem { @@ -87,7 +99,7 @@ interface StandardTsServerRequests { 'prepareCallHierarchy': [Proto.FileLocationRequestArgs, Proto.PrepareCallHierarchyResponse]; 'provideCallHierarchyIncomingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyIncomingCallsResponse]; 'provideCallHierarchyOutgoingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyOutgoingCallsResponse]; - 'provideInlineHints': [Proto.FileRequestArgs, Experimental.ProvideInlineHintsResponse]; + 'provideInlineHints': [Experimental.ProvideInlineHintsArgs, Experimental.ProvideInlineHintsResponse]; } interface NoResponseTsServerRequests { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index a0132bd7498..f4b5f14b9da 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1665,7 +1665,7 @@ export interface InlineHint { } export interface InlineHintsProvider { - provideInlineHints(model: model.ITextModel, token: CancellationToken): ProviderResult; + provideInlineHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult; } export interface SemanticTokensLegend { diff --git a/src/vs/editor/contrib/inlineHints/inlineHintsController.ts b/src/vs/editor/contrib/inlineHints/inlineHintsController.ts index 2e89fec5a00..582f129af78 100644 --- a/src/vs/editor/contrib/inlineHints/inlineHintsController.ts +++ b/src/vs/editor/contrib/inlineHints/inlineHintsController.ts @@ -19,6 +19,7 @@ import { flatten } from 'vs/base/common/arrays'; import { inlineHintForeground, inlineHintBackground } from 'vs/platform/theme/common/colorRegistry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { Range } from 'vs/editor/common/core/range'; const MAX_DECORATORS = 500; @@ -27,15 +28,14 @@ export interface InlineHintsData { provider: InlineHintsProvider; } -export function getSignatures(model: ITextModel, token: CancellationToken): Promise { +export function getSignatures(model: ITextModel, ranges: Range[], token: CancellationToken): Promise { const datas: InlineHintsData[] = []; const providers = InlineHintsProviderRegistry.ordered(model).reverse(); - const promises = providers.map(provider => Promise.resolve(provider.provideInlineHints(model, token)).then(result => { + const promises = flatten(providers.map(provider => ranges.map(range => Promise.resolve(provider.provideInlineHints(model, range, token)).then(result => { if (result) { datas.push({ list: result, provider }); - } - })); + })))); return Promise.all(promises).then(() => datas); } @@ -51,9 +51,9 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi private _timeoutTimer: TimeoutTimer | null; private _decorationsIds: string[] = []; - private _labelDatas = new Map(); + private _hintsDatas = new Map(); - private _labelDecoratorIds: string[] = []; + private _hintsDecoratorIds: string[] = []; private readonly _decorationsTypes = new Set(); private _isEnabled: boolean; @@ -80,6 +80,9 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi } } })); + this._register(_editor.onDidScrollChange(() => { + this._onModelChanged(); + })) this._timeoutTimer = null; this._computePromise = null; @@ -137,11 +140,13 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi if (!model) { return Promise.resolve([]); } - return getSignatures(model, token); + + const visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow(); + return getSignatures(model, visibleRanges, token); }); - this._computePromise.then((labelData) => { - this._updateDecorations(labelData); - this._updateLabelDecorators(labelData); + this._computePromise.then((hintsData) => { + this._updateDecorations(hintsData); + this._updateHintsDecorators(hintsData); this._computePromise = null; }, onUnexpectedError); } @@ -158,14 +163,14 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi this._localToDispose.clear(); } - private _updateDecorations(labelData: InlineHintsData[]): void { - const decorations = flatten(labelData.map(labels => labels.list.map(label => { + private _updateDecorations(hintsData: InlineHintsData[]): void { + const decorations = flatten(hintsData.map(hints => hints.list.map(hint => { return { range: { - startLineNumber: label.position.lineNumber, - startColumn: label.position.column, - endLineNumber: label.position.lineNumber, - endColumn: label.position.column + startLineNumber: hint.position.lineNumber, + startColumn: hint.position.column, + endLineNumber: hint.position.lineNumber, + endColumn: hint.position.column }, options: ModelDecorationOptions.EMPTY }; @@ -173,21 +178,21 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, decorations); - this._labelDatas = new Map(); - this._decorationsIds.forEach((id, i) => this._labelDatas.set(id, labelData[i])); + this._hintsDatas = new Map(); + this._decorationsIds.forEach((id, i) => this._hintsDatas.set(id, hintsData[i])); } - private _updateLabelDecorators(labelData: InlineHintsData[]): void { + private _updateHintsDecorators(hintsData: InlineHintsData[]): void { let decorations: IModelDeltaDecoration[] = []; let newDecorationsTypes: { [key: string]: boolean } = {}; const { fontSize } = this._getLayoutInfo(); const backgroundColor = this._themeService.getColorTheme().getColor(inlineHintBackground); const fontColor = this._themeService.getColorTheme().getColor(inlineHintForeground); - for (let i = 0; i < labelData.length; i++) { - const label = labelData[i].list; - for (let j = 0; j < label.length && decorations.length < MAX_DECORATORS; j++) { - const { text, position } = label[j]; + for (let i = 0; i < hintsData.length; i++) { + const hint = hintsData[i].list; + for (let j = 0; j < hint.length && decorations.length < MAX_DECORATORS; j++) { + const { text, position } = hint[j]; const subKey = hash(text).toString(16); let key = 'inlineHints-' + subKey; @@ -224,7 +229,7 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi } }); - this._labelDecoratorIds = this._editor.deltaDecorations(this._labelDecoratorIds, decorations); + this._hintsDecoratorIds = this._editor.deltaDecorations(this._hintsDecoratorIds, decorations); } private _getLayoutInfo() { @@ -234,7 +239,7 @@ export class InlineHintsDetector extends Disposable implements IEditorContributi private _removeAllDecorations(): void { this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, []); - this._labelDecoratorIds = this._editor.deltaDecorations(this._labelDecoratorIds, []); + this._hintsDecoratorIds = this._editor.deltaDecorations(this._hintsDecoratorIds, []); this._decorationsTypes.forEach(subType => { this._codeEditorService.removeDecorationType(subType); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index d50be4ff7a9..b303f446422 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -6373,7 +6373,7 @@ declare namespace monaco.languages { } export interface InlineHintsProvider { - provideInlineHints(model: editor.ITextModel, token: CancellationToken): ProviderResult; + provideInlineHints(model: editor.ITextModel, range: Range, token: CancellationToken): ProviderResult; } export interface SemanticTokensLegend { diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 12514b7d8a5..51ad8dd93aa 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3796,7 +3796,7 @@ declare module 'vscode' { * * @return A list of arguments labels or a thenable that resolves to such. */ - provideInlineHints(model: TextDocument, token: CancellationToken): ProviderResult; + provideInlineHints(model: TextDocument, range: Range, token: CancellationToken): ProviderResult; } /** diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 48fbc4032d3..2ef2c83bcea 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -501,8 +501,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerInlineHintsProvider(handle: number, selector: IDocumentFilterDto[]): void { this._registrations.set(handle, modes.InlineHintsProviderRegistry.register(selector, { - provideInlineHints: async (model: ITextModel, token: CancellationToken): Promise => { - const result = await this._proxy.$provideInlineHints(handle, model.uri, token); + provideInlineHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise => { + const result = await this._proxy.$provideInlineHints(handle, model.uri, range, token); return result?.hints; } })); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 6caa96cc393..22a591a26e0 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1468,7 +1468,7 @@ export interface ExtHostLanguageFeaturesShape { $releaseCompletionItems(handle: number, id: number): void; $provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise; $releaseSignatureHelp(handle: number, id: number): void; - $provideInlineHints(handle: number, resource: UriComponents, token: CancellationToken): Promise + $provideInlineHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise $provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise; $releaseDocumentLinks(handle: number, id: number): void; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index f46f214ebc5..7a38d2d7038 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1070,9 +1070,9 @@ class InlineHintsAdapter { private readonly _provider: vscode.InlineHintsProvider, ) { } - provideInlineHints(resource: URI, token: CancellationToken): Promise { + provideInlineHints(resource: URI, range: Range, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); - return asPromise(() => this._provider.provideInlineHints(doc, token)).then(value => { + return asPromise(() => this._provider.provideInlineHints(doc, range, token)).then(value => { if (value) { const id = this._cache.add([value]); return { hints: value.map(typeConvert.InlineHint.from), id }; @@ -1798,8 +1798,8 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- inline hints - $provideInlineHints(handle: number, resource: UriComponents, token: CancellationToken): Promise { - return this._withAdapter(handle, InlineHintsAdapter, adapter => adapter.provideInlineHints(URI.revive(resource), token), undefined); + $provideInlineHints(handle: number, resource: UriComponents, range: Range, token: CancellationToken): Promise { + return this._withAdapter(handle, InlineHintsAdapter, adapter => adapter.provideInlineHints(URI.revive(resource), range, token), undefined); } // --- links