diff --git a/extensions/signal/src/format.test.ts b/extensions/signal/src/format.test.ts index 64cff3335d86..663bfd46ca76 100644 --- a/extensions/signal/src/format.test.ts +++ b/extensions/signal/src/format.test.ts @@ -86,6 +86,20 @@ describe("markdownToSignalText", () => { }); it.each([ + { + name: "nested styles across multiple expanded links and emoji", + markdown: "**[😀](https://a.test) _[two](https://b.test) tail_**", + expected: { + text: "😀 (https://a.test) two (https://b.test) tail", + styles: [ + { start: 0, length: 2, style: "BOLD" }, + { start: 19, length: 4, style: "BOLD" }, + { start: 20, length: 3, style: "ITALIC" }, + { start: 40, length: 5, style: "BOLD" }, + { start: 40, length: 5, style: "ITALIC" }, + ], + }, + }, { name: "nested style around an expanded link", markdown: "**[docs](https://example.com) _nested_ tail**", diff --git a/packages/markdown-core/src/construct-fallbacks.ts b/packages/markdown-core/src/construct-fallbacks.ts index 36f7f67487a2..76bd9bf045f2 100644 --- a/packages/markdown-core/src/construct-fallbacks.ts +++ b/packages/markdown-core/src/construct-fallbacks.ts @@ -1,5 +1,6 @@ import type { FormatCapabilityProfile, FormatConstruct } from "./format-capabilities.js"; import { copyHtmlTags } from "./ir-metadata.js"; +import { sliceMarkdownIRRanges } from "./ir-slice.js"; import { createStyleSpan, mergeAnnotationSpans, @@ -8,7 +9,7 @@ import { type MarkdownStyle, type MarkdownStyleSpan, } from "./ir-spans.js"; -import { appendMarkdownIR, sliceMarkdownIR, type MarkdownIR } from "./ir.js"; +import { appendMarkdownIR, type MarkdownIR } from "./ir.js"; type TextEdit = { start: number; end: number; text: string }; @@ -119,14 +120,18 @@ function applyTextEdits(ir: MarkdownIR, edits: TextEdit[]): MarkdownIR { links: ir.links, annotations: ir.annotations, }); - const result: MarkdownIR = { text: "", styles: [], links: [] }; let cursor = 0; - for (const edit of ordered) { - appendMarkdownIR(result, sliceMarkdownIR(content, cursor, edit.start)); - result.text += edit.text; + const ranges = ordered.map((edit) => { + const range = { start: cursor, end: edit.start }; cursor = edit.end; + return range; + }); + ranges.push({ start: cursor, end: ir.text.length }); + const result: MarkdownIR = { text: "", styles: [], links: [] }; + for (const [index, slice] of sliceMarkdownIRRanges(content, ranges).entries()) { + appendMarkdownIR(result, slice); + result.text += ordered[index]?.text ?? ""; } - appendMarkdownIR(result, sliceMarkdownIR(content, cursor, ir.text.length)); result.styles = mergeStyleSpans(result.styles); if (result.annotations) { result.annotations = mergeAnnotationSpans(result.annotations);