From e023a78fb5b1d2c255abc83798436b4e2168eb7c Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 26 Oct 2023 17:01:07 +0100 Subject: [PATCH 1/7] Fix issue 2279 --- src/System.CommandLine/Completions/CompletionContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.CommandLine/Completions/CompletionContext.cs b/src/System.CommandLine/Completions/CompletionContext.cs index 0ce1544cae..8e61b5ada5 100644 --- a/src/System.CommandLine/Completions/CompletionContext.cs +++ b/src/System.CommandLine/Completions/CompletionContext.cs @@ -87,8 +87,8 @@ protected static string GetWordToComplete( var textAfterCursor = rawInput.Substring(position.Value); - return textBeforeCursor.Split(' ').LastOrDefault() + - textAfterCursor.Split(' ').FirstOrDefault(); + return textBeforeCursor.Split(' ','=').LastOrDefault() + + textAfterCursor.Split(' ','=').FirstOrDefault(); } return ""; From c3c13333551a160a49944f2dc5d2d40ad612e9e7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 26 Oct 2023 20:38:38 +0100 Subject: [PATCH 2/7] #2279 - add test --- .../CompletionContextTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/System.CommandLine.Tests/CompletionContextTests.cs b/src/System.CommandLine.Tests/CompletionContextTests.cs index de5e33c5ab..dc193d2074 100644 --- a/src/System.CommandLine.Tests/CompletionContextTests.cs +++ b/src/System.CommandLine.Tests/CompletionContextTests.cs @@ -2,7 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Completions; +using System.Linq; +using System.Runtime.InteropServices; using FluentAssertions; +using FluentAssertions.Specialized; using Xunit; namespace System.CommandLine.Tests @@ -33,6 +36,32 @@ public void CommandLineText_preserves_command_line_prior_to_splitting_when_compl .Be(commandLine); } + [Fact] + public void CommandLineText_is_parsed_when_option_is_in_name_equals_sign_value_format() + { + CliRootCommand command = new CliRootCommand + { + new CliCommand("inner") + { + new CliOption("--optionOne"), + new CliOption("--optionTwo") + } + }; + + var commandLine = "outer inner --optionOne argument1 --optionTwo=argument2"; + + var parseResult = command.Parse(commandLine); + + parseResult.GetCompletionContext() + .Should() + .BeOfType() + .Which + .CommandLineText + .Should() + .Be(commandLine); + + } + [Fact] public void CommandLineText_is_preserved_when_adjusting_position() { From 7a87dc96e1045a6a2799ebe84678498ee4307afe Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 26 Oct 2023 20:46:09 +0100 Subject: [PATCH 3/7] 2279 - remove unused declarations --- src/System.CommandLine.Tests/CompletionContextTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/System.CommandLine.Tests/CompletionContextTests.cs b/src/System.CommandLine.Tests/CompletionContextTests.cs index dc193d2074..0dd5ad76f0 100644 --- a/src/System.CommandLine.Tests/CompletionContextTests.cs +++ b/src/System.CommandLine.Tests/CompletionContextTests.cs @@ -2,10 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Completions; -using System.Linq; -using System.Runtime.InteropServices; using FluentAssertions; -using FluentAssertions.Specialized; using Xunit; namespace System.CommandLine.Tests From 43d2c185bd47b69e5b96e1082f8b6453cdb7f137 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Oct 2023 20:15:00 +0000 Subject: [PATCH 4/7] #2279 - fix test --- .../CompletionContextTests.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/System.CommandLine.Tests/CompletionContextTests.cs b/src/System.CommandLine.Tests/CompletionContextTests.cs index 0dd5ad76f0..a2c6ab4f77 100644 --- a/src/System.CommandLine.Tests/CompletionContextTests.cs +++ b/src/System.CommandLine.Tests/CompletionContextTests.cs @@ -2,8 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Completions; +using ApprovalTests.Namers; using FluentAssertions; using Xunit; +using System.CommandLine; +using System.Threading; namespace System.CommandLine.Tests { @@ -36,6 +39,7 @@ public void CommandLineText_preserves_command_line_prior_to_splitting_when_compl [Fact] public void CommandLineText_is_parsed_when_option_is_in_name_equals_sign_value_format() { + CliRootCommand command = new CliRootCommand { new CliCommand("inner") @@ -45,17 +49,15 @@ public void CommandLineText_is_parsed_when_option_is_in_name_equals_sign_value_f } }; - var commandLine = "outer inner --optionOne argument1 --optionTwo=argument2"; + var commandLine = "inner --optionOne argument1 --optionTwo=argument2"; var parseResult = command.Parse(commandLine); + parseResult.GetCompletions(); - parseResult.GetCompletionContext() - .Should() - .BeOfType() - .Which - .CommandLineText - .Should() - .Be(commandLine); + Assert.True(parseResult.Tokens[1].Value == "--optionOne"); + Assert.True(parseResult.Tokens[2].Value == "argument1"); + Assert.True(parseResult.Tokens[3].Value == "--optionTwo"); + Assert.True(parseResult.Tokens[4].Value == "argument2"); } From 1847bcc859e3308c4f10ffcb328bad2f8f89d040 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 31 Oct 2023 22:44:40 +0000 Subject: [PATCH 5/7] 2279 - fix completioncontext issue 2279 --- src/System.CommandLine/Completions/CompletionContext.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/System.CommandLine/Completions/CompletionContext.cs b/src/System.CommandLine/Completions/CompletionContext.cs index 8e61b5ada5..e85a6371ba 100644 --- a/src/System.CommandLine/Completions/CompletionContext.cs +++ b/src/System.CommandLine/Completions/CompletionContext.cs @@ -87,8 +87,11 @@ protected static string GetWordToComplete( var textAfterCursor = rawInput.Substring(position.Value); - return textBeforeCursor.Split(' ','=').LastOrDefault() + - textAfterCursor.Split(' ','=').FirstOrDefault(); + var lastOrFirstWord = textBeforeCursor.Split(' ').LastOrDefault() + + textAfterCursor.Split(' ').FirstOrDefault(); + + return (lastOrFirstWord.StartsWith("--")) ? lastOrFirstWord.Split('=').Last() : lastOrFirstWord; + } return ""; From 4d8d7e84a6651649a64fe625f49f55b48c205bb4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 31 Oct 2023 23:25:31 +0000 Subject: [PATCH 6/7] add some tests - 2279 --- .../CompletionContextTests.cs | 100 +++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/src/System.CommandLine.Tests/CompletionContextTests.cs b/src/System.CommandLine.Tests/CompletionContextTests.cs index a2c6ab4f77..cae58bbe27 100644 --- a/src/System.CommandLine.Tests/CompletionContextTests.cs +++ b/src/System.CommandLine.Tests/CompletionContextTests.cs @@ -37,7 +37,7 @@ public void CommandLineText_preserves_command_line_prior_to_splitting_when_compl } [Fact] - public void CommandLineText_is_parsed_when_option_is_in_name_equals_sign_value_format() + public void CommandLineText_is_parsed_when_option_other_than_last_is_in_name_equals_sign_value_format() { CliRootCommand command = new CliRootCommand @@ -49,6 +49,104 @@ public void CommandLineText_is_parsed_when_option_is_in_name_equals_sign_value_f } }; + var commandLine = "inner --optionOne=argument1 --optionTwo argument2"; + + var parseResult = command.Parse(commandLine); + parseResult.GetCompletions(); + + Assert.True(parseResult.Tokens[1].Value == "--optionOne"); + Assert.True(parseResult.Tokens[2].Value == "argument1"); + Assert.True(parseResult.Tokens[3].Value == "--optionTwo"); + Assert.True(parseResult.Tokens[4].Value == "argument2"); + + } + + [Fact] + public void CommandLineText_is_parsed_when_equal_sign_used_in_multiple_option_params() + { + + CliRootCommand command = new CliRootCommand + { + new CliCommand("inner") + { + new CliOption("--optionOne"), + new CliOption("--optionTwo") + } + }; + + var commandLine = "inner --optionOne=argument1 --optionTwo=argument2"; + + var parseResult = command.Parse(commandLine); + parseResult.GetCompletions(); + + Assert.True(parseResult.Tokens[1].Value == "--optionOne"); + Assert.True(parseResult.Tokens[2].Value == "argument1"); + Assert.True(parseResult.Tokens[3].Value == "--optionTwo"); + Assert.True(parseResult.Tokens[4].Value == "argument2"); + + } + + [Fact] + public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value() + { + + CliRootCommand command = new CliRootCommand + { + new CliCommand("inner") + { + new CliOption("--optionOne"), + new CliOption("--optionTwo") + } + }; + + var commandLine = "inner --optionOne -=Yay=-"; + + var parseResult = command.Parse(commandLine); + parseResult.GetCompletions(); + + Assert.True(parseResult.Tokens[0].Value == "inner"); + Assert.True(parseResult.Tokens[1].Value == "--optionOne"); + Assert.True(parseResult.Tokens[2].Value == "-=Yay=-"); + + } + + [Fact] + public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value_and_as_option_value_spacer() + { + + CliRootCommand command = new CliRootCommand + { + new CliCommand("inner") + { + new CliOption("--optionOne"), + new CliOption("--optionTwo") + } + }; + + var commandLine = "inner --optionOne=-=Yay=-"; + + var parseResult = command.Parse(commandLine); + parseResult.GetCompletions(); + + Assert.True(parseResult.Tokens[0].Value == "inner"); + Assert.True(parseResult.Tokens[1].Value == "--optionOne"); + Assert.True(parseResult.Tokens[2].Value == "-=Yay=-"); + + } + + [Fact] + public void CommandLineText_is_parsed_when_last_option_is_in_name_equals_sign_value_format() + { + + CliRootCommand command = new CliRootCommand + { + new CliCommand("inner") + { + new CliOption("--optionOne"), + new CliOption("--optionTwo") + } + }; + var commandLine = "inner --optionOne argument1 --optionTwo=argument2"; var parseResult = command.Parse(commandLine); From abe31f9b3c8a35a6625de71229763592c5373960 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 1 Nov 2023 11:14:30 +0000 Subject: [PATCH 7/7] 2279 - fix bug where = sign could not be used in a CLi option value --- .../CompletionContextTests.cs | 29 +++++++++---------- .../Completions/CompletionContext.cs | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/System.CommandLine.Tests/CompletionContextTests.cs b/src/System.CommandLine.Tests/CompletionContextTests.cs index cae58bbe27..71f28db1e7 100644 --- a/src/System.CommandLine.Tests/CompletionContextTests.cs +++ b/src/System.CommandLine.Tests/CompletionContextTests.cs @@ -62,7 +62,7 @@ public void CommandLineText_is_parsed_when_option_other_than_last_is_in_name_equ } [Fact] - public void CommandLineText_is_parsed_when_equal_sign_used_in_multiple_option_params() + public void CommandLineText_is_parsed_when_last_option_is_in_name_equals_sign_value_format() { CliRootCommand command = new CliRootCommand @@ -74,7 +74,7 @@ public void CommandLineText_is_parsed_when_equal_sign_used_in_multiple_option_pa } }; - var commandLine = "inner --optionOne=argument1 --optionTwo=argument2"; + var commandLine = "inner --optionOne argument1 --optionTwo=argument2"; var parseResult = command.Parse(commandLine); parseResult.GetCompletions(); @@ -87,7 +87,7 @@ public void CommandLineText_is_parsed_when_equal_sign_used_in_multiple_option_pa } [Fact] - public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value() + public void CommandLineText_is_parsed_when_equal_sign_used_in_multiple_option_params() { CliRootCommand command = new CliRootCommand @@ -99,19 +99,20 @@ public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value() } }; - var commandLine = "inner --optionOne -=Yay=-"; + var commandLine = "inner --optionOne=argument1 --optionTwo=argument2"; var parseResult = command.Parse(commandLine); parseResult.GetCompletions(); - Assert.True(parseResult.Tokens[0].Value == "inner"); Assert.True(parseResult.Tokens[1].Value == "--optionOne"); - Assert.True(parseResult.Tokens[2].Value == "-=Yay=-"); + Assert.True(parseResult.Tokens[2].Value == "argument1"); + Assert.True(parseResult.Tokens[3].Value == "--optionTwo"); + Assert.True(parseResult.Tokens[4].Value == "argument2"); } [Fact] - public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value_and_as_option_value_spacer() + public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value() { CliRootCommand command = new CliRootCommand @@ -123,7 +124,7 @@ public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value_and_a } }; - var commandLine = "inner --optionOne=-=Yay=-"; + var commandLine = "inner --optionOne -=Yay=-"; var parseResult = command.Parse(commandLine); parseResult.GetCompletions(); @@ -135,27 +136,25 @@ public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value_and_a } [Fact] - public void CommandLineText_is_parsed_when_last_option_is_in_name_equals_sign_value_format() + public void CommandLineText_is_parsed_when_equal_sign_used_in_option_value_and_as_option_value_spacer() { CliRootCommand command = new CliRootCommand { new CliCommand("inner") { - new CliOption("--optionOne"), - new CliOption("--optionTwo") + new CliOption("--optionOne") } }; - var commandLine = "inner --optionOne argument1 --optionTwo=argument2"; + var commandLine = "inner --optionOne=-=Yay=-"; var parseResult = command.Parse(commandLine); parseResult.GetCompletions(); + Assert.True(parseResult.Tokens[0].Value == "inner"); Assert.True(parseResult.Tokens[1].Value == "--optionOne"); - Assert.True(parseResult.Tokens[2].Value == "argument1"); - Assert.True(parseResult.Tokens[3].Value == "--optionTwo"); - Assert.True(parseResult.Tokens[4].Value == "argument2"); + Assert.True(parseResult.Tokens[2].Value == "-=Yay=-"); } diff --git a/src/System.CommandLine/Completions/CompletionContext.cs b/src/System.CommandLine/Completions/CompletionContext.cs index e85a6371ba..53b566a284 100644 --- a/src/System.CommandLine/Completions/CompletionContext.cs +++ b/src/System.CommandLine/Completions/CompletionContext.cs @@ -90,7 +90,7 @@ protected static string GetWordToComplete( var lastOrFirstWord = textBeforeCursor.Split(' ').LastOrDefault() + textAfterCursor.Split(' ').FirstOrDefault(); - return (lastOrFirstWord.StartsWith("--")) ? lastOrFirstWord.Split('=').Last() : lastOrFirstWord; + return (lastOrFirstWord.StartsWith("--")) ? lastOrFirstWord.Split(new[] { '=' }, 2).Last() : lastOrFirstWord; }