Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Razor inlay hint and inlay hint resolve handlers #6857

Merged
merged 1 commit into from Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/lsptoolshost/razorCommands.ts
Expand Up @@ -23,6 +23,10 @@ import {
CompletionRequest,
CompletionResolveRequest,
CompletionItem,
InlayHint,
InlayHintResolveRequest,
InlayHintParams,
InlayHintRequest,
} from 'vscode-languageclient/node';
import SerializableSimplifyMethodParams from '../razor/src/simplify/serializableSimplifyMethodParams';
import { TextEdit } from 'vscode-html-languageservice';
Expand All @@ -40,6 +44,8 @@ export const provideSemanticTokensRangeCommand = 'roslyn.provideSemanticTokensRa
export const roslynSimplifyMethodCommand = 'roslyn.simplifyMethod';
export const roslynFormatNewFileCommand = 'roslyn.formatNewFile';
export const razorInitializeCommand = 'razor.initialize';
export const provideInlayHintsCommand = 'roslyn.provideInlayHints';
export const resolveInlayHintCommand = 'roslyn.resolveInlayHint';

export function registerRazorCommands(context: vscode.ExtensionContext, languageServer: RoslynLanguageServer) {
// Razor will call into us (via command) for generated file didChange/didClose notifications. We'll then forward these
Expand Down Expand Up @@ -100,6 +106,18 @@ export function registerRazorCommands(context: vscode.ExtensionContext, language
})
);

context.subscriptions.push(
vscode.commands.registerCommand(provideInlayHintsCommand, async (request: InlayHintParams) => {
return await languageServer.sendRequest(InlayHintRequest.type, request, CancellationToken.None);
})
);

context.subscriptions.push(
vscode.commands.registerCommand(resolveInlayHintCommand, async (request: InlayHint) => {
return await languageServer.sendRequest(InlayHintResolveRequest.type, request, CancellationToken.None);
})
);

