Skip to content

Commit

Permalink
Merged PR 469678: Fix Razor formatting bug
Browse files Browse the repository at this point in the history
This is the Blue/Green version of dotnet/razor#8669. I literally just copied the code over from one repo to the other. Also testsed in Blue because I couldn't test in O# locally for some reason.

Fixes dotnet#5561 for Blue/Green
  • Loading branch information
davidwengier committed May 9, 2023
2 parents 0922c35 + b4ad031 commit d502a5a
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 157 deletions.
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"defaults": {
"roslyn": "4.7.0-2.23258.2",
"omniSharp": "1.39.6",
"razor": "7.0.0-preview.23220.3"
"razor": "7.0.0-preview.23258.1"
},
"main": "./dist/extension",
"brokeredServices": [{
Expand Down Expand Up @@ -538,7 +538,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Windows / x64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/6d3896fc76117c1a941ad64514e48860/razorlanguageserver-win-x64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/d67585e2b3009d700c70f6f3f7ec666f/razorlanguageserver-win-x64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"win32"
Expand All @@ -550,7 +550,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Windows / x86)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/0a9275474ea64e65890ec70e3e155699/razorlanguageserver-win-x86-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/dc253426025d44bf9f78e9d69b1b946e/razorlanguageserver-win-x86-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"win32"
Expand All @@ -562,7 +562,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Windows / ARM64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/da796acb9624df1f0506cae5bee403c3/razorlanguageserver-win-arm64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/c6a4cc07ec8a8e089ce3a8e618e2df35/razorlanguageserver-win-arm64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"win32"
Expand All @@ -574,7 +574,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Linux / x64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/e6b119e9d63d402f743625eb8f090afd/razorlanguageserver-linux-x64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/86cc790bb4a8c703cbec0e3260b63620/razorlanguageserver-linux-x64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"linux"
Expand All @@ -589,7 +589,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Linux ARM64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/91b088b9b816ea2d9f633e4653407796/razorlanguageserver-linux-arm64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/cbd4a5d06dfd59faf0afca97cb44c2d8/razorlanguageserver-linux-arm64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"linux"
Expand All @@ -604,7 +604,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Linux musl / x64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/9dbbf00efa68e82a028e46929aa974c0/razorlanguageserver-linux-musl-x64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/8eb49bd7a28941933356bdb206864b2d/razorlanguageserver-linux-musl-x64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"linux-musl"
Expand All @@ -619,7 +619,7 @@
{
"id": "Razor",
"description": "Razor Language Server (Linux musl ARM64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/4283aabbacb3013a5c4449091d1802e0/razorlanguageserver-linux-musl-arm64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/6ddcb891121eef359196e37ab1f4f31d/razorlanguageserver-linux-musl-arm64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"linux-musl"
Expand All @@ -634,7 +634,7 @@
{
"id": "Razor",
"description": "Razor Language Server (macOS / x64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/89434a154d12c8981a55b176486fc38a/razorlanguageserver-osx-x64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/cd0a3b009315c636383c21962d312d8a/razorlanguageserver-osx-x64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"darwin"
Expand All @@ -649,7 +649,7 @@
{
"id": "Razor",
"description": "Razor Language Server (macOS ARM64)",
"url": "https://download.visualstudio.microsoft.com/download/pr/04badfdc-0d27-45fa-a857-6116db74269b/0fb5b30e7cb285257e5122b4ea3e10c8/razorlanguageserver-osx-arm64-7.0.0-preview.23220.3.zip",
"url": "https://download.visualstudio.microsoft.com/download/pr/4ccf25e1-f154-4946-b682-0cdfd35a60ce/274355756fd7dd499d0116f063b2cd67/razorlanguageserver-osx-arm64-7.0.0-preview.23258.1.zip",
"installPath": ".razor",
"platforms": [
"darwin"
Expand Down
105 changes: 88 additions & 17 deletions src/razor/src/Formatting/FormattingHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@

import * as vscode from 'vscode';
import { RequestType } from 'vscode-languageclient';
import { IRazorDocument } from '../Document/IRazorDocument';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorDocumentSynchronizer } from '../Document/RazorDocumentSynchronizer';
import { RazorLanguageServerClient } from '../RazorLanguageServerClient';
import { RazorLogger } from '../RazorLogger';
import { convertTextEditToSerializable, SerializableTextEdit } from '../RPC/SerializableTextEdit';
import { SerializableFormattingParams } from './SerializableFormattingParams';
import { SerializableFormattingResponse } from './SerializableFormattingResponse';
import { SerializableOnTypeFormattingParams } from './SerializableOnTypeFormattingParams';

export class FormattingHandler {
private static readonly provideFormattingEndpoint = 'textDocument/formatting';
private static readonly provideFormattingEndpoint = 'razor/htmlFormatting';
private static readonly provideOnTypeFormattingEndpoint = 'razor/htmlOnTypeFormatting';
private formattingRequestType: RequestType<SerializableFormattingParams, SerializableFormattingResponse, any> = new RequestType(FormattingHandler.provideFormattingEndpoint);
private onTypeFormattingRequestType: RequestType<SerializableOnTypeFormattingParams, SerializableFormattingResponse, any> = new RequestType(FormattingHandler.provideOnTypeFormattingEndpoint);
private emptyFormattingResponse = new SerializableFormattingResponse();

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

Expand All @@ -27,6 +33,10 @@ export class FormattingHandler {
this.serverClient.onRequestWithParams<SerializableFormattingParams, SerializableFormattingResponse, any>(
this.formattingRequestType,
async (request, token) => this.provideFormatting(request, token));
// tslint:disable-next-line: no-floating-promises
this.serverClient.onRequestWithParams<SerializableOnTypeFormattingParams, SerializableFormattingResponse, any>(
this.onTypeFormattingRequestType,
async (request, token) => this.provideOnTypeFormatting(request, token));
}

private async provideFormatting(
Expand All @@ -39,6 +49,12 @@ export class FormattingHandler {
return this.emptyFormattingResponse;
}

const textDocument = await vscode.workspace.openTextDocument(razorDocumentUri);
const synchronized = await this.documentSynchronizer.trySynchronizeProjectedDocument(textDocument, razorDocument.csharpDocument, formattingParams.hostDocumentVersion, cancellationToken);
if (!synchronized) {
return this.emptyFormattingResponse;
}

const virtualHtmlUri = razorDocument.htmlDocument.uri;

const textEdits = await vscode.commands.executeCommand<vscode.TextEdit[]>(
Expand All @@ -50,24 +66,47 @@ export class FormattingHandler {
return this.emptyFormattingResponse;
}

const htmlDocText = razorDocument.htmlDocument.getContent();
const zeroBasedLineCount = this.countLines(htmlDocText);
const serializableTextEdits = Array<SerializableTextEdit>();
for (let textEdit of textEdits) {
// The below workaround is needed due to a bug on the HTML side where
// they'll sometimes send us an end position that exceeds the length
// of the document. Tracked by https://github.com/microsoft/vscode/issues/175298.
if (textEdit.range.end.line > zeroBasedLineCount) {
const lastLineLength = this.getLastLineLength(htmlDocText);
const updatedEndPosition = new vscode.Position(zeroBasedLineCount, lastLineLength);
const updatedRange = new vscode.Range(textEdit.range.start, updatedEndPosition);
textEdit = new vscode.TextEdit(updatedRange, textEdit.newText);
}
const serializableTextEdits = this.sanitizeTextEdits(razorDocument, textEdits);

return new SerializableFormattingResponse(serializableTextEdits);
} catch (error) {
this.logger.logWarning(`${FormattingHandler.provideFormattingEndpoint} failed with ${error}`);
}

const serializableTextEdit = convertTextEditToSerializable(textEdit);
serializableTextEdits.push(serializableTextEdit);
return this.emptyFormattingResponse;
}

private async provideOnTypeFormatting(
formattingParams: SerializableOnTypeFormattingParams,
cancellationToken: vscode.CancellationToken) {
try {
const razorDocumentUri = vscode.Uri.parse(formattingParams.textDocument.uri);
const razorDocument = await this.documentManager.getDocument(razorDocumentUri);
if (razorDocument === undefined) {
return this.emptyFormattingResponse;
}

const textDocument = await vscode.workspace.openTextDocument(razorDocumentUri);
const synchronized = await this.documentSynchronizer.trySynchronizeProjectedDocument(textDocument, razorDocument.csharpDocument, formattingParams.hostDocumentVersion, cancellationToken);
if (!synchronized) {
return this.emptyFormattingResponse;
}

const virtualHtmlUri = razorDocument.htmlDocument.uri;

const textEdits = await vscode.commands.executeCommand<vscode.TextEdit[]>(
'vscode.executeFormatOnTypeProvider',
virtualHtmlUri,
formattingParams.position,
formattingParams.ch,
formattingParams.options);

if (textEdits === undefined) {
return this.emptyFormattingResponse;
}

const serializableTextEdits = this.sanitizeTextEdits(razorDocument, textEdits);

return new SerializableFormattingResponse(serializableTextEdits);
} catch (error) {
this.logger.logWarning(`${FormattingHandler.provideFormattingEndpoint} failed with ${error}`);
Expand All @@ -76,6 +115,38 @@ export class FormattingHandler {
return this.emptyFormattingResponse;
}

private sanitizeTextEdits(razorDocument: IRazorDocument, textEdits: vscode.TextEdit[]) {
const htmlDocText = razorDocument.htmlDocument.getContent();
const zeroBasedLineCount = this.countLines(htmlDocText);
const serializableTextEdits = Array<SerializableTextEdit>();
for (let textEdit of textEdits) {
// The below workaround is needed due to a bug on the HTML side where
// they'll sometimes send us an end position that exceeds the length
// of the document. Tracked by https://github.com/microsoft/vscode/issues/175298.
if (textEdit.range.end.line > zeroBasedLineCount ||
textEdit.range.start.line > zeroBasedLineCount) {
const lastLineLength = this.getLastLineLength(htmlDocText);
const updatedPosition = new vscode.Position(zeroBasedLineCount, lastLineLength);

let start = textEdit.range.start;
let end = textEdit.range.end;
if (textEdit.range.start.line > zeroBasedLineCount) {
start = updatedPosition;
}

if (textEdit.range.end.line > zeroBasedLineCount) {
end = updatedPosition;
}
const updatedRange = new vscode.Range(start, end);
textEdit = new vscode.TextEdit(updatedRange, textEdit.newText);
}

const serializableTextEdit = convertTextEditToSerializable(textEdit);
serializableTextEdits.push(serializableTextEdit);
}
return serializableTextEdits;
}

private countLines(text: string) {
let lineCount = 0;
for (const i of text) {
Expand Down Expand Up @@ -103,4 +174,4 @@ export class FormattingHandler {

return currentLineLength;
}
}
}
15 changes: 0 additions & 15 deletions src/razor/src/Formatting/RazorDocumentRangeFormattingRequest.ts

This file was deleted.

11 changes: 0 additions & 11 deletions src/razor/src/Formatting/RazorDocumentRangeFormattingResponse.ts

This file was deleted.

19 changes: 0 additions & 19 deletions src/razor/src/Formatting/RazorFormatOnTypeProvider.ts

This file was deleted.

73 changes: 0 additions & 73 deletions src/razor/src/Formatting/RazorFormattingFeature.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/razor/src/Formatting/SerializableFormattingParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as vscode from 'vscode';
import { SerializableTextDocumentIdentifier } from './../RPC/SerializableTextDocumentIdentifier';

export interface SerializableFormattingParams {
hostDocumentVersion: number;
textDocument: SerializableTextDocumentIdentifier;
options: vscode.FormattingOptions;
}
Loading

0 comments on commit d502a5a

Please sign in to comment.