这是indexloc提供的服务,不要输入任何密码
Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
Expand All @@ -31,7 +30,7 @@ public async Task Handle(JupyterRequestContext context)

var command = new RequestCompletion(completeRequest.Code, completeRequest.CursorPosition);

var openRequest = new InflightRequest(context, completeRequest, 0, null);
var openRequest = new InflightRequest(context, completeRequest, 0);

InFlightRequests[command] = openRequest;

Expand Down
29 changes: 20 additions & 9 deletions Microsoft.DotNet.Interactive.Jupyter/ExecuteRequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Events;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
public class ExecuteRequestHandler : RequestHandlerBase<ExecuteRequest>
{
private int _executionCount;

public ExecuteRequestHandler(IKernel kernel) : base(kernel)
{
}
Expand All @@ -30,9 +29,8 @@ public async Task Handle(JupyterRequestContext context)
var executionCount = executeRequest.Silent ? _executionCount : Interlocked.Increment(ref _executionCount);

var command = new SubmitCode(executeRequest.Code, "csharp");
var id = Guid.NewGuid();
var transient = new Dictionary<string, object> { { "display_id", id.ToString() } };
var openRequest = new InflightRequest(context, executeRequest, executionCount, transient);

var openRequest = new InflightRequest(context, executeRequest, executionCount);

InFlightRequests[command] = openRequest;

Expand Down Expand Up @@ -79,6 +77,13 @@ public async Task Handle(JupyterRequestContext context)
}
}

private static Dictionary<string, object> CreateTransient()
{
var id = Guid.NewGuid();
var transient = new Dictionary<string, object> { { "display_id", id.ToString() } };
return transient;
}

