From 11f1949c9d71eeaad28402cb350722a103cc0514 Mon Sep 17 00:00:00 2001 From: shkomg Date: Tue, 3 Nov 2026 19:09:56 +0100 Subject: [PATCH] fix(markdown): remove blockquote from code fence lines when toggling off matchLeadingBlockCharacters only recognised a block marker when the next character was a letter, digit or one of `_*[!`, so "> ```" and "> ~~~" were never seen as quoted. Toggling a blockquote off over a fenced code block unquoted the code lines but left the fences quoted. Allow backtick and tilde after the marker, which also covers lines starting with inline code or strikethrough. --- .changeset/quiet-fences-unquote.md | 5 +++++ src/commonmark/commands.ts | 2 +- test/commonmark/commands.test.ts | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .changeset/quiet-fences-unquote.md diff --git a/.changeset/quiet-fences-unquote.md b/.changeset/quiet-fences-unquote.md new file mode 100644 index 00000000..6c3ecc41 --- /dev/null +++ b/.changeset/quiet-fences-unquote.md @@ -0,0 +1,5 @@ +--- +"@stackoverflow/stacks-editor": patch +--- + +Remove the blockquote from code fence lines when toggling a blockquote off in markdown mode diff --git a/src/commonmark/commands.ts b/src/commonmark/commands.ts index 0302cc0e..37bad391 100644 --- a/src/commonmark/commands.ts +++ b/src/commonmark/commands.ts @@ -197,7 +197,7 @@ export function matchLeadingBlockCharacters(text: string) { // If text is not an ordered list block, check for other block types if (!match) { // TODO HACK assumes all non-ordered list block types are non-letter characters followed by a single space - match = /^[^a-zA-Z0-9]+\s{1}(?=[a-zA-Z0-9_*[!]|$)+/.exec(text)?.[0]; + match = /^[^a-zA-Z0-9]+\s{1}(?=[a-zA-Z0-9_*[!`~]|$)+/.exec(text)?.[0]; } return match || ""; diff --git a/test/commonmark/commands.test.ts b/test/commonmark/commands.test.ts index 1362ca90..80de7737 100644 --- a/test/commonmark/commands.test.ts +++ b/test/commonmark/commands.test.ts @@ -489,6 +489,18 @@ some text`; "\nth" ); }); + + it("multi line, selection spanning a fenced code block", () => { + const content = "> ```\n> Some code\n> ```"; + const state = createState(content, 0, content.length); + const command = commands.setBlockTypeCommand(">"); + + expect(state).transactionSuccess( + command, + "```\nSome code\n```", + "```\nSome code\n```" + ); + }); }); /* SWAP */ @@ -605,6 +617,11 @@ some text`; expect(command).toBe("## "); }); + + it("return blockquote leading characters before a code fence", () => { + expect(commands.matchLeadingBlockCharacters("> ```")).toBe("> "); + expect(commands.matchLeadingBlockCharacters("> ~~~")).toBe("> "); + }); }); describe("insertTagLinkCommand", () => {