Skip to content

Commit 139fd6f

Browse files
tpetriceksylvanc
authored andcommitted
Add support for FsLab-compatible AddHtmlPrinter (#96)
1 parent 9a4a3e1 commit 139fd6f

File tree

5 files changed

+57
-9
lines changed

5 files changed

+57
-9
lines changed

paket.dependencies

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ framework: >= net451
22
source https://www.nuget.org/api/v2
33

44
nuget FSharp.Compiler.Service
5+
nuget FSharp.Compiler.Tools
56
nuget AsyncIO = 0.1.20.0
67
nuget NetMQ
78
nuget Newtonsoft.Json

paket.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ NUGET
88
FSharp.Compiler.Service (8.0)
99
System.Collections.Immutable (>= 1.2)
1010
System.Reflection.Metadata (>= 1.4.1-beta-24227-04)
11+
FSharp.Compiler.Tools (4.0.1.10)
1112
FSharp.Core (4.0.0.1)
1213
Mono.Cecil (0.9.6.4)
1314
NetMQ (3.3.3.4)

src/IfSharp.Kernel/Evaluation.fs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,49 @@ open Microsoft.FSharp.Compiler.Interactive.Shell
88
[<AutoOpen>]
99
module Evaluation =
1010

11-
let internal fsiout = ref false
12-
let internal sbOut = new StringBuilder()
13-
let internal sbErr = new StringBuilder()
14-
let internal inStream = new StringReader("")
15-
let internal outStream = new StringWriter(sbOut)
16-
let internal errStream = new StringWriter(sbErr)
17-
let internal fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
18-
let internal fsiEval = FsiEvaluationSession.Create(fsiConfig, [|"--noninteractive"|], inStream, outStream, errStream)
11+
/// Extend the `fsi` object with `fsi.AddHtmlPrinter`
12+
let addHtmlPrinter = """
13+
module FsInteractiveService =
14+
let mutable htmlPrinters = new ResizeArray<System.Type * (obj -> seq<string * string> * string)>()
15+
let htmlPrinterParams = System.Collections.Generic.Dictionary<string, obj>()
16+
do htmlPrinterParams.["html-standalone-output"] <- false
17+
18+
type Microsoft.FSharp.Compiler.Interactive.InteractiveSession with
19+
member x.HtmlPrinterParameters = FsInteractiveService.htmlPrinterParams
20+
member x.AddHtmlPrinter<'T>(f:'T -> seq<string * string> * string) =
21+
FsInteractiveService.htmlPrinters.Add(typeof<'T>, fun (value:obj) ->
22+
f (value :?> 'T))"""
23+
24+
/// Start the F# interactive session with HAS_FSI_ADDHTMLPRINTER symbol defined
25+
let internal startSession () =
26+
let sbOut = new StringBuilder()
27+
let sbErr = new StringBuilder()
28+
let inStream = new StringReader("")
29+
let outStream = new StringWriter(sbOut)
30+
let errStream = new StringWriter(sbErr)
1931

32+
let fsiObj = Microsoft.FSharp.Compiler.Interactive.Settings.fsi
33+
let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration(fsiObj, false)
34+
let args = [|"--noninteractive"; "--define:HAS_FSI_ADDHTMLPRINTER" |]
35+
let fsiSession = FsiEvaluationSession.Create(fsiConfig, args, inStream, outStream, errStream)
36+
37+
// Load the `fsi` object from the right location of the `FSharp.Compiler.Interactive.Settings.dll`
38+
// assembly and add the `fsi.AddHtmlPrinter` extension method; then clean it from FSI output
39+
let origLength = sbOut.Length
40+
let fsiLocation = typeof<Microsoft.FSharp.Compiler.Interactive.InteractiveSession>.Assembly.Location
41+
fsiSession.EvalInteraction("#r @\"" + fsiLocation + "\"")
42+
fsiSession.EvalInteraction(addHtmlPrinter)
43+
sbOut.Remove(origLength, sbOut.Length-origLength) |> ignore
44+
45+
// Get reference to the extra HTML printers registered inside the FSI session
46+
let extraPrinters =
47+
unbox<ResizeArray<System.Type * (obj -> seq<string * string> * string)>>
48+
(fsiSession.EvalExpression("FsInteractiveService.htmlPrinters").Value.ReflectionValue)
49+
sbErr, sbOut, extraPrinters, fsiSession
50+
51+
let internal fsiout = ref false
52+
let internal sbErr, sbOut, extraPrinters, fsiEval = startSession ()
53+
2054
/// Gets `it` only if `it` was printed to the console
2155
let GetLastExpression() =
2256

src/IfSharp.Kernel/IfSharp.Kernel.fsproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@
9898
<Content Include="app.config" />
9999
</ItemGroup>
100100
<ItemGroup>
101+
<Reference Include="FSharp.Compiler.Interactive.Settings">
102+
<HintPath>..\..\packages\FSharp.Compiler.Tools\tools\FSharp.Compiler.Interactive.Settings.dll</HintPath>
103+
</Reference>
101104
<Reference Include="mscorlib" />
102105
<Reference Include="NuGet">
103106
<HintPath>..\..\lib\NuGet.dll</HintPath>

src/IfSharp.Kernel/Printers.fs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,17 @@ module Printers =
2424

2525
/// Finds a display printer based off of the type
2626
let findDisplayPrinter(findType) =
27+
// Get printers that were registered using `fsi.AddHtmlPrinter` and turn them
28+
// into printers expected here (just contactenate all <script> tags with HTML)
29+
let extraPrinters =
30+
Evaluation.extraPrinters
31+
|> Seq.map (fun (t, p) -> t, fun o ->
32+
let extras, html = p o
33+
let extras = extras |> Seq.map snd |> String.concat ""
34+
{ ContentType = "text/html"; Data = extras + html })
35+
2736
let printers =
28-
displayPrinters
37+
Seq.append displayPrinters extraPrinters
2938
|> Seq.filter (fun (t, _) -> t.IsAssignableFrom(findType))
3039
|> Seq.toList
3140

0 commit comments

Comments
 (0)