Skip to content

Commit c740c3b

Browse files
committed
fix how fsx outputs display inline html
1 parent 3934dfa commit c740c3b

File tree

5 files changed

+232
-14
lines changed

5 files changed

+232
-14
lines changed

src/FSharp.Formatting.Literate/Literate.fs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -568,18 +568,16 @@ type Literate private () =
568568
rootInputFolder,
569569
crefResolver,
570570
mdlinkResolver,
571-
parseOptions,
572571
onError,
573572
filesWithFrontMatter: FrontMatterFile array
574573
) =
575574

576575
let parseOptions =
577576
match outputKind with
578-
| OutputKind.Markdown
579577
| OutputKind.Fsx
580-
| OutputKind.Pynb -> parseOptions ||| MarkdownParseOptions.ParseCodeAsOther
581-
//||| MarkdownParseOptions.ParseNonCodeAsOther
582-
| _ -> parseOptions
578+
| OutputKind.Pynb ->
579+
(MarkdownParseOptions.ParseCodeAsOther)
580+
| _ -> MarkdownParseOptions.None
583581

584582
let fsx = ParsePynb.pynbToFsx input
585583

src/FSharp.Formatting.Literate/ParsePynb.fs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module internal ParsePynb =
2525
| Some outputs ->
2626
let outputsString = outputs |> String.concat "\n"
2727
sprintf $"{codeBlock}\n{outputsString}"
28+
2829
member this.ToFsx() =
2930
match this with
3031
| Markdown source -> $"(**\n{source}\n*)"
@@ -36,14 +37,17 @@ module internal ParsePynb =
3637
| Some outputs ->
3738
let outputsString = outputs |> String.concat "\n"
3839
sprintf $"{codeBlock}\n(**\n{outputsString}\n*)"
39-
| Code _ ->
40-
$"(**\n{this.ToMarkdown()}\n*)"
40+
| Code _ -> $"(**\n{this.ToMarkdown()}\n*)"
4141

4242
module Output =
4343
let (|TextHtml|_|) (x: JsonElement) =
4444
match x.TryGetProperty("text/html") with
4545
| true, html ->
46-
let html = html.EnumerateArray() |> Seq.map (fun x -> x.GetString()) |> String.concat "\n"
46+
let html =
47+
html.EnumerateArray()
48+
|> Seq.map (fun x -> x.GetString().Replace("\r\n", "\n") |> addLineEnd)
49+
|> String.concat ""
50+
4751
Some $"<p>{html}</p>"
4852
| _ -> None
4953

src/FSharp.Formatting.Markdown/FsxFormatting.fs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,43 @@ module internal FSharp.Formatting.Markdown.FsxFormatting
66

77
open MarkdownUtils
88

9+
/// Like MarkdownUtils.isCode, but does not treat InlineHtmlBlock as code
10+
let isFsxCode =
11+
(function
12+
| CodeBlock _ -> true
13+
| _ -> false)
14+
15+
/// Like MarkdownUtils.splitParagraphs, but does not treat InlineHtmlBlock as code
16+
let splitFsxParagraphs paragraphs =
17+
let firstCode = paragraphs |> List.tryFindIndex isFsxCode
18+
19+
match firstCode with
20+
| Some 0 ->
21+
let code = paragraphs.[0]
22+
let codeLines = getCode code
23+
let otherParagraphs = paragraphs.[1..]
24+
25+
// Collect the code output(s) that follows this cell if any
26+
let codeOutput = otherParagraphs |> List.takeWhile isCodeOutput |> List.map getCodeOutput
27+
28+
let otherParagraphs = otherParagraphs |> List.skipWhile isCodeOutput
29+
30+
Choice1Of2(codeLines, codeOutput, getExecutionCount code), otherParagraphs
31+
32+
| Some _
33+
| None ->
34+
let markdownParagraphs = paragraphs |> List.takeWhile (isFsxCode >> not)
35+
36+
let otherParagraphs = paragraphs |> List.skipWhile (isFsxCode >> not)
37+
38+
Choice2Of2 markdownParagraphs, otherParagraphs
39+
940
/// Write a list of MarkdownParagraph values to a TextWriter
1041
let rec formatParagraphs ctx paragraphs =
1142
match paragraphs with
1243
| [] -> []
1344
| _ ->
14-
let k, otherParagraphs = splitParagraphs paragraphs
45+
let k, otherParagraphs = splitFsxParagraphs paragraphs
1546

1647
let cell =
1748
match k with

src/fsdocs-tool/BuildCommand.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,6 @@ type internal DocContent
422422
rootInputFolder = rootInputFolder,
423423
crefResolver = crefResolver,
424424
mdlinkResolver = mdlinkResolver,
425-
parseOptions = MarkdownParseOptions.AllowYamlFrontMatter,
426425
onError = Some onError,
427426
filesWithFrontMatter = filesWithFrontMatter
428427
)

