Merge pull request #9294 from peterhuene/fix-completion
Improve command completion.
This commit is contained in:
commit
b5b47dd40d
8 changed files with 271 additions and 116 deletions
|
@ -3,14 +3,23 @@
|
|||
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
using Microsoft.DotNet.Tools.Help;
|
||||
using Microsoft.DotNet.Tools.New;
|
||||
using static System.Environment;
|
||||
using static Microsoft.DotNet.Cli.CommandLine.LocalizableStrings;
|
||||
using LocalizableStrings = Microsoft.DotNet.Tools.Run.LocalizableStrings;
|
||||
using NewCommandParser = Microsoft.TemplateEngine.Cli.CommandParsing.CommandParserSupport;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
{
|
||||
public static class Parser
|
||||
{
|
||||
// This is used for descriptions of commands and options that are only defined for `dotnet complete` (i.e. command line completion).
|
||||
// For example, a NuGet assembly handles parsing the `nuget` command and options.
|
||||
// To get completion for such a command, we have to define a parser that is used for the completion.
|
||||
// Command and option help text cannot be empty, otherwise the parser will hide them from the completion list.
|
||||
// The value of `-` has no special meaning; it simply prevents these commands and options from being hidden.
|
||||
internal const string CompletionOnlyDescription = "-";
|
||||
|
||||
static Parser()
|
||||
{
|
||||
ConfigureCommandLineLocalizedStrings();
|
||||
|
@ -35,7 +44,7 @@ namespace Microsoft.DotNet.Cli
|
|||
options: Create.Command("dotnet",
|
||||
".NET Command Line Tools",
|
||||
Accept.NoArguments(),
|
||||
NewCommandParser.New(),
|
||||
NewCommandParser.CreateNewCommandWithoutTemplateInfo(NewCommandShim.CommandName),
|
||||
RestoreCommandParser.Restore(),
|
||||
BuildCommandParser.Build(),
|
||||
PublishCommandParser.Publish(),
|
||||
|
@ -51,15 +60,17 @@ namespace Microsoft.DotNet.Cli
|
|||
NuGetCommandParser.NuGet(),
|
||||
StoreCommandParser.Store(),
|
||||
HelpCommandParser.Help(),
|
||||
Create.Command("msbuild", ""),
|
||||
Create.Command("vstest", ""),
|
||||
Create.Command("msbuild", CompletionOnlyDescription),
|
||||
Create.Command("vstest", CompletionOnlyDescription),
|
||||
CompleteCommandParser.Complete(),
|
||||
InternalReportinstallsuccessCommandParser.InternalReportinstallsuccess(),
|
||||
ToolCommandParser.Tool(),
|
||||
BuildServerCommandParser.CreateCommand(),
|
||||
CommonOptions.HelpOption(),
|
||||
Create.Option("--info", ""),
|
||||
Create.Option("-d", ""),
|
||||
Create.Option("--debug", "")));
|
||||
Create.Option("--info", CompletionOnlyDescription),
|
||||
Create.Option("-d|--diagnostics", CompletionOnlyDescription),
|
||||
Create.Option("--version", CompletionOnlyDescription),
|
||||
Create.Option("--list-sdks", CompletionOnlyDescription),
|
||||
Create.Option("--list-runtimes", CompletionOnlyDescription)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,16 @@ namespace Microsoft.DotNet.Cli
|
|||
{
|
||||
public static int Run(string[] args)
|
||||
{
|
||||
return RunWithReporter(args, Reporter.Output);
|
||||
}
|
||||
|
||||
public static int RunWithReporter(string [] args, IReporter reporter)
|
||||
{
|
||||
if (reporter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reporter));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
@ -28,7 +38,7 @@ namespace Microsoft.DotNet.Cli
|
|||
|
||||
foreach (var suggestion in suggestions)
|
||||
{
|
||||
Console.WriteLine(suggestion);
|
||||
reporter.WriteLine(suggestion);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
|
|
|
@ -10,7 +10,8 @@ namespace Microsoft.DotNet.Cli
|
|||
{
|
||||
public static Command InternalReportinstallsuccess() =>
|
||||
Create.Command(
|
||||
"internal-reportinstallsuccess", "internal only",
|
||||
"internal-reportinstallsuccess",
|
||||
"",
|
||||
Accept.ExactlyOneArgument());
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
{
|
||||
internal static class NewCommandParser
|
||||
{
|
||||
public static Command New() =>
|
||||
Create.Command("new",
|
||||
"Initialize .NET projects.",
|
||||
Accept
|
||||
.ExactlyOneArgument()
|
||||
.WithSuggestionsFrom(
|
||||
"console",
|
||||
"classlib",
|
||||
"mstest",
|
||||
"xunit",
|
||||
"web",
|
||||
"mvc",
|
||||
"webapi",
|
||||
"sln"),
|
||||
Create.Option("-l|--list",
|
||||
"List templates containing the specified name."),
|
||||
Create.Option("-lang|--language",
|
||||
"Specifies the language of the template to create",
|
||||
Accept.WithSuggestionsFrom("C#", "F#")
|
||||
.With(defaultValue: () => "C#")),
|
||||
Create.Option("-n|--name",
|
||||
"The name for the output being created. If no name is specified, the name of the current directory is used."),
|
||||
Create.Option("-o|--output",
|
||||
"Location to place the generated output."),
|
||||
Create.Option("-h|--help",
|
||||
"Displays help for this command."),
|
||||
Create.Option("-all|--show-all",
|
||||
"Shows all templates"));
|
||||
}
|
||||
}
|
|
@ -24,8 +24,8 @@ namespace Microsoft.DotNet.Tools.New
|
|||
{
|
||||
internal class NewCommandShim
|
||||
{
|
||||
public const string CommandName = "new";
|
||||
private const string HostIdentifier = "dotnetcli";
|
||||
private const string CommandName = "new";
|
||||
|
||||
public static int Run(string[] args)
|
||||
{
|
||||
|
|
|
@ -5,74 +5,52 @@ using Microsoft.DotNet.Cli.CommandLine;
|
|||
|
||||
namespace Microsoft.DotNet.Cli
|
||||
{
|
||||
// This parser is used for completion and telemetry.
|
||||
// See https://github.com/NuGet/NuGet.Client for the actual implementation.
|
||||
internal static class NuGetCommandParser
|
||||
{
|
||||
public static Command NuGet() =>
|
||||
Create.Command("nuget",
|
||||
"NuGet Command Line 4.0.0.0",
|
||||
CommonOptions.HelpOption(),
|
||||
Create.Option("--version",
|
||||
"Show version information"),
|
||||
Create.Option("-v|--verbosity",
|
||||
"The verbosity of logging to use. Allowed values: Debug, Verbose, Information, Minimal, Warning, Error.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "verbosity")),
|
||||
Create.Command("delete",
|
||||
"Deletes a package from the server.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "root",
|
||||
description: "The Package Id and version."),
|
||||
CommonOptions.HelpOption(),
|
||||
Create.Option("--force-english-output",
|
||||
"Forces the application to run using an invariant, English-based culture."),
|
||||
Create.Option("-s|--source",
|
||||
"Specifies the server URL",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "source")),
|
||||
Create.Option("--non-interactive",
|
||||
"Do not prompt for user input or confirmations."),
|
||||
Create.Option("-k|--api-key",
|
||||
"The API key for the server.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "apiKey"))),
|
||||
Create.Command("locals",
|
||||
"Clears or lists local NuGet resources such as http requests cache, packages cache or machine-wide global packages folder.",
|
||||
Accept.AnyOneOf(@"all",
|
||||
@"http-cache",
|
||||
@"global-packages",
|
||||
@"temp")
|
||||
.With(description: "Cache Location(s) Specifies the cache location(s) to list or clear."),
|
||||
CommonOptions.HelpOption(),
|
||||
Create.Option("--force-english-output",
|
||||
"Forces the application to run using an invariant, English-based culture."),
|
||||
Create.Option("-c|--clear", "Clear the selected local resources or cache location(s)."),
|
||||
Create.Option("-l|--list", "List the selected local resources or cache location(s).")),
|
||||
Create.Command("push",
|
||||
"Pushes a package to the server and publishes it.",
|
||||
CommonOptions.HelpOption(),
|
||||
Create.Option("--force-english-output",
|
||||
"Forces the application to run using an invariant, English-based culture."),
|
||||
Create.Option("-s|--source",
|
||||
"Specifies the server URL",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "source")),
|
||||
Create.Option("-ss|--symbol-source",
|
||||
"Specifies the symbol server URL. If not specified, nuget.smbsrc.net is used when pushing to nuget.org.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "source")),
|
||||
Create.Option("-t|--timeout",
|
||||
"Specifies the timeout for pushing to a server in seconds. Defaults to 300 seconds (5 minutes).",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "timeout")),
|
||||
Create.Option("-k|--api-key", "The API key for the server.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "apiKey")),
|
||||
Create.Option("-sk|--symbol-api-key", "The API key for the symbol server.",
|
||||
Accept.ExactlyOneArgument()
|
||||
.With(name: "apiKey")),
|
||||
Create.Option("-d|--disable-buffering",
|
||||
"Disable buffering when pushing to an HTTP(S) server to decrease memory usage."),
|
||||
Create.Option("-n|--no-symbols",
|
||||
"If a symbols package exists, it will not be pushed to a symbols server.")));
|
||||
Create.Command(
|
||||
"nuget",
|
||||
Parser.CompletionOnlyDescription,
|
||||
Create.Option("-h|--help", Parser.CompletionOnlyDescription),
|
||||
Create.Option("--version", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-v|--verbosity", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Command(
|
||||
"delete",
|
||||
Parser.CompletionOnlyDescription,
|
||||
Accept.OneOrMoreArguments(),
|
||||
Create.Option("-h|--help", Parser.CompletionOnlyDescription),
|
||||
Create.Option("--force-english-output", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-s|--source", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("--non-interactive", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-k|--api-key", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("--no-service-endpoint", Parser.CompletionOnlyDescription)),
|
||||
Create.Command(
|
||||
"locals",
|
||||
Parser.CompletionOnlyDescription,
|
||||
Accept.AnyOneOf(
|
||||
"all",
|
||||
"http-cache",
|
||||
"global-packages",
|
||||
"temp"),
|
||||
Create.Option("-h|--help", Parser.CompletionOnlyDescription),
|
||||
Create.Option("--force-english-output", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-c|--clear", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-l|--list", Parser.CompletionOnlyDescription)),
|
||||
Create.Command(
|
||||
"push",
|
||||
Parser.CompletionOnlyDescription,
|
||||
Accept.OneOrMoreArguments(),
|
||||
Create.Option("-h|--help", Parser.CompletionOnlyDescription),
|
||||
Create.Option("--force-english-output", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-s|--source", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("-ss|--symbol-source", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("-t|--timeout", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("-k|--api-key", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("-sk|--symbol-api-key", Parser.CompletionOnlyDescription, Accept.ExactlyOneArgument()),
|
||||
Create.Option("-d|--disable-buffering", Parser.CompletionOnlyDescription),
|
||||
Create.Option("-n|--no-symbols", Parser.CompletionOnlyDescription),
|
||||
Create.Option("--no-service-endpoint", Parser.CompletionOnlyDescription)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
194
test/dotnet.Tests/CommandTests/CompleteCommandTests.cs
Normal file
194
test/dotnet.Tests/CommandTests/CompleteCommandTests.cs
Normal file
|
@ -0,0 +1,194 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.DotNet.Tools.Test.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.DotNet.Tests.Commands
|
||||
{
|
||||
public class CompleteCommandTests : TestBase
|
||||
{
|
||||
[Fact]
|
||||
public void GivenOnlyDotnetItSuggestsTopLevelCommandsAndOptions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--diagnostics",
|
||||
"--help",
|
||||
"--info",
|
||||
"--list-runtimes",
|
||||
"--list-sdks",
|
||||
"--version",
|
||||
"-d",
|
||||
"-h",
|
||||
"add",
|
||||
"build",
|
||||
"build-server",
|
||||
"clean",
|
||||
"help",
|
||||
"list",
|
||||
"migrate",
|
||||
"msbuild",
|
||||
"new",
|
||||
"nuget",
|
||||
"pack",
|
||||
"publish",
|
||||
"remove",
|
||||
"restore",
|
||||
"run",
|
||||
"sln",
|
||||
"store",
|
||||
"test",
|
||||
"tool",
|
||||
"vstest"
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenASlashItSuggestsTopLevelOptions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--diagnostics",
|
||||
"--help",
|
||||
"--info",
|
||||
"--list-runtimes",
|
||||
"--list-sdks",
|
||||
"--version",
|
||||
"-d",
|
||||
"-h",
|
||||
"build-server" // This should be removed when completion is based on "starts with" rather than "contains".
|
||||
// See https://github.com/dotnet/cli/issues/8958.
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet -" }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenNewCommandItDisplaysCompletions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--force",
|
||||
"--help",
|
||||
"--install",
|
||||
"--language",
|
||||
"--list",
|
||||
"--name",
|
||||
"--nuget-source",
|
||||
"--output",
|
||||
"--type",
|
||||
"--uninstall",
|
||||
"-h",
|
||||
"-i",
|
||||
"-l",
|
||||
"-lang",
|
||||
"-n",
|
||||
"-o",
|
||||
"-u"
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet new " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenNuGetCommandItDisplaysCompletions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--help",
|
||||
"--verbosity",
|
||||
"--version",
|
||||
"-h",
|
||||
"-v",
|
||||
"delete",
|
||||
"locals",
|
||||
"push",
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet nuget " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenNuGetDeleteCommandItDisplaysCompletions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--api-key",
|
||||
"--force-english-output",
|
||||
"--help",
|
||||
"--no-service-endpoint",
|
||||
"--non-interactive",
|
||||
"--source",
|
||||
"-h",
|
||||
"-k",
|
||||
"-s"
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet nuget delete " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenNuGetLocalsCommandItDisplaysCompletions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--clear",
|
||||
"--force-english-output",
|
||||
"--help",
|
||||
"--list",
|
||||
"-c",
|
||||
"-h",
|
||||
"-l",
|
||||
"all",
|
||||
"global-packages",
|
||||
"http-cache",
|
||||
"temp"
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet nuget locals " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GivenNuGetPushCommandItDisplaysCompletions()
|
||||
{
|
||||
var expected = new string[] {
|
||||
"--api-key",
|
||||
"--disable-buffering",
|
||||
"--force-english-output",
|
||||
"--help",
|
||||
"--no-service-endpoint",
|
||||
"--no-symbols",
|
||||
"--source",
|
||||
"--symbol-api-key",
|
||||
"--symbol-source",
|
||||
"--timeout",
|
||||
"-d",
|
||||
"-h",
|
||||
"-k",
|
||||
"-n",
|
||||
"-s",
|
||||
"-sk",
|
||||
"-ss",
|
||||
"-t"
|
||||
};
|
||||
|
||||
var reporter = new BufferedReporter();
|
||||
CompleteCommand.RunWithReporter(new[] { "dotnet nuget push " }, reporter).Should().Be(0);
|
||||
reporter.Lines.Should().Equal(expected.OrderBy(c => c));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -163,7 +163,7 @@ namespace Microsoft.DotNet.Tests
|
|||
{
|
||||
const string argumentToSend = "push";
|
||||
|
||||
string[] args = { "nuget", argumentToSend };
|
||||
string[] args = { "nuget", argumentToSend, "path" };
|
||||
|
||||
Cli.Program.ProcessArgs(args);
|
||||
_fakeTelemetry
|
||||
|
|
Loading…
Add table
Reference in a new issue