context.subscriptions.push(
vscode.commands.registerCommand(provideCompletionsCommand, async (request: CompletionParams) => {
return await languageServer.sendRequest(CompletionRequest.type, request, CancellationToken.None);
Expand Down
11 changes: 11 additions & 0 deletions src/razor/src/extension.ts
Expand Up @@ -53,6 +53,8 @@ import { PlatformInformation } from '../../shared/platform';
import { RazorLanguageServerOptions } from './razorLanguageServerOptions';
import { resolveRazorLanguageServerOptions } from './razorLanguageServerOptionsResolver';
import { RazorFormatNewFileHandler } from './formatNewFile/razorFormatNewFileHandler';
import { InlayHintHandler } from './inlayHint/inlayHintHandler';
import { InlayHintResolveHandler } from './inlayHint/inlayHintResolveHandler';

// We specifically need to take a reference to a particular instance of the vscode namespace,
// otherwise providers attempt to operate on the null extension.
Expand Down Expand Up @@ -179,6 +181,13 @@ export async function activate(
logger
);
const foldingRangeHandler = new FoldingRangeHandler(languageServerClient, documentManager, logger);
const inlayHintHandler = new InlayHintHandler(
languageServerClient,
documentManager,
documentSynchronizer,
logger
);
const inlayHintResolveHandler = new InlayHintResolveHandler(languageServerClient, documentManager, logger);
const formattingHandler = new FormattingHandler(
documentManager,
documentSynchronizer,
Expand Down Expand Up @@ -301,6 +310,8 @@ export async function activate(
colorPresentationHandler.register(),
documentColorHandler.register(),
foldingRangeHandler.register(),
inlayHintHandler.register(),
inlayHintResolveHandler.register(),
formattingHandler.register(),
semanticTokenHandler.register(),
razorDiagnosticHandler.register(),
Expand Down
80 changes: 80 additions & 0 deletions src/razor/src/inlayHint/inlayHintHandler.ts
@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { InlayHint, InlayHintParams, RequestType, TextDocumentIdentifier } from 'vscode-languageclient';
import { RazorDocumentManager } from '../document/razorDocumentManager';
import { RazorLanguageServerClient } from '../razorLanguageServerClient';
import { RazorLogger } from '../razorLogger';
import { SerializableInlayHintParams } from './serializableInlayHintParams';
import { provideInlayHintsCommand } from '../../../lsptoolshost/razorCommands';
import { UriConverter } from '../../../lsptoolshost/uriConverter';
import { RazorDocumentSynchronizer } from '../document/razorDocumentSynchronizer';

export class InlayHintHandler {
private static readonly provideInlayHint = 'razor/inlayHint';
private InlayHintRequestType: RequestType<SerializableInlayHintParams, InlayHint[], any> = new RequestType(
InlayHintHandler.provideInlayHint
);
private emptyInlayHintResponse = new Array<InlayHint>();

constructor(
private readonly serverClient: RazorLanguageServerClient,
private readonly documentManager: RazorDocumentManager,
private readonly documentSynchronizer: RazorDocumentSynchronizer,
private readonly logger: RazorLogger
) {}

public async register() {
await this.serverClient.onRequestWithParams<SerializableInlayHintParams, InlayHint[], any>(
this.InlayHintRequestType,
async (request, token) => this.provideInlayHints(request, token)
);
}

private async provideInlayHints(inlayHintParams: SerializableInlayHintParams, token: vscode.CancellationToken) {
try {
const razorDocumentUri = vscode.Uri.parse(inlayHintParams.identifier.textDocumentIdentifier.uri, true);
const razorDocument = await this.documentManager.getDocument(razorDocumentUri);
if (razorDocument === undefined) {
return this.emptyInlayHintResponse;
}

if (!this.documentManager.roslynActivated) {
// Unlike most other handlers, inlay hints works by directly sending an LSP request to Roslyn, so if Roslyn isn't
// activated we need to catch that here.
return this.emptyInlayHintResponse;
}

const textDocument = await vscode.workspace.openTextDocument(razorDocumentUri);
const synchronized = await this.documentSynchronizer.trySynchronizeProjectedDocument(
textDocument,
razorDocument.csharpDocument,
inlayHintParams.identifier.version,
token
);
if (!synchronized) {
return this.emptyInlayHintResponse;
}

const virtualCSharpUri = UriConverter.serialize(razorDocument.csharpDocument.uri);

const roslynInlayHintParams = <InlayHintParams>{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding - why do we not need to do this for the resolve request?

textDocument: TextDocumentIdentifier.create(virtualCSharpUri),
range: inlayHintParams.projectedRange,
};
const csharpInlayHints = await vscode.commands.executeCommand<InlayHint[]>(
provideInlayHintsCommand,
roslynInlayHintParams
);

return csharpInlayHints;
} catch (error) {
this.logger.logWarning(`${InlayHintHandler.provideInlayHint} failed with ${error}`);
}

return this.emptyInlayHintResponse;
}
}
52 changes: 52 additions & 0 deletions src/razor/src/inlayHint/inlayHintResolveHandler.ts
@@ -0,0 +1,52 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { InlayHint, RequestType } from 'vscode-languageclient';
import { RazorDocumentManager } from '../document/razorDocumentManager';
import { RazorLanguageServerClient } from '../razorLanguageServerClient';
import { RazorLogger } from '../razorLogger';
import { SerializableInlayHintResolveParams } from './serializableInlayHintResolveParams';
import { resolveInlayHintCommand } from '../../../lsptoolshost/razorCommands';

export class InlayHintResolveHandler {
private static readonly resolveInlayHint = 'razor/inlayHintResolve';
private InlayHintResolveRequestType: RequestType<SerializableInlayHintResolveParams, InlayHint | null, any> =
new RequestType(InlayHintResolveHandler.resolveInlayHint);

constructor(
private readonly serverClient: RazorLanguageServerClient,
private readonly documentManager: RazorDocumentManager,
private readonly logger: RazorLogger
) {}

public async register() {
await this.serverClient.onRequestWithParams<SerializableInlayHintResolveParams, InlayHint | null, any>(
this.InlayHintResolveRequestType,
async (request, token) => this.resolveInlayHint(request, token)
);
}

private async resolveInlayHint(InlayHintParams: SerializableInlayHintResolveParams, _: vscode.CancellationToken) {
try {
const razorDocumentUri = vscode.Uri.parse(InlayHintParams.identifier.textDocumentIdentifier.uri, true);
const razorDocument = await this.documentManager.getDocument(razorDocumentUri);
if (razorDocument === undefined) {
return null;
}

const response = await vscode.commands.executeCommand<InlayHint>(
resolveInlayHintCommand,
InlayHintParams.inlayHint
);

return response;
} catch (error) {
this.logger.logWarning(`${InlayHintResolveHandler.resolveInlayHint} failed with ${error}`);
}

return null;
}
}
12 changes: 12 additions & 0 deletions src/razor/src/inlayHint/serializableInlayHintParams.ts
@@ -0,0 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Range } from 'vscode-languageserver-protocol';
import { SerializableTextDocumentIdentifierAndVersion } from '../simplify/serializableTextDocumentIdentifierAndVersion';

export interface SerializableInlayHintParams {
identifier: SerializableTextDocumentIdentifierAndVersion;
projectedRange: Range;
}
12 changes: 12 additions & 0 deletions src/razor/src/inlayHint/serializableInlayHintResolveParams.ts
@@ -0,0 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { InlayHint } from 'vscode-languageserver-protocol';
import { SerializableTextDocumentIdentifierAndVersion } from '../simplify/serializableTextDocumentIdentifierAndVersion';

export interface SerializableInlayHintResolveParams {
identifier: SerializableTextDocumentIdentifierAndVersion;
inlayHint: InlayHint;
}