Skip to content

Commit

Permalink
Parent search bug fix (#2030)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamsitnik authored Jan 23, 2023
1 parent daec22f commit 6524142
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
11 changes: 8 additions & 3 deletions src/System.CommandLine.Tests/CompletionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,25 @@ public void Command_GetCompletions_returns_available_option_aliases()
[Fact] // https://github.com/dotnet/command-line-api/issues/1563
public void Command_GetCompletions_returns_available_option_aliases_for_global_options()
{
var subcommand = new Command("command")
var subcommand2 = new Command("command2")
{
new Option<string>("--one", "option one"),
new Option<string>("--two", "option two")
};

var subcommand1 = new Command("command1")
{
subcommand2
};

var rootCommand = new RootCommand
{
subcommand
subcommand1
};

rootCommand.AddGlobalOption(new Option<string>("--three", "option three"));

var completions = subcommand.GetCompletions(CompletionContext.Empty);
var completions = subcommand2.GetCompletions(CompletionContext.Empty);

completions
.Select(item => item.Label)
Expand Down
38 changes: 38 additions & 0 deletions src/System.CommandLine.Tests/ParseResultTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// 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.CommandLine.Parsing;
using FluentAssertions;
using Xunit;
Expand Down Expand Up @@ -83,5 +84,42 @@ public void Command_will_not_accept_a_command_if_a_sibling_command_has_already_b
result2.CommandResult.Command.Name.Should().Be("inner-two");
result2.Errors.Count.Should().Be(1);
}

[Fact] // https://github.com/dotnet/command-line-api/pull/2030#issuecomment-1400275332
public void ParseResult_GetCompletions_returns_global_options_of_given_command_only()
{
var leafCommand = new Command("leafCommand")
{
new Option<string>("--one", "option one"),
new Option<string>("--two", "option two")
};

var midCommand1 = new Command("midCommand1")
{
leafCommand
};
midCommand1.AddGlobalOption(new Option<string>("--three1", "option three 1"));

var midCommand2 = new Command("midCommand2")
{
leafCommand
};
midCommand2.AddGlobalOption(new Option<string>("--three2", "option three 2"));

var rootCommand = new Command("root")
{
midCommand1,
midCommand2
};

var result = new Parser(rootCommand).Parse("root midCommand2 leafCommand --");

var completions = result.GetCompletions();

completions
.Select(item => item.Label)
.Should()
.BeEquivalentTo("--one", "--two", "--three2");
}
}
}
24 changes: 16 additions & 8 deletions src/System.CommandLine/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,20 +192,28 @@ public override IEnumerable<CompletionItem> GetCompletions(CompletionContext con
ParentNode? parent = FirstParent;
while (parent is not null)
{
if (parent.Symbol is Command parentCommand && parentCommand.HasOptions)
Command parentCommand = (Command)parent.Symbol;

if (context.IsEmpty || context.ParseResult.FindResultFor(parentCommand) is not null)
{
for (var i = 0; i < parentCommand.Options.Count; i++)
if (parentCommand.HasOptions)
{
var option = parentCommand.Options[i];

if (option.IsGlobal)
for (var i = 0; i < parentCommand.Options.Count; i++)
{
AddCompletionsFor(option);
var option = parentCommand.Options[i];

if (option.IsGlobal)
{
AddCompletionsFor(option);
}
}
}
parent = parent.Symbol.FirstParent;
}
else
{
parent = parent.Next;
}

parent = parent.Next;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/System.CommandLine/Completions/CompletionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ internal CompletionContext(ParseResult parseResult, string wordToComplete)
/// <remarks>Can be used for testing purposes.</remarks>
public static CompletionContext Empty => _empty ??= new TokenCompletionContext(ParseResult.Empty());

internal bool IsEmpty => ReferenceEquals(this, _empty);

/// <summary>
/// Gets the text to be matched for completion, which can be used to filter a list of completions.
/// </summary>
Expand Down

0 comments on commit 6524142

Please sign in to comment.