From 5c331687ffa8b0620fca37bb8ef0b36f57082387 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Thu, 2 Apr 2026 02:06:50 -0400 Subject: [PATCH] fix(matrix): ignore escaped backticks in mention masking --- extensions/matrix/src/matrix/format.test.ts | 11 +++++++++++ extensions/matrix/src/matrix/format.ts | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/extensions/matrix/src/matrix/format.test.ts b/extensions/matrix/src/matrix/format.test.ts index 1d1fc97a32f..bad6ecbbd2d 100644 --- a/extensions/matrix/src/matrix/format.test.ts +++ b/extensions/matrix/src/matrix/format.test.ts @@ -219,6 +219,17 @@ describe("markdownToMatrixHtml", () => { expect(result.mentions).toEqual({}); }); + it("keeps escaped mentions literal after escaped backticks", async () => { + const result = await renderMarkdownToMatrixHtmlWithMentions({ + markdown: "\\`literal then \\@alice:example.org", + client: createMentionClient(), + }); + + expect(result.html).toContain("`literal then @alice:example.org"); + expect(result.html).not.toContain("matrix.to"); + expect(result.mentions).toEqual({}); + }); + it("restores escaped mentions in markdown link labels without linking them", async () => { const result = await renderMarkdownToMatrixHtmlWithMentions({ markdown: "[\\@alice:example.org](https://example.com)", diff --git a/extensions/matrix/src/matrix/format.ts b/extensions/matrix/src/matrix/format.ts index 8469e18bc48..1b7e75f4ff0 100644 --- a/extensions/matrix/src/matrix/format.ts +++ b/extensions/matrix/src/matrix/format.ts @@ -68,7 +68,7 @@ function maskEscapedMentions(markdown: string): string { let codeFenceLength = 0; while (idx < markdown.length) { - if (markdown[idx] === "`") { + if (markdown[idx] === "`" && !isMarkdownEscaped(markdown, idx)) { let runLength = 1; while (markdown[idx + runLength] === "`") { runLength += 1; @@ -94,6 +94,16 @@ function maskEscapedMentions(markdown: string): string { return masked; } +function isMarkdownEscaped(markdown: string, idx: number): boolean { + let slashCount = 0; + let cursor = idx - 1; + while (cursor >= 0 && markdown[cursor] === "\\") { + slashCount += 1; + cursor -= 1; + } + return slashCount % 2 === 1; +} + function restoreEscapedMentions(text: string): string { return text.replaceAll(ESCAPED_MENTION_SENTINEL, "@"); }