这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions DotNetTry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.Interactiv
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XPlot.DotNet.Interactive.KernelExtensions", "XPlot.DotNet.Interactive.KernelExtensions\XPlot.DotNet.Interactive.KernelExtensions.csproj", "{90A9DF5F-CBEE-4B6B-8B58-BA94B0BDCF3C}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Microsoft.DotNet.Interactive.FSharp", "Microsoft.DotNet.Interactive.FSharp\Microsoft.DotNet.Interactive.FSharp.fsproj", "{12821999-9F44-486B-8EE3-38F0EFDFDA32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -187,6 +189,10 @@ Global
{90A9DF5F-CBEE-4B6B-8B58-BA94B0BDCF3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90A9DF5F-CBEE-4B6B-8B58-BA94B0BDCF3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90A9DF5F-CBEE-4B6B-8B58-BA94B0BDCF3C}.Release|Any CPU.Build.0 = Release|Any CPU
{12821999-9F44-486B-8EE3-38F0EFDFDA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12821999-9F44-486B-8EE3-38F0EFDFDA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12821999-9F44-486B-8EE3-38F0EFDFDA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12821999-9F44-486B-8EE3-38F0EFDFDA32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -221,6 +227,7 @@ Global
{113A4166-5734-4F6E-B609-D6CF42679399} = {6EE8F484-DFA2-4F0F-939F-400CE78DFAC2}
{2BB7CCD7-73D1-4B16-82EC-A5D0183F8CF5} = {6EE8F484-DFA2-4F0F-939F-400CE78DFAC2}
{90A9DF5F-CBEE-4B6B-8B58-BA94B0BDCF3C} = {6EE8F484-DFA2-4F0F-939F-400CE78DFAC2}
{12821999-9F44-486B-8EE3-38F0EFDFDA32} = {6EE8F484-DFA2-4F0F-939F-400CE78DFAC2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D6CD99BA-B16B-4570-8910-225CBDFFA3AD}
Expand Down
2 changes: 1 addition & 1 deletion MLS.Agent.Tests/CommandLine/PackCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
using System.Threading.Tasks;
using FluentAssertions;
using MLS.Agent.CommandLine;
using MLS.Agent.Tools;
using WorkspaceServer;
using WorkspaceServer.Tests;
using WorkspaceServer.WorkspaceFeatures;
using Xunit;

namespace MLS.Agent.Tests.CommandLine
Expand Down
31 changes: 1 addition & 30 deletions WorkspaceServer/Dotnet.cs → MLS.Agent.Tools/Dotnet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
using System.Reflection;
using System.Threading.Tasks;
using Clockwise;
using MLS.Agent.Tools;

namespace WorkspaceServer
namespace MLS.Agent.Tools
{
public class Dotnet
{
Expand Down Expand Up @@ -97,34 +96,6 @@ public async Task<IEnumerable<string>> ToolList(DirectoryInfo directory, Budget
.Select(s => s.Split(separator, StringSplitOptions.RemoveEmptyEntries)[2]);
}

private string RemoveTrailingSlash(string path)
{
// dotnet tool install doesn't like it if directory arguments end with "/"
if (path.EndsWith("\\"))
{
return path.Substring(0, path.Length - 1);
}

return path;
}

public Task<CommandLineResult> ToolInstall(
string packageName,
DirectoryInfo toolPath,
PackageSource addSource = null,
Budget budget = null,
string version = null)
{
var versionArg = version != null ? $"--version {version}" : "";
var args = $@"{packageName} --tool-path ""{RemoveTrailingSlash(toolPath.FullName)}"" {versionArg}";
if (addSource != null)
{
args += $@" --add-source ""{addSource}""";
}

return Execute("tool install".AppendArgs(args), budget);
}

public Task<CommandLineResult> Pack(string args = null, Budget budget = null) =>
Execute("pack".AppendArgs(args), budget);

Expand Down
16 changes: 16 additions & 0 deletions MLS.Agent.Tools/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace MLS.Agent.Tools
{
Expand All @@ -23,5 +24,20 @@ public static void DeleteFileSystemObject(this string path)
throw new ArgumentException($"Couldn't find a file or directory called {path}");
}
}

public static string ExecutableName(this string withoutExtension) =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? withoutExtension + ".exe"
: withoutExtension;

public static string RemoveTrailingSlash(this string path)
{
if (path.EndsWith("\\"))
{
return path.Substring(0, path.Length - 1);
}

return path;
}
}
}
8 changes: 5 additions & 3 deletions MLS.Agent/CommandLine/CommandLineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.FSharp;
using Microsoft.DotNet.Interactive.Jupyter;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -508,10 +509,11 @@ private static CompositeKernel CreateKernel()
new CSharpKernel()
.UseDefaultRendering()
.UseNugetDirective()
.UseExtendDirective()
.UseKernelHelpers()
.UseXplot()
};
.UseXplot(),
new FSharpKernel()
.UseDefaultRendering()
}.UseExtendDirective();
}
}
}
79 changes: 79 additions & 0 deletions Microsoft.DotNet.Interactive.FSharp/FSharpKernel.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 System
open System.ComponentModel
open System.Diagnostics
open System.Text
open System.Threading.Tasks
open Microsoft.DotNet.Interactive
open Microsoft.DotNet.Interactive.Commands
open Microsoft.DotNet.Interactive.Events
open MLS.Agent.Tools

