From 14d70052a592f019258dda54143c7e3e9615af50 Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Fri, 4 Jul 2025 10:55:56 +0200 Subject: [PATCH 1/3] Sort text edits by descending start position --- apps/vscode/src/providers/format.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/vscode/src/providers/format.ts b/apps/vscode/src/providers/format.ts index 92c078e5..263340d3 100644 --- a/apps/vscode/src/providers/format.ts +++ b/apps/vscode/src/providers/format.ts @@ -138,9 +138,13 @@ class FormatCellCommand implements Command { const edits = await formatActiveCell(editor, this.engine_); if (edits) { editor.edit((editBuilder) => { - edits.forEach((edit) => { - editBuilder.replace(edit.range, edit.newText); - }); + // Sort edits by descending start position to avoid range shifting issues + edits + .slice() + .sort((a, b) => b.range.start.compareTo(a.range.start)) + .forEach((edit) => { + editBuilder.replace(edit.range, edit.newText); + }); }); } else { window.showInformationMessage( @@ -204,15 +208,21 @@ async function formatActiveCell(editor: TextEditor, engine: MarkdownEngine) { } async function formatBlock(doc: TextDocument, block: TokenMath | TokenCodeBlock, language: EmbeddedLanguage) { + // Create virtual document containing the block const blockLines = lines(codeForExecutableLanguageBlock(block)); blockLines.push(""); const vdoc = virtualDocForCode(blockLines, language); + const edits = await executeFormatDocumentProvider( vdoc, doc, formattingOptions(doc.uri, vdoc.language) ); + if (edits) { + // Because we format with the block code copied in an empty virtual + // document, we need to adjust the ranges to match the edits to the block + // cell in the original file. const blockRange = new Range( new Position(block.range.start.line, block.range.start.character), new Position(block.range.end.line, block.range.end.character) From 636d9843ed64a5da950ca2cdc418139378421887 Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Fri, 4 Jul 2025 12:24:26 +0200 Subject: [PATCH 2/3] Don't append lines to block code before formatting --- apps/vscode/src/providers/format.ts | 3 +-- packages/quarto-core/src/markdown/language.ts | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/vscode/src/providers/format.ts b/apps/vscode/src/providers/format.ts index 263340d3..51e53170 100644 --- a/apps/vscode/src/providers/format.ts +++ b/apps/vscode/src/providers/format.ts @@ -209,8 +209,7 @@ async function formatActiveCell(editor: TextEditor, engine: MarkdownEngine) { async function formatBlock(doc: TextDocument, block: TokenMath | TokenCodeBlock, language: EmbeddedLanguage) { // Create virtual document containing the block - const blockLines = lines(codeForExecutableLanguageBlock(block)); - blockLines.push(""); + const blockLines = lines(codeForExecutableLanguageBlock(block, false)); const vdoc = virtualDocForCode(blockLines, language); const edits = await executeFormatDocumentProvider( diff --git a/packages/quarto-core/src/markdown/language.ts b/packages/quarto-core/src/markdown/language.ts index ea3f88fe..201fc259 100644 --- a/packages/quarto-core/src/markdown/language.ts +++ b/packages/quarto-core/src/markdown/language.ts @@ -38,11 +38,14 @@ export function isExecutableLanguageBlock(token: Token) : token is TokenMath | T } } -export function codeForExecutableLanguageBlock(token: TokenMath | TokenCodeBlock) { +export function codeForExecutableLanguageBlock( + token: TokenMath | TokenCodeBlock, + appendNewline = true, +) { if (isMath(token)) { return token.data.text; } else if (isCodeBlock(token)) { - return token.data + "\n"; + return token.data + (appendNewline ? "\n" : ""); } else { return ""; } From 0902ef2d43e21663cda38c6df4196bc4757a27f6 Mon Sep 17 00:00:00 2001 From: Lionel Henry Date: Fri, 4 Jul 2025 12:33:37 +0200 Subject: [PATCH 3/3] Don't apply partial edits --- apps/vscode/src/providers/format.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/vscode/src/providers/format.ts b/apps/vscode/src/providers/format.ts index 51e53170..c6a5eb84 100644 --- a/apps/vscode/src/providers/format.ts +++ b/apps/vscode/src/providers/format.ts @@ -233,8 +233,17 @@ async function formatBlock(doc: TextDocument, block: TokenMath | TokenCodeBlock, new Position(edit.range.end.line + block.range.start.line + 1, edit.range.end.character) ); return new TextEdit(range, edit.newText); - }) - .filter(edit => blockRange.contains(edit.range)); + }); + + // Bail if any edit is out of range. We used to filter these edits out but + // this could bork the cell. + if (edits.some(edit => !blockRange.contains(edit.range))) { + window.showInformationMessage( + "Formatting edits were out of range and could not be applied to the code cell." + ); + return []; + } + return adjustedEdits; } }