diff --git a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs index 59bf09a3..71be2fc9 100644 --- a/src/FSharp.Formatting.Markdown/MarkdownUtils.fs +++ b/src/FSharp.Formatting.Markdown/MarkdownUtils.fs @@ -125,12 +125,19 @@ module internal MarkdownUtils = let rec formatParagraph (ctx: FormattingContext) paragraph = [ match paragraph with | LatexBlock(env, lines, _) -> - yield sprintf "\\begin{%s}" env + // Single-line equation blocks are rendered with the compact $$...$$ notation + // (which is also valid markdown and what most authors write). Multi-line or + // non-standard environments keep the \begin{env}...\end{env} form. + if env = "equation" && lines.Length = 1 then + yield sprintf "$$%s$$" lines.[0] + else + yield sprintf "\\begin{%s}" env - for line in lines do - yield line + for line in lines do + yield line + + yield sprintf "\\end{%s}" env - yield sprintf "\\end{%s}" env yield "" | Heading(n, spans, _) -> diff --git a/tests/FSharp.Markdown.Tests/Markdown.fs b/tests/FSharp.Markdown.Tests/Markdown.fs index 984047f7..142a0475 100644 --- a/tests/FSharp.Markdown.Tests/Markdown.fs +++ b/tests/FSharp.Markdown.Tests/Markdown.fs @@ -1371,3 +1371,94 @@ let ``ToMd round-trip: indirect image with unresolved reference`` () = let result = Markdown.ToMd(doc) // When key is not resolved, should preserve the indirect form result |> should contain "![alt text][unknown-ref]" + +// -------------------------------------------------------------------------------------- +// ToMd additional coverage: headings, nested structures, LaTeX display math, inline code +// -------------------------------------------------------------------------------------- + +[] +let ``ToMd preserves heading level 4`` () = + "#### Heading Four" |> toMd |> shouldEqual "#### Heading Four" + +[] +let ``ToMd preserves heading level 5`` () = + "##### Heading Five" |> toMd |> shouldEqual "##### Heading Five" + +[] +let ``ToMd preserves heading level 6`` () = + "###### Heading Six" |> toMd |> shouldEqual "###### Heading Six" + +[] +let ``ToMd preserves emphasis inside a heading`` () = + let result = "## Hello *world*" |> toMd + result |> should contain "## Hello *world*" + +[] +let ``ToMd preserves strong text inside a heading`` () = + let result = "## Hello **world**" |> toMd + result |> should contain "## Hello **world**" + +[] +let ``ToMd preserves LaTeX display math`` () = + let md = "$$E = mc^2$$" + let result = toMd md + result |> should contain "$$E = mc^2$$" + +[] +let ``ToMd preserves inline code containing special chars`` () = + let md = "Use `a + b = c` inline." + let result = toMd md + result |> should contain "`a + b = c`" + +[] +let ``ToMd preserves nested unordered list`` () = + // Outer list item containing an inner list + let md = "* outer\n\n * inner" + let result = toMd md + result |> should contain "outer" + result |> should contain "inner" + +[] +let ``ToMd preserves a nested blockquote`` () = + // A blockquote that itself contains a blockquote + let md = "> > inner quote" + let result = toMd md + result |> should contain "> " + result |> should contain "inner quote" + // The inner quote marker should appear in the output (two levels of '>') + result |> should contain "> >" + +[] +let ``ToMd preserves emphasis inside a blockquote`` () = + let md = "> *italic text*" + let result = toMd md + result |> should contain "> " + result |> should contain "*italic text*" + +[] +let ``ToMd preserves inline code inside a blockquote`` () = + let md = "> use `printf` here" + let result = toMd md + result |> should contain "> " + result |> should contain "`printf`" + +[] +let ``ToMd preserves a code block without language`` () = + let md = "```\nsome code\n```" + let result = toMd md + result |> should contain "some code" + result |> should contain "```" + +[] +let ``ToMd preserves horizontal rule (dash variant)`` () = + let md = "---" + let result = toMd md + result |> should contain "---" + +[] +let ``ToMd preserves a link with a title`` () = + // Title attribute is allowed in Markdown links + let md = "[FSharp](https://fsharp.org \"F# home\")" + let result = toMd md + result |> should contain "[FSharp](" + result |> should contain "https://fsharp.org"