type FSharpKernel() =
inherit KernelBase()
let mutable proc: Process = null
let write (s: string) = proc.StandardInput.Write(s)
let sentinelValue = Guid.NewGuid().ToString()
let sentinelFound = Event<_>()
let stdout = StringBuilder()
let waitForReady () =
async {
write <| sprintf ";;printfn \"\\n%s\";;\n" sentinelValue
do! Async.AwaitEvent sentinelFound.Publish
}
let startProcess () =
async {
if isNull proc then
let outputReceived line =
if line = sentinelValue then
sentinelFound.Trigger()
else
stdout.AppendLine(line) |> ignore
proc <- Dotnet().StartProcess("fsi --nologo", output = Action<string>(outputReceived))
do! waitForReady()
}
let eval (code: string) =
async {
do! startProcess ()
stdout.Clear() |> ignore
write code
do! waitForReady ()
let value = stdout.ToString()
// trim garbage
let nl = Environment.NewLine
let headerGarbage = sprintf "val it : unit = ()%s%s" nl nl
let value = if value.StartsWith(headerGarbage) then value.Substring(headerGarbage.Length) else value
let footerGarbage = sprintf "%s%s> %s" nl nl nl
let value = if value.EndsWith(footerGarbage) then value.Substring(0, value.Length - footerGarbage.Length) else value
return value
}
do base.AddDisposable({ new IDisposable with
member __.Dispose() =
if not <| isNull proc then
try
proc.Kill()
with
| :? InvalidOperationException -> ()
| :? NotSupportedException -> ()
| :? Win32Exception -> () })
let handleSubmitCode (codeSubmission: SubmitCode) (context: KernelInvocationContext) =
async {
let codeSubmissionReceived = CodeSubmissionReceived(codeSubmission.Code, codeSubmission)
context.OnNext(codeSubmissionReceived)
// submit code
let! value = eval codeSubmission.Code
context.OnNext(ValueProduced(value, codeSubmission, true, [FormattedValue("text/plain", value)]))
context.OnNext(CodeSubmissionEvaluated(codeSubmission))
context.OnCompleted()
}
override __.Name = "fsharp"
override __.HandleAsync(command: IKernelCommand, _context: KernelInvocationContext): Task =
async {
match command with
| :? SubmitCode as submitCode -> submitCode.Handler <- fun invocationContext -> (handleSubmitCode submitCode invocationContext) |> Async.StartAsTask :> Task
| _ -> ()
} |> Async.StartAsTask :> Task
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PublishWindowsPdb>false</PublishWindowsPdb>
</PropertyGroup>