tests/FSharp.Literate.Tests/LiterateTests.fs

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,7 @@ let hello5 = 4 // Doc preparation code is not present in generated notebooks
13591359

13601360
[<Test>]
13611361
let ``Notebook output is exactly right`` () =
1362-
let md =
1362+
let doc =
13631363
Literate.ParseScriptString(
13641364
"""
13651365
let hello = 1
@@ -1371,7 +1371,7 @@ let goodbye = 2
13711371
||| MarkdownParseOptions.ParseNonCodeAsOther)
13721372
)
13731373

1374-
let pynb = Literate.ToPynb(md)
1374+
let pynb = Literate.ToPynb(doc)
13751375
printfn "----"
13761376
printfn "%s" pynb
13771377
printfn "----"
@@ -1433,6 +1433,192 @@ let goodbye = 2
14331433

14341434
pynb2 |> shouldEqual expected2
14351435

1436+
[<Test>]
1437+
let ``pynb outputs passed to script correctly`` () =
1438+
1439+
let input =
1440+
"""{
1441+
"cells": [
1442+
{
1443+
"cell_type": "markdown",
1444+
"metadata": {
1445+
"dotnet_repl_cellExecutionStartTime": "2023-11-22T09:25:48.0570832+00:00",
1446+
"dotnet_repl_cellExecutionEndTime": "2023-11-22T09:25:48.0798154+00:00"
1447+
},
1448+
"source": [
1449+
"words"
1450+
]
1451+
},
1452+
{
1453+
"cell_type": "code",
1454+
"execution_count": null,
1455+
"metadata": {
1456+
"dotnet_repl_cellExecutionStartTime": "2023-11-22T09:25:48.081018+00:00",
1457+
"dotnet_repl_cellExecutionEndTime": "2023-11-22T09:25:50.1467326+00:00",
1458+
"dotnet_interactive": {
1459+
"language": "fsharp"
1460+
},
1461+
"polyglot_notebook": {
1462+
"kernelName": "fsharp"
1463+
}
1464+
},
1465+
"outputs": [
1466+
{
1467+
"data": {
1468+
"text/html": [
1469+
"<details open=\"open\" class=\"dni-treeview\"><summary><span class=\"dni-code-hint\"><code>{ Name = &quot;Alf&quot;\\n Phone = &quot;(555) 555-5555&quot;\\n ZipCode = &quot;90210&quot; }</code></span></summary><div><table><thead><tr></tr></thead><tbody><tr><td>Name</td><td><div class=\"dni-plaintext\"><pre>&quot;Alf&quot;\r\n",
1470+
"</pre></div></td></tr><tr><td>Phone</td><td><div class=\"dni-plaintext\"><pre>&quot;(555) 555-5555&quot;\r\n",
1471+
"</pre></div></td></tr><tr><td>ZipCode</td><td><div class=\"dni-plaintext\"><pre>&quot;90210&quot;\r\n",
1472+
"</pre></div></td></tr></tbody></table></div></details><style>\r\n",
1473+
".dni-code-hint {\r\n",
1474+
" font-style: italic;\r\n",
1475+
" overflow: hidden;\r\n",
1476+
" white-space: nowrap;\r\n",
1477+
"}\r\n",
1478+
".dni-treeview {\r\n",
1479+
" white-space: nowrap;\r\n",
1480+
"}\r\n",
1481+
".dni-treeview td {\r\n",
1482+
" vertical-align: top;\r\n",
1483+
" text-align: start;\r\n",
1484+
"}\r\n",
1485+
"details.dni-treeview {\r\n",
1486+
" padding-left: 1em;\r\n",
1487+
"}\r\n",
1488+
"table td {\r\n",
1489+
" text-align: start;\r\n",
1490+
"}\r\n",
1491+
"table tr { \r\n",
1492+
" vertical-align: top; \r\n",
1493+
" margin: 0em 0px;\r\n",
1494+
"}\r\n",
1495+
"table tr td pre \r\n",
1496+
"{ \r\n",
1497+
" vertical-align: top !important; \r\n",
1498+
" margin: 0em 0px !important;\r\n",
1499+
"} \r\n",
1500+
"table th {\r\n",
1501+
" text-align: start;\r\n",
1502+
"}\r\n",
1503+
"</style>"
1504+
]
1505+
},
1506+
"metadata": {},
1507+
"output_type": "display_data"
1508+
}
1509+
],
1510+
"source": [
1511+
"type ContactCard =\n",
1512+
" { Name: string\n",
1513+
" Phone: string\n",
1514+
" ZipCode: string }\n",
1515+
"\n",
1516+
"// Create a new record\n",
1517+
"{ Name = \"Alf\"; Phone = \"(555) 555-5555\"; ZipCode = \"90210\" }"
1518+
]
1519+
}
1520+
],
1521+
"metadata": {
1522+
"kernelspec": {
1523+
"display_name": ".NET (F#)",
1524+
"language": "F#",
1525+
"name": ".net-fsharp"
1526+
},
1527+
"language_info": {
1528+
"file_extension": ".fs",
1529+
"mimetype": "text/x-fsharp",
1530+
"name": "F#",
1531+
"pygments_lexer": "fsharp",
1532+
"version": "6.0"
1533+
},
1534+
"polyglot_notebook": {
1535+
"defaultKernelName": "fsharp",
1536+
"items": [
1537+
{
1538+
"name": "fsharp"
1539+
}
1540+
]
1541+
},
1542+
"dotnet_interactive": {
1543+
"defaultKernelName": "fsharp",
1544+
"items": [
1545+
{
1546+
"name": "fsharp"
1547+
}
1548+
]
1549+
}
1550+
},
1551+
"nbformat": 4,
1552+
"nbformat_minor": 5
1553+
}"""
1554+
1555+
let doc = Literate.ParsePynbString(input, parseOptions = (MarkdownParseOptions.ParseCodeAsOther))
1556+
1557+
let fsx = Literate.ToFsx(doc)
1558+
printfn "----"
1559+
printfn "%s" fsx
1560+
printfn "----"
1561+
1562+
let fsx2 =
1563+
fsx
1564+
.Replace("\r\n", "\n")
1565+
.Replace(" \n", "\n")
1566+
.Replace("\n\n*)", "\n*)")
1567+
.Replace("\n", "!")
1568+
1569+
let expected =
1570+
"""(**
1571+
words
1572+
*)
1573+
type ContactCard =
1574+
{ Name: string
1575+
Phone: string
1576+
ZipCode: string }
1577+
1578+
// Create a new record
1579+
{ Name = "Alf"; Phone = "(555) 555-5555"; ZipCode = "90210" }
1580+
(**
1581+
<p><details open="open" class="dni-treeview"><summary><span class="dni-code-hint"><code>{ Name = &quot;Alf&quot;\n Phone = &quot;(555) 555-5555&quot;\n ZipCode = &quot;90210&quot; }</code></span></summary><div><table><thead><tr></tr></thead><tbody><tr><td>Name</td><td><div class="dni-plaintext"><pre>&quot;Alf&quot;
1582+
</pre></div></td></tr><tr><td>Phone</td><td><div class="dni-plaintext"><pre>&quot;(555) 555-5555&quot;
1583+
</pre></div></td></tr><tr><td>ZipCode</td><td><div class="dni-plaintext"><pre>&quot;90210&quot;
1584+
</pre></div></td></tr></tbody></table></div></details><style>
1585+
.dni-code-hint {
1586+
font-style: italic;
1587+
overflow: hidden;
1588+
white-space: nowrap;
1589+
}
1590+
.dni-treeview {
1591+
white-space: nowrap;
1592+
}
1593+
.dni-treeview td {
1594+
vertical-align: top;
1595+
text-align: start;
1596+
}
1597+
details.dni-treeview {
1598+
padding-left: 1em;
1599+
}
1600+
table td {
1601+
text-align: start;
1602+
}
1603+
table tr {
1604+
vertical-align: top;
1605+
margin: 0em 0px;
1606+
}
1607+
table tr td pre
1608+
{
1609+
vertical-align: top !important;
1610+
margin: 0em 0px !important;
1611+
}
1612+
table th {
1613+
text-align: start;
1614+
}
1615+
</style>
1616+
</p>
1617+
*)"""
1618+
1619+
let expected2 = expected.Replace("\r\n", "\n").Replace("\n", "!")
1620+
fsx2 |> shouldEqual expected2
1621+
14361622
[<Test>]
14371623
let ``md --> pynb --> md comes back the same`` () =
14381624
let mdIn =
@@ -1471,7 +1657,7 @@ let add a b = a + b
14711657
let ``Notebook is converted to script exactly right`` () =
14721658
let doc =
14731659
Literate.ParsePynbString(
1474-
"""
1660+
"""
14751661
{
14761662
"cells": [
14771663
{
@@ -1533,7 +1719,7 @@ let ``Notebook is converted to script exactly right`` () =
15331719
let fsx2 = fsx.Replace("\r\n", "\n").Replace("\n", "!")
15341720

15351721
let expected =
1536-
"""let hello = 1
1722+
"""let hello = 1
15371723
15381724
let goodbye = 2"""
15391725

0 commit comments

Comments
 (0)