From 34814bf156d702a1a3f4c85e924d6997deb7e3f5 Mon Sep 17 00:00:00 2001 From: Lukas Weil Date: Mon, 21 Dec 2020 23:18:56 +0100 Subject: [PATCH] Add include-it-raw literate command (#624) --- docs/literate.fsx | 2 ++ src/FSharp.Formatting.Literate/Document.fs | 5 +++++ src/FSharp.Formatting.Literate/Evaluator.fs | 18 ++++++++++++++++++ src/FSharp.Formatting.Literate/ParseScript.fs | 12 ++++++++++++ .../Transformations.fs | 3 +++ tests/FSharp.Literate.Tests/EvalTests.fs | 14 ++++++++++++++ 6 files changed, 54 insertions(+) diff --git a/docs/literate.fsx b/docs/literate.fsx index 89d3f451c..b12916003 100644 --- a/docs/literate.fsx +++ b/docs/literate.fsx @@ -64,6 +64,7 @@ The F# script files is processed as follows: | `(*** include-fsi-output ***)` | The F# Interactive output of the preceeding snippet | | `(*** include-fsi-merged-output ***)` | The merge of console output and F# Interactive output of the preceeding snippet | | `(*** include-it ***)` | The formatted result of the preceeding snippet | +| `(*** include-it-raw ***)` | The unformatted result of the preceeding snippet | | `(*** include-value: value-name ***)` | The formatted value | | `(*** raw ***)` | The subsequent code is treated as raw text | @@ -82,6 +83,7 @@ F# language. | `(*** include-fsi-output: snippet-name ***)` | The F# Interactive output of the named snippet | | `(*** include-fsi-merged-output: snippet-name ***)` | The merge of console output and F# Interactive output of the named snippet | | `(*** include-it: snippet-name ***)` | The formatted result of the named snippet | +| `(*** include-it-raw: snippet-name ***)` | The unformatted result of the named snippet | | `(*** include: snippet-name ***)` | Include the code of the named snippet | #### Hiding code snippets diff --git a/src/FSharp.Formatting.Literate/Document.fs b/src/FSharp.Formatting.Literate/Document.fs index 2cb9c4418..3d82029ac 100644 --- a/src/FSharp.Formatting.Literate/Document.fs +++ b/src/FSharp.Formatting.Literate/Document.fs @@ -67,6 +67,10 @@ type LiterateParagraph = /// (*** include-it:foo ***) - Include "it" value from a named snippet | ItValueReference of string * LiterateParagraphOptions + /// (*** include-it-raw ***) - Include "it" value from the subsequent snippet here as raw text (Not formatted as fsi) + /// (*** include-it-raw:foo ***) - Include "it" value from a named snippet as raw text (Not formatted as fsi) + | ItRawReference of string * LiterateParagraphOptions + /// (*** include-value:foo ***) - Include the formatting of a specified value here | ValueReference of string * LiterateParagraphOptions @@ -86,6 +90,7 @@ type LiterateParagraph = | FsiOutputReference(_,popts) -> popts | OutputReference(_,popts) -> popts | ItValueReference(_,popts) -> popts + | ItRawReference(_,popts) -> popts | ValueReference(_,popts) -> popts | LiterateCode(_,_,popts) -> popts | LanguageTaggedCode(_,_,popts) -> popts diff --git a/src/FSharp.Formatting.Literate/Evaluator.fs b/src/FSharp.Formatting.Literate/Evaluator.fs index 175ea78c4..d8183510e 100644 --- a/src/FSharp.Formatting.Literate/Evaluator.fs +++ b/src/FSharp.Formatting.Literate/Evaluator.fs @@ -20,6 +20,8 @@ type FsiEmbedKind = | ConsoleOutput /// The 'it' value | ItValue + /// The 'it' value as raw text + | ItRaw /// A specific value | Value @@ -376,6 +378,22 @@ module __FsiSettings = let outputText = defaultArg result.FsiMergedOutput "No output has been produced." let output = outputText.Trim() [ OutputBlock (output, "text/plain", Some executionCount) ] + | { ItValue = Some (obj, ty) }, FsiEmbedKind.ItRaw -> + match valueTransformations |> Seq.pick (fun f -> lock lockObj (fun () -> f (obj, ty, executionCount))) with + | [] -> + [ OutputBlock("No value returned by any evaluator", "text/plain", Some executionCount) ] + | blocks -> + blocks + |> List.map (function + | OutputBlock(output,_,Some executionCount) -> + let output = + if ty.FullName = (typeof).FullName then + let l = output.Length + output.Substring(1,l-2) + else + output + OutputBlock(output,"text/html",Some executionCount) + | _ -> OutputBlock("Value could not be returned raw", "text/plain", Some executionCount)) | { ItValue = Some (obj, ty) }, FsiEmbedKind.ItValue | { Result = Some (obj, ty) }, FsiEmbedKind.Value -> match valueTransformations |> Seq.pick (fun f -> lock lockObj (fun () -> f (obj, ty, executionCount))) with diff --git a/src/FSharp.Formatting.Literate/ParseScript.fs b/src/FSharp.Formatting.Literate/ParseScript.fs index 5f6cfb556..21b2fec9c 100644 --- a/src/FSharp.Formatting.Literate/ParseScript.fs +++ b/src/FSharp.Formatting.Literate/ParseScript.fs @@ -194,6 +194,18 @@ type internal ParseScript(parseOptions, ctx:CompilerContext) = let p = EmbedParagraphs(ItValueReference(ref, popts), None) transformBlocks None count noEval (p::acc) defs blocks + // Include unformatted 'it' of previous block + | BlockCommand((Command "include-it-raw" "") as cmds)::blocks when prevCodeId.IsSome -> + let popts = getParaOptions cmds + let p1 = EmbedParagraphs(ItRawReference(prevCodeId.Value, popts), None) + transformBlocks prevCodeId count noEval (p1::acc) defs blocks + + // Include unformatted 'it' of a named block + | BlockCommand(Command "include-it-raw" ref as cmds)::blocks -> + let popts = getParaOptions cmds + let p = EmbedParagraphs(ItRawReference(ref, popts), None) + transformBlocks None count noEval (p::acc) defs blocks + // Include formatted named value | BlockCommand(Command "include-value" ref as cmds)::blocks -> let popts = getParaOptions cmds diff --git a/src/FSharp.Formatting.Literate/Transformations.fs b/src/FSharp.Formatting.Literate/Transformations.fs index 6e4320c8a..09d15ef1f 100644 --- a/src/FSharp.Formatting.Literate/Transformations.fs +++ b/src/FSharp.Formatting.Literate/Transformations.fs @@ -295,6 +295,7 @@ module internal Transformations = | FsiOutputReference (ref, _popts) | OutputReference (ref, _popts) | ItValueReference (ref, _popts) + | ItRawReference (ref, _popts) | ValueReference (ref, _popts) -> let key = (match special with ValueReference _ -> ValueRef ref | _ -> OutputRef ref) match results.TryFind(key) with @@ -305,6 +306,7 @@ module internal Transformations = | FsiOutputReference _ -> FsiEmbedKind.FsiOutput | OutputReference _ -> FsiEmbedKind.ConsoleOutput | ItValueReference _ -> FsiEmbedKind.ItValue + | ItRawReference _ -> FsiEmbedKind.ItRaw | ValueReference _ -> FsiEmbedKind.Value | _ -> failwith "unreachable" ctx.Evaluator.Value.Format(result, kind, executionCount) @@ -385,6 +387,7 @@ module internal Transformations = | FsiOutputReference _ | OutputReference _ | ItValueReference _ + | ItRawReference _ | ValueReference _ -> let msg = "Warning: Output, it-value and value references require --eval" printfn "%s" msg diff --git a/tests/FSharp.Literate.Tests/EvalTests.fs b/tests/FSharp.Literate.Tests/EvalTests.fs index d574a5ca3..f9df6be06 100644 --- a/tests/FSharp.Literate.Tests/EvalTests.fs +++ b/tests/FSharp.Literate.Tests/EvalTests.fs @@ -348,6 +348,20 @@ let ``Can hide and include-it`` () = html1 |> shouldContainText "2000" html1 |> shouldNotContainText "1000" +[] +let ``Can hide and include-it-raw`` () = + let content = """ +1000+1000 +|> string +(*** include-it-raw ***) +""" + let fsie = getFsiEvaluator() + let doc1 = Literate.ParseScriptString(content, "." "A.fsx", formatAgent=getFormatAgent(), fsiEvaluator = fsie) + let html1 = Literate.ToHtml(doc1) + html1 |> shouldContainText "2000" + html1 |> shouldNotContainText "\"2000\"" + html1 |> shouldNotContainText "2000" + [] let ``Can include-output`` () = let content = """