From f6e9251aba1b5fb1f86461a1eec6bc4a090dc0d0 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Mon, 7 Oct 2024 14:23:47 -0700 Subject: [PATCH 1/3] improve magic command completions --- .../Parsing/PolyglotSyntaxParser.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.DotNet.Interactive/Parsing/PolyglotSyntaxParser.cs b/src/Microsoft.DotNet.Interactive/Parsing/PolyglotSyntaxParser.cs index 5bde8153eb..b9b664c6d2 100644 --- a/src/Microsoft.DotNet.Interactive/Parsing/PolyglotSyntaxParser.cs +++ b/src/Microsoft.DotNet.Interactive/Parsing/PolyglotSyntaxParser.cs @@ -193,6 +193,9 @@ void AppendNode(SyntaxNode node) case DirectiveParameterValueNode valueNode when subcommandNode is null: directiveNode.Add(valueNode); break; + case DirectiveParameterValueNode valueNode when subcommandNode is not null: + subcommandNode.Add(valueNode); + break; case DirectiveParameterValueNode valueNode when subcommandNode is not null: subcommandNode.Add(valueNode); From 75c48fcb75e7c9ef659ba60066f1fc84c60c7d03 Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Tue, 8 Oct 2024 09:39:43 -0700 Subject: [PATCH 2/3] add test case --- .../KeyValueStoreKernelTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Microsoft.DotNet.Interactive.Tests/KeyValueStoreKernelTests.cs b/src/Microsoft.DotNet.Interactive.Tests/KeyValueStoreKernelTests.cs index 9372033b2c..67a3e2d7c0 100644 --- a/src/Microsoft.DotNet.Interactive.Tests/KeyValueStoreKernelTests.cs +++ b/src/Microsoft.DotNet.Interactive.Tests/KeyValueStoreKernelTests.cs @@ -445,6 +445,33 @@ public async Task Completions_show_value_options() .Contain("--name", "--from-url", "--from-file", "--mime-type"); } + [Fact] + public async Task Canceled_input_request_does_not_record_input_token_as_value() + { + using var kernel = CreateKernel(); + + kernel.RegisterCommandHandler((requestInput, context) => + { + context.Fail(requestInput); + return Task.CompletedTask; + }); + + kernel.SetDefaultTargetKernelNameForCommand(typeof(RequestInput), kernel.Name); + + var result = await kernel.SubmitCodeAsync( + """ + #!value --from-value @input:{"type": "file"} --name file + """); + + result.Events.Should().ContainSingle(); + + var keyValueStoreKernel = kernel.FindKernelByName("value"); + + var (_, valueInfosProduced) = await keyValueStoreKernel.TryRequestValueInfosAsync(); + + valueInfosProduced.ValueInfos.Should().BeEmpty(); + } + private static CompositeKernel CreateKernel() => new() { From eeaad2bc8d9c3e2a059687ab4e8820445de63bbb Mon Sep 17 00:00:00 2001 From: Jon Sequeira Date: Tue, 8 Oct 2024 14:17:13 -0700 Subject: [PATCH 3/3] fail invocation context when user input is canceled --- .../KeyValueStoreKernel.cs | 6 ++++++ .../Parsing/DirectiveExpressionNode.cs | 3 +++ .../Parsing/SubmissionParser.cs | 11 ++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.Interactive/KeyValueStoreKernel.cs b/src/Microsoft.DotNet.Interactive/KeyValueStoreKernel.cs index c5123c18e9..a8521d0bdf 100644 --- a/src/Microsoft.DotNet.Interactive/KeyValueStoreKernel.cs +++ b/src/Microsoft.DotNet.Interactive/KeyValueStoreKernel.cs @@ -95,6 +95,12 @@ Task TryGetKernelCommandAsync( ExpressionBindingResult expressionBindingResult, Kernel keyValueStoreKernel) { + if (expressionBindingResult.Diagnostics.FirstOrDefault(d => d.Severity == DiagnosticSeverity.Error) is { } diagnostic) + { + directiveNode.AddDiagnostic(diagnostic); + return Task.FromResult(null); + } + var parameterValues = directiveNode .GetParameterValues(directive, expressionBindingResult.BoundValues) .ToDictionary(t => t.Name, t => (t.Value, t.ParameterNode)); diff --git a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveExpressionNode.cs b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveExpressionNode.cs index 3d739bdde7..214dac33a4 100644 --- a/src/Microsoft.DotNet.Interactive/Parsing/DirectiveExpressionNode.cs +++ b/src/Microsoft.DotNet.Interactive/Parsing/DirectiveExpressionNode.cs @@ -16,6 +16,9 @@ internal DirectiveExpressionNode(SourceText sourceText, SyntaxTree syntaxTree) : public DirectiveExpressionParametersNode? ParametersNode { get; private set; } + public bool IsInputExpression => + TypeNode?.Type is "input" or "password"; + public void Add(DirectiveExpressionTypeNode node) { AddInternal(node); diff --git a/src/Microsoft.DotNet.Interactive/Parsing/SubmissionParser.cs b/src/Microsoft.DotNet.Interactive/Parsing/SubmissionParser.cs index 823fd4cc39..bcf1e934ab 100644 --- a/src/Microsoft.DotNet.Interactive/Parsing/SubmissionParser.cs +++ b/src/Microsoft.DotNet.Interactive/Parsing/SubmissionParser.cs @@ -784,7 +784,8 @@ await RequestSingleValueOrInputAsync( sourceCommand, directiveNode.TargetKernelName); - if (expressionNode.Parent is { Parent: DirectiveParameterNode { NameNode.Text: { } parameterName } }) + if (bindingResult?.IsSuccessful == true && + expressionNode.Parent is { Parent: DirectiveParameterNode { NameNode.Text: { } parameterName } }) { if (inputProduced is not null) { @@ -798,6 +799,14 @@ await RequestSingleValueOrInputAsync( valuesProduced.Add(parameterName, valueProduced); } } + else + { + if (directiveNode.DescendantNodesAndTokens().OfType().Any(node => node.IsInputExpression) && + KernelInvocationContext.Current is { Command: SubmitCode } context) + { + context.Fail(sourceCommand, message: "Input not provided."); + } + } return bindingResult; });