<ItemGroup>
<Compile Include="FSharpKernel.fs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Microsoft.DotNet.Interactive\Microsoft.DotNet.Interactive.csproj" />
<ProjectReference Include="..\MLS.Agent.Tools\MLS.Agent.Tools.csproj" />
</ItemGroup>

</Project>
46 changes: 9 additions & 37 deletions WorkspaceServer.Tests/Kernel/CSharpKernelTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,52 +1,24 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// 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.Collections.Generic;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Events;
using Pocket;
using WorkspaceServer.Kernel;
using Xunit.Abstractions;
using System.Reactive.Linq;
using System.Reactive;

namespace WorkspaceServer.Tests.Kernel
{
public abstract class CSharpKernelTestBase : IDisposable
public abstract class CSharpKernelTestBase : KernelTestBase
{
protected CSharpKernelTestBase(ITestOutputHelper output)
public CSharpKernelTestBase(ITestOutputHelper output) : base(output)
{
DisposeAfterTest(output.SubscribeToPocketLogger());
}

protected CSharpKernel CreateKernel()
protected override KernelBase CreateBaseKernel()
{
var kernel = new CSharpKernel()
.UseDefaultRendering()
.UseNugetDirective()
.UseExtendDirective()
.UseKernelHelpers()
.LogEventsToPocketLogger();

DisposeAfterTest(
kernel.KernelEvents.Timestamp().Subscribe(KernelEvents.Add));

return kernel;
}

private readonly CompositeDisposable _disposables = new CompositeDisposable();

protected IList<Timestamped<IKernelEvent>> KernelEvents { get; } = new List<Timestamped<IKernelEvent>>();

protected void DisposeAfterTest(IDisposable disposable)
{
_disposables.Add(disposable);
}

public void Dispose()
{
_disposables?.Dispose();
return new CSharpKernel()
.UseDefaultRendering()
.UseExtendDirective()
.UseKernelHelpers();
}
}
}
}
5 changes: 3 additions & 2 deletions WorkspaceServer.Tests/Kernel/CSharpKernelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

using System;
using System.IO;
using FluentAssertions;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using FluentAssertions.Extensions;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
Expand All @@ -16,7 +18,6 @@
using WorkspaceServer.Kernel;
using Xunit;
using Xunit.Abstractions;
using FluentAssertions.Extensions;

namespace WorkspaceServer.Tests.Kernel
{
Expand Down
57 changes: 57 additions & 0 deletions WorkspaceServer.Tests/Kernel/FSharpKernelTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.FSharp;
using WorkspaceServer.Kernel;
using Xunit;
using Xunit.Abstractions;

namespace WorkspaceServer.Tests.Kernel
{
public class FSharpKernelTests : KernelTestBase
{
public FSharpKernelTests(ITestOutputHelper output) : base(output)
{
}

protected override KernelBase CreateBaseKernel()
{
return new FSharpKernel()
.UseDefaultRendering();
}

[Fact]
public async Task it_returns_an_object_value()
{
var kernel = CreateKernel();
await kernel.SendAsync(new SubmitCode("123"));
AssertLastValue("> val it : int = 123");
}

[Fact]
public async Task it_remembers_state_between_submissions()
{
var kernel = CreateKernel();
await kernel.SendAsync(new SubmitCode("let add x y = x + y"));
AssertLastValue("> val add : x:int -> y:int -> int");
await kernel.SendAsync(new SubmitCode("add 2 3"));
AssertLastValue("> val it : int = 5");
}

private void AssertLastValue(string value)
{
KernelEvents.ValuesOnly()
.OfType<ValueProduced>()
.Last()
.Value
.Should()
.Be(value);
}
}
}
Loading