diff --git a/MLS.Agent/CommandLine/CommandLineParser.cs b/MLS.Agent/CommandLine/CommandLineParser.cs
index f08cb70ac..49d6a6f7f 100644
--- a/MLS.Agent/CommandLine/CommandLineParser.cs
+++ b/MLS.Agent/CommandLine/CommandLineParser.cs
@@ -545,6 +545,7 @@ private static IKernel CreateKernel(string defaultKernelName)
.UseXplot(),
new FSharpKernel()
.UseDefaultRendering()
+ .UseKernelHelpers()
.UseXplot()
}
.UseDefaultMagicCommands()
diff --git a/Microsoft.DotNet.Interactive.FSharp/FSharpKernelHelpers.fs b/Microsoft.DotNet.Interactive.FSharp/FSharpKernelHelpers.fs
new file mode 100644
index 000000000..8da70830f
--- /dev/null
+++ b/Microsoft.DotNet.Interactive.FSharp/FSharpKernelHelpers.fs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.DotNet.Interactive.FSharp
+
+open Microsoft.DotNet.Interactive
+
+module FSharpKernelHelpers =
+ let display (value: obj) =
+ Kernel.display value
+ let Javascript (content: string) =
+ Kernel.Javascript content
diff --git a/Microsoft.DotNet.Interactive.FSharp/Microsoft.DotNet.Interactive.FSharp.fsproj b/Microsoft.DotNet.Interactive.FSharp/Microsoft.DotNet.Interactive.FSharp.fsproj
index f59340c3c..6083183f3 100644
--- a/Microsoft.DotNet.Interactive.FSharp/Microsoft.DotNet.Interactive.FSharp.fsproj
+++ b/Microsoft.DotNet.Interactive.FSharp/Microsoft.DotNet.Interactive.FSharp.fsproj
@@ -17,6 +17,7 @@
+
diff --git a/WorkspaceServer.Tests/Kernel/CSharpKernelRenderingTests.cs b/WorkspaceServer.Tests/Kernel/LanguageKernelRenderingTests.cs
similarity index 58%
rename from WorkspaceServer.Tests/Kernel/CSharpKernelRenderingTests.cs
rename to WorkspaceServer.Tests/Kernel/LanguageKernelRenderingTests.cs
index 2d31721c7..9231ff662 100644
--- a/WorkspaceServer.Tests/Kernel/CSharpKernelRenderingTests.cs
+++ b/WorkspaceServer.Tests/Kernel/LanguageKernelRenderingTests.cs
@@ -1,12 +1,11 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using System;
+using System.Linq;
using System.Reactive.Linq;
+using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Extensions;
-using System.Linq;
-using System.Threading.Tasks;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
@@ -16,23 +15,31 @@
using Xunit.Abstractions;
using static Pocket.Logger;
+#pragma warning disable 8509
namespace WorkspaceServer.Tests.Kernel
{
- public class CSharpKernelRenderingTests : LanguageKernelTestBase
+ public class LanguageKernelRenderingTests : LanguageKernelTestBase
{
- public CSharpKernelRenderingTests(ITestOutputHelper output) : base(output)
+ public LanguageKernelRenderingTests(ITestOutputHelper output) : base(output)
{
}
[Theory]
- [InlineData("b(123) // PocketView", "123")]
- [InlineData("new[] { 1, 2, 3, 4 } // sequence", "
")]
- [InlineData("new[] { new { a = 123 }, new { a = 456 } } // sequence of anonymous objects", "")]
+ // PocketView
+ [InlineData(Language.CSharp, "b(123)", "123")]
+ [InlineData(Language.FSharp, "b.innerHTML(123)", "123")]
+ // sequence
+ [InlineData(Language.CSharp, "new[] { 1, 2, 3, 4 }", "")]
+ [InlineData(Language.FSharp, "[1; 2; 3; 4]", "")]
+ // sequence of anonymous objects
+ [InlineData(Language.CSharp, "new[] { new { a = 123 }, new { a = 456 } }", "")]
+ [InlineData(Language.FSharp, "[{| a = 123 |}; {| a = 456 |}]", "")]
public async Task Default_rendering_is_HTML(
+ Language language,
string submission,
string expectedContent)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
var result = await kernel.SendAsync(new SubmitCode(submission));
@@ -53,14 +60,18 @@ public async Task Default_rendering_is_HTML(
}
[Theory]
- [InlineData("div(123).ToString()", "123
")]
- [InlineData("display(div(123).ToString());", "123
")]
- [InlineData("\"hi\"", "hi")]
+ [InlineData(Language.CSharp, "div(123).ToString()", "123
")]
+ [InlineData(Language.FSharp, "div.innerHTML(123).ToString()", "123
")]
+ [InlineData(Language.CSharp, "display(div(123).ToString());", "123
")]
+ [InlineData(Language.FSharp, "display(div.innerHTML(123).ToString())", "123
")]
+ [InlineData(Language.CSharp, "\"hi\"", "hi")]
+ [InlineData(Language.FSharp, "\"hi\"", "hi")]
public async Task String_is_rendered_as_plain_text(
+ Language language,
string submission,
string expectedContent)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
var result = await kernel.SendAsync(new SubmitCode(submission));
@@ -78,12 +89,20 @@ public async Task String_is_rendered_as_plain_text(
v.Value.ToString().Contains(expectedContent));
}
- [Fact]
- public async Task Display_helper_can_be_called_without_specifying_class_name()
+ [Theory]
+ [InlineData(Language.CSharp)]
+ [InlineData(Language.FSharp)]
+ public async Task Display_helper_can_be_called_without_specifying_class_name(Language language)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
+
+ var submission = language switch
+ {
+ Language.CSharp => "display(b(\"hi!\"));",
+ Language.FSharp => "display(b.innerHTML(\"hi!\"));",
+ };
- await kernel.SendAsync(new SubmitCode("display(b(\"hi!\"));"));
+ await kernel.SendAsync(new SubmitCode(submission));
var formatted =
KernelEvents
@@ -98,13 +117,20 @@ public async Task Display_helper_can_be_called_without_specifying_class_name()
v.Value.ToString().Contains("hi!"));
}
- [Fact]
- public async Task Displayed_value_can_be_updated()
+ [Theory]
+ [InlineData(Language.CSharp)]
+ [InlineData(Language.FSharp)]
+ public async Task Displayed_value_can_be_updated(Language language)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
- await kernel.SendAsync(new SubmitCode("var d = display(b(\"hello\")); d.Update(b(\"world\"));"));
+ var submission = language switch
+ {
+ Language.CSharp => "var d = display(b(\"hello\")); d.Update(b(\"world\"));",
+ Language.FSharp => "let d = display(b.innerHTML(\"hello\"))\nd.Update(b.innerHTML(\"world\"))",
+ };
+ await kernel.SendAsync(new SubmitCode(submission));
KernelEvents
.OrderBy(e => e.Timestamp)
@@ -128,12 +154,20 @@ public async Task Displayed_value_can_be_updated()
v.Value.ToString().Contains("world"));
}
- [Fact]
- public async Task Value_display_and_update_are_in_right_order()
+ [Theory]
+ [InlineData(Language.CSharp)]
+ [InlineData(Language.FSharp)]
+ public async Task Value_display_and_update_are_in_right_order(Language language)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
+
+ var submission = language switch
+ {
+ Language.CSharp => "var d = display(b(\"hello\")); d.Update(b(\"world\"));",
+ Language.FSharp => "let d = display(b.innerHTML(\"hello\"))\nd.Update(b.innerHTML(\"world\"))",
+ };
- await kernel.SendAsync(new SubmitCode("var d = display(b(\"hello\")); d.Update(b(\"world\"));"));
+ await kernel.SendAsync(new SubmitCode(submission));
var valueEvents =
KernelEvents
@@ -146,14 +180,22 @@ public async Task Value_display_and_update_are_in_right_order()
valueEvents.Last().Should().BeOfType();
}
- [Fact]
- public async Task Javascript_helper_emits_string_as_content_within_a_script_element()
+ [Theory]
+ [InlineData(Language.CSharp)]
+ [InlineData(Language.FSharp)]
+ public async Task Javascript_helper_emits_string_as_content_within_a_script_element(Language language)
{
- var kernel = CreateKernel();
+ var kernel = CreateKernel(language);
var scriptContent = "alert('Hello World!');";
- await kernel.SendAsync(new SubmitCode($@"Javascript(""{scriptContent}"");"));
+ var submission = language switch
+ {
+ Language.CSharp => $@"Javascript(""{scriptContent}"");",
+ Language.FSharp => $@"Javascript(""{scriptContent}"")",
+ };
+
+ await kernel.SendAsync(new SubmitCode(submission));
var formatted =
KernelEvents
diff --git a/WorkspaceServer.Tests/Kernel/LanguageKernelTestBase.cs b/WorkspaceServer.Tests/Kernel/LanguageKernelTestBase.cs
index 51099705f..7507b22b3 100644
--- a/WorkspaceServer.Tests/Kernel/LanguageKernelTestBase.cs
+++ b/WorkspaceServer.Tests/Kernel/LanguageKernelTestBase.cs
@@ -27,7 +27,7 @@ private KernelBase CreateLanguageKernel(Language language)
{
var kernelBase = language switch
{
- Language.FSharp => (KernelBase) new FSharpKernel().UseDefaultRendering(),
+ Language.FSharp => (KernelBase) new FSharpKernel().UseDefaultRendering().UseKernelHelpers(),
Language.CSharp => new CSharpKernel().UseDefaultRendering().UseExtendDirective().UseKernelHelpers(),
_ => throw new InvalidOperationException("Unknown language specified")
};
diff --git a/WorkspaceServer/Kernel/FSharpKernelExtensions.cs b/WorkspaceServer/Kernel/FSharpKernelExtensions.cs
index 460b3ff51..1fce2f256 100644
--- a/WorkspaceServer/Kernel/FSharpKernelExtensions.cs
+++ b/WorkspaceServer/Kernel/FSharpKernelExtensions.cs
@@ -29,6 +29,17 @@ public static FSharpKernel UseDefaultRendering(
return kernel;
}
+ public static FSharpKernel UseKernelHelpers(
+ this FSharpKernel kernel)
+ {
+ Task.Run(() =>
+ kernel.SendAsync(new SubmitCode($@"
+open {typeof(FSharpKernelHelpers).FullName}
+"))).Wait();
+
+ return kernel;
+ }
+
private static string ReferenceFromType(Type type)
{
return $@"#r ""{type.Assembly.Location.Replace("\\", "\\\\")}""";