Skip to content

Commit 4dcc5f4

Browse files
authored
Merge pull request #73 from fsprojects/display-types
Add a new notebook specific directive "fsioutput" to capture outputs
2 parents 56516a2 + 2a891a8 commit 4dcc5f4

File tree

5 files changed

+72
-24
lines changed

5 files changed

+72
-24
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace IfSharp.Kernel
2+
3+
module DirectivePreprocessor =
4+
5+
type Line =
6+
| HelpDirective
7+
| FSIOutputDirective
8+
| NugetDirective
9+
| Other
10+
11+
let determineLineType (idx, (line:string)) =
12+
match line.ToLower() with
13+
| line when line.StartsWith "#n" -> NugetDirective
14+
| line when line.StartsWith "#help" -> HelpDirective
15+
| line when line.StartsWith "#fsioutput" -> FSIOutputDirective
16+
| _ -> Other
17+
18+
/// Separates into map of directive types
19+
let partitionLines(lines : string[]) =
20+
lines
21+
|> Seq.mapi (fun (idx) (line) -> (idx, line))
22+
|> Seq.groupBy determineLineType
23+
|> Map.ofSeq
24+
25+
/// Parses a directive line. Example: #N "Deedle"
26+
let parseDirectiveLine (prefix : string) (line : string) =
27+
line.Substring(prefix.Length + 1).Trim().Trim('"')

src/IfSharp.Kernel/Evaluation.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ open Microsoft.FSharp.Compiler.Interactive.Shell
88
[<AutoOpen>]
99
module Evaluation =
1010

11+
let internal fsiout = ref false
1112
let internal sbOut = new StringBuilder()
1213
let internal sbErr = new StringBuilder()
1314
let internal inStream = new StringReader("")

src/IfSharp.Kernel/IfSharp.Kernel.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
<ItemGroup>
7979
<Compile Include="Config.fs" />
8080
<Compile Include="IfSharpResources.fs" />
81+
<Compile Include="DirectivePreprocessor.fs" />
8182
<Compile Include="NuGetManager.fs" />
8283
<Compile Include="FsCompiler.fs" />
8384
<None Include="Include.fsx">

src/IfSharp.Kernel/Kernel.fs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,27 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) =
236236
let results = compiler.NuGetManager.Preprocess(code)
237237
let newCode = String.Join("\n", results.FilteredLines)
238238

239+
if not (Seq.isEmpty results.HelpLines) then
240+
fsiEval.EvalInteraction("#help")
241+
let ifsharpHelp =
242+
""" IF# notebook directives:
243+
244+
#fsioutput ["on"|"off"];; Toggle output display on/off
245+
"""
246+
let fsiHelp = sbOut.ToString()
247+
pyout (ifsharpHelp + fsiHelp)
248+
sbOut.Clear() |> ignore
249+
250+
//This is a persistent toggle, just respect the last one
251+
if not (Seq.isEmpty results.FsiOutputLines) then
252+
let lastFsiOutput = Seq.last results.FsiOutputLines
253+
if lastFsiOutput.ToLower().Contains("on") then
254+
fsiout := true
255+
else if lastFsiOutput.ToLower().Contains("off") then
256+
fsiout := false
257+
else
258+
pyout (sprintf "Unreocognised fsioutput setting: %s" lastFsiOutput)
259+
239260
// do nuget stuff
240261
for package in results.Packages do
241262
if not (String.IsNullOrWhiteSpace(package.Error)) then
@@ -256,6 +277,9 @@ type IfSharpKernel(connectionInformation : ConnectionInformation) =
256277

257278
if not <| String.IsNullOrEmpty(newCode) then
258279
fsiEval.EvalInteraction(newCode)
280+
281+
if fsiout.Value then
282+
pyout (sbOut.ToString())
259283

260284
/// Handles an 'execute_request' message
261285
let executeRequest(msg : KernelMessage) (content : ExecuteRequest) =

src/IfSharp.Kernel/NuGetManager.fs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ type CustomErrorInfo =
5959
type PreprocessResults =
6060
{
6161
OriginalLines : string[];
62+
HelpLines : string[];
63+
FsiOutputLines : string[];
6264
NuGetLines : string[];
6365
FilteredLines : string[];
6466
Packages : NuGetPackage[];
@@ -87,24 +89,6 @@ type CustomInstallCommand() =
8789
let semanticVersion = SemanticVersion(version)
8890
packageManager.LocalRepository.FindPackage(packageId, semanticVersion)
8991

90-
module NuGetManagerInternals =
91-
92-
/// Separates a list of lines between into two partitions, the first list are the directive lines, second list is the other lines
93-
let partitionLines(directive) (lines : string[]) =
94-
lines
95-
|> Seq.mapi (fun (idx) (line) -> (idx, line))
96-
|> Seq.toList
97-
|> List.partition (fun (idx, line) -> line.StartsWith(directive))
98-
99-
/// Separates a list of lines between into two partitions, the first list are the directive lines, second list is the other lines
100-
let partitionSource(directive) (source : string) =
101-
let delimiters = [|"\r\n"; "\n"; "\r";|]
102-
partitionLines directive (source.Split(delimiters, StringSplitOptions.None))
103-
104-
/// Parses a directive line. Example: #N "Deedle"
105-
let parseDirectiveLine (prefix : string) (line : string) =
106-
line.Substring(prefix.Length + 1).Trim().Trim('"')
107-
10892
/// The NuGetManager class contains methods for downloading nuget packages and such
10993
type NuGetManager (executingDirectory : string) =
11094

@@ -231,7 +215,7 @@ type NuGetManager (executingDirectory : string) =
231215
/// prerelease should be used or not.
232216
member this.ParseNugetLine (line : string) =
233217

234-
let contents = NuGetManagerInternals.parseDirectiveLine "#N" line
218+
let contents = DirectivePreprocessor.parseDirectiveLine "#N" line
235219
if contents.Contains("/") then
236220
let splits = contents.Split([| '/' |])
237221
if splits.Length > 2 then
@@ -246,7 +230,15 @@ type NuGetManager (executingDirectory : string) =
246230

247231
// split the source code into lines, then get the nuget lines
248232
let lines = source.Split('\n')
249-
let (nugetLines, otherLines) = NuGetManagerInternals.partitionLines "#N" lines
233+
let linesSplit = DirectivePreprocessor.partitionLines lines
234+
235+
let orEmpty key = let opt = Map.tryFind key linesSplit
236+
if opt.IsSome then opt.Value else Seq.empty
237+
238+
let helpLines = DirectivePreprocessor.Line.HelpDirective |> orEmpty
239+
let fsiOutputLines = DirectivePreprocessor.Line.FSIOutputDirective |> orEmpty
240+
let nugetLines = DirectivePreprocessor.Line.NugetDirective |> orEmpty
241+
let otherLines = DirectivePreprocessor.Line.Other |> orEmpty
250242

251243
// parse the nuget lines and then download the packages
252244
let nugetPackages =
@@ -258,14 +250,17 @@ type NuGetManager (executingDirectory : string) =
258250
// gather errors
259251
let errors =
260252
nugetPackages
261-
|> Seq.filter (fun (idx, package) -> String.IsNullOrEmpty(package.Error) = false)
253+
|> Seq.filter (fun (_, package) -> String.IsNullOrEmpty(package.Error) = false)
262254
|> Seq.map (fun (idx, package) -> CustomErrorInfo.From("", idx, 0, idx, lines.[idx].Length, package.Error, "Error", "preprocess"))
263255
|> Seq.toArray
264256

265257
{
266258
OriginalLines = lines;
267-
NuGetLines = nugetLines |> Seq.map(fun (idx, line) -> line) |> Seq.toArray;
268-
FilteredLines = otherLines |> Seq.map(fun (idx, line) -> line) |> Seq.toArray;
269-
Packages = nugetPackages |> Seq.map(fun (idx, package) -> package) |> Seq.toArray;
259+
HelpLines = helpLines |> Seq.map(fun (_, line) -> line) |> Seq.toArray;
260+
FsiOutputLines = fsiOutputLines |> Seq.map(fun (_, line) -> line) |> Seq.toArray;
261+
NuGetLines = nugetLines |> Seq.map(fun (_, line) -> line) |> Seq.toArray;
262+
263+
FilteredLines = otherLines |> Seq.map(fun (_, line) -> line) |> Seq.toArray;
264+
Packages = nugetPackages |> Seq.map(fun (_, package) -> package) |> Seq.toArray;
270265
Errors = errors;
271266
}

0 commit comments

Comments
 (0)