void OnKernelResultEvent(IKernelEvent value)
{
switch (value)
Expand All @@ -96,7 +101,7 @@ void OnKernelResultEvent(IKernelEvent value)
case IncompleteCodeSubmissionReceived _:
case CompleteCodeSubmissionReceived _:
break;
default:
default:
throw new NotSupportedException();
}
}
Expand Down Expand Up @@ -152,12 +157,18 @@ private static void OnValueProduced(

try
{
var transient = CreateTransient();
// executeResult data
var executeResultData = new ExecuteResult(
var executeResultData = valueProduced.IsLastValue
? new ExecuteResult(
openRequest.ExecutionCount,
transient: openRequest.Transient,
transient: transient,
data: valueProduced?.FormattedValues
?.ToDictionary(k => k.MimeType, v => v.Value))
: new DisplayData(
transient: transient,
data: valueProduced?.FormattedValues
?.ToDictionary(k => k.MimeType ?? "text/plain", v => v.Value));
?.ToDictionary(k => k.MimeType, v => v.Value));

if (!openRequest.Request.Silent)
{
Expand Down
6 changes: 1 addition & 5 deletions Microsoft.DotNet.Interactive.Jupyter/RequestHandlerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Reactive.Disposables;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Jupyter.Protocol;
using WorkspaceServer.Kernel;

namespace Microsoft.DotNet.Interactive.Jupyter
{
Expand Down Expand Up @@ -41,18 +40,15 @@ public void Dispose()
protected class InflightRequest : IDisposable
{
private readonly CompositeDisposable _disposables = new CompositeDisposable();
public Dictionary<string, object> Transient { get; }
public JupyterRequestContext Context { get; }
public T Request { get; }
public int ExecutionCount { get; }

public InflightRequest(JupyterRequestContext context, T request, int executionCount,
Dictionary<string, object> transient)
public InflightRequest(JupyterRequestContext context, T request, int executionCount)
{
Context = context;
Request = request;
ExecutionCount = executionCount;
Transient = transient;
}

public void AddDisposable(IDisposable disposable)
Expand Down
4 changes: 2 additions & 2 deletions Microsoft.DotNet.Interactive.Rendering/Formatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Interactive.Rendering
/// </summary>
public static class Formatter
{
private const string DefaultMimeType = "text/plain";
private static Func<Type, bool> _autoGenerateForType = t => false;
private static int _defaultListExpansionLimit;
private static int _recursionLimit;
Expand Down Expand Up @@ -358,8 +359,7 @@ private static void TryRegisterDefault(string typeName, Action<object, TextWrite

public static string MimeTypeFor(Type type)
{
_mimeTypesByType.TryGetValue(type, out var mimeType);
return mimeType;
return _mimeTypesByType.TryGetValue(type, out var mimeType) ? mimeType : DefaultMimeType;
}

public static void SetMimeType(Type type, string mimeType)
Expand Down
3 changes: 2 additions & 1 deletion Microsoft.DotNet.Interactive.Rendering/PocketView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ private void SetContent(object[] args)
break;

default:
if (Formatter.MimeTypeFor(item.GetType()) != null)
var mimeType = Formatter.MimeTypeFor(item.GetType());
if (mimeType != null && mimeType != "text/plain")
{
item.FormatTo(writer);
}
Expand Down
6 changes: 4 additions & 2 deletions Microsoft.DotNet.Interactive/Events/ValueProduced.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ namespace Microsoft.DotNet.Interactive.Events
{
public class ValueProduced : KernelEventBase
{
public ValueProduced(
object value,
public ValueProduced(object value,
SubmitCode submitCode,
bool isLastValue = false,
IReadOnlyCollection<FormattedValue> formattedValues = null) : base(submitCode)
{
Value = value;
IsLastValue = isLastValue;
FormattedValues = formattedValues;
}

public object Value { get; }
public bool IsLastValue { get; }

public IReadOnlyCollection<FormattedValue> FormattedValues { get; }
}
Expand Down
7 changes: 7 additions & 0 deletions Microsoft.DotNet.Interactive/FormattedValue.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
// 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;

namespace Microsoft.DotNet.Interactive
{
public class FormattedValue
{
public FormattedValue(string mimeType, object value)
{
if (string.IsNullOrWhiteSpace(mimeType))
{
throw new ArgumentException("Value cannot be null or whitespace.", nameof(mimeType));
}

MimeType = mimeType;
Value = value;
}
Expand Down
77 changes: 58 additions & 19 deletions WorkspaceServer.Tests/Kernel/CSharpKernelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public async Task it_returns_the_result_of_a_non_null_expression()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("123", "csharp"));
await kernel.SendAsync(new SubmitCode("123"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -44,9 +44,9 @@ public async Task when_it_throws_exception_after_a_value_was_produced_then_only_
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("2 + 2", "csharp"));
await kernel.SendAsync(new SubmitCode("adddddddddd", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("2 + 2"));
await kernel.SendAsync(new SubmitCode("adddddddddd"));

var (failure, lastCodeSubmissionEvaluationFailedPosition) = KernelEvents
.Select((error, pos) => (error, pos))
Expand Down Expand Up @@ -75,8 +75,8 @@ public async Task it_returns_exceptions_thrown_in_user_code()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("throw new NotImplementedException();", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("throw new NotImplementedException();"));

KernelEvents.Last()
.Should()
Expand All @@ -92,8 +92,8 @@ public async Task it_returns_diagnostics()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("using System;", "csharp"));
await kernel.SendAsync(new SubmitCode("aaaadd", "csharp"));
await kernel.SendAsync(new SubmitCode("using System;"));
await kernel.SendAsync(new SubmitCode("aaaadd"));

KernelEvents.Last()
.Should()
Expand All @@ -109,9 +109,9 @@ public async Task it_notifies_when_submission_is_complete()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var a =", "csharp"));
await kernel.SendAsync(new SubmitCode("var a ="));

await kernel.SendAsync(new SubmitCode("12;", "csharp"));
await kernel.SendAsync(new SubmitCode("12;"));

KernelEvents.Should()
.NotContain(e => e is ValueProduced);
Expand All @@ -126,7 +126,7 @@ public async Task it_notifies_when_submission_is_incomplete()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var a =", "csharp"));
await kernel.SendAsync(new SubmitCode("var a ="));

KernelEvents.Should()
.NotContain(e => e is ValueProduced);
Expand All @@ -141,7 +141,7 @@ public async Task it_returns_the_result_of_a_null_expression()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("null", "csharp"));
await kernel.SendAsync(new SubmitCode("null"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -155,7 +155,7 @@ public async Task it_does_not_return_a_result_for_a_statement()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var x = 1;", "csharp"));
await kernel.SendAsync(new SubmitCode("var x = 1;"));

KernelEvents
.Should()
Expand All @@ -167,9 +167,9 @@ public async Task it_aggregates_multiple_submissions()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var x = new List<int>{1,2};", "csharp"));
await kernel.SendAsync(new SubmitCode("x.Add(3);", "csharp"));
await kernel.SendAsync(new SubmitCode("x.Max()", "csharp"));
await kernel.SendAsync(new SubmitCode("var x = new List<int>{1,2};"));
await kernel.SendAsync(new SubmitCode("x.Add(3);"));
await kernel.SendAsync(new SubmitCode("x.Max()"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand All @@ -178,13 +178,52 @@ public async Task it_aggregates_multiple_submissions()
.Be(3);
}

[Fact]
public async Task it_produces_values_when_executing_Console_output()
{
var kernel = CreateKernel();

var kernelCommand = new SubmitCode(@"
Console.Write(""value one"");
Console.Write(""value two"");
Console.Write(""value three"");");
await kernel.SendAsync(kernelCommand);

KernelEvents.OfType<ValueProduced>()
.Should()
.BeEquivalentTo(
new ValueProduced("value one", kernelCommand, false, new[] { new FormattedValue("text/plain", "value one"), }),
new ValueProduced("value two", kernelCommand, false, new[] { new FormattedValue("text/plain", "value two"), }),
new ValueProduced("value three", kernelCommand, false, new[] { new FormattedValue("text/plain", "value three"), }));
}

[Fact]
public async Task it_produces_a_final_value_if_the_code_expression_evaluates()
{
var kernel = CreateKernel();

var kernelCommand = new SubmitCode(@"
Console.Write(""value one"");
Console.Write(""value two"");
Console.Write(""value three"");
5", "csharp");
await kernel.SendAsync(kernelCommand);

KernelEvents.OfType<ValueProduced>()
.Should()
.HaveCount(4)
.And
.ContainSingle(e => e.IsLastValue);

}

[Fact(Skip = "requires support for cs8 in roslyn scripting")]
public async Task it_supports_csharp_8()
{
var kernel = CreateKernel();

await kernel.SendAsync(new SubmitCode("var text = \"meow? meow!\";", "csharp"));
await kernel.SendAsync(new SubmitCode("text[^5..^0]", "csharp"));
await kernel.SendAsync(new SubmitCode("var text = \"meow? meow!\";"));
await kernel.SendAsync(new SubmitCode("text[^5..^0]"));

KernelEvents.OfType<ValueProduced>()
.Last()
Expand Down Expand Up @@ -280,7 +319,7 @@ await kernel.SendAsync(
.Should()
.Contain(i => i.DisplayText == "SerializeObject");
}

[Fact]
public async Task The_extend_directive_can_be_used_to_load_a_kernel_extension()
{
Expand Down
Loading