-
Notifications
You must be signed in to change notification settings - Fork 382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API review issues #1891
Comments
I've noted some additional questions today: CompletionsCompletionItempublic class CompletionItem
.ctor(String label, String kind = Value, String sortText = null, String insertText = null, String documentation = null, String detail = null)
public String Detail { get; }
public String Documentation { get; set; }
public String InsertText { get; }
public String Kind { get; } // string, not enum, 2 values, used only for equality checks
public String Label { get; } // value, displayed to the users
public String SortText { get; } // when present, used for sorting the completions instead Label.
protected Boolean Equals(CompletionItem other)
public Boolean Equals(Object obj)
public Int32 GetHashCode()
public String ToString()
CompletionContextpublic abstract class CompletionContext
public CommandLine.ParseResult ParseResult { get; }
public String WordToComplete { get; }
TokenCompletionContextpublic class TokenCompletionContext : CompletionContext
TextCompletionContextpublic class TextCompletionContext : CompletionContext
public String CommandLineText { get; }
public Int32 CursorPosition { get; }
public TextCompletionContext AtCursorPosition(Int32 position)
ICompletionSourcepublic interface ICompletionSource
public Collections.Generic.IEnumerable<CompletionItem> GetCompletions(CompletionContext context)
Edit: I can see there are SymbolsSymbolpublic abstract class Symbol, CommandLine.Completions.ICompletionSource
public String Description { get; set; }
public Boolean IsHidden { get; set; }
public String Name { get; set; }
public Collections.Generic.IEnumerable<Symbol> Parents { get; }
public Collections.Generic.IEnumerable<CommandLine.Completions.CompletionItem> GetCompletions()
public Collections.Generic.IEnumerable<CommandLine.Completions.CompletionItem> GetCompletions(CommandLine.Completions.CompletionContext context)
public String ToString()
Argumentpublic abstract class Argument : Symbol, CommandLine.Binding.IValueDescriptor, CommandLine.Completions.ICompletionSource
public ArgumentArity Arity { get; set; }
public Collections.Generic.ICollection<CommandLine.Completions.ICompletionSource> Completions { get; }
public Boolean HasDefaultValue { get; }
public String HelpName { get; set; }
public Type ValueType { get; }
public Void AddValidator(Action<CommandLine.Parsing.ArgumentResult> validate)
public Collections.Generic.IEnumerable<CommandLine.Completions.CompletionItem> GetCompletions(CommandLine.Completions.CompletionContext context)
public Object GetDefaultValue()
public Void SetDefaultValue(Object value)
public Void SetDefaultValueFactory(Func<Object> defaultValueFactory)
public Void SetDefaultValueFactory(Func<CommandLine.Parsing.ArgumentResult,Object> defaultValueFactory)
public String ToString()
new Argument<string>
{
Completions = { _ => new[] { "vegetable", "mineral", "animal" } }
}
public override IEnumerable<CompletionItem> GetCompletions(CompletionContext context)
{
return Completions
.SelectMany(source => source.GetCompletions(context))
.Distinct()
.OrderBy(c => c.SortText, StringComparer.OrdinalIgnoreCase);
} |
For a hidden Option<bool>: I had a command-line application with an
|
Related #1765.
Related #1220 (comment).
IIUC, a completion menu (perhaps a popup in PowerShell) could display Label and then insert InsertText. But the suggest directive currently uses Label only, so dotnet-suggest will complete incorrectly if the completion delegate sets different strings in them. Help likewise uses Label only; I think that too should be InsertText. Even though the help is displayed to the user and Label therefore seems correct, it is intended for the user to copy to a command so InsertText is better.
|
I feel this would suggest it is already a complete word, rather than part of a word. |
I need it in #1884. |
AFAIK, GetCompletions is not normally called more than once for the same Symbol in the same process. It might be called again in an interactive application that reads more commands, but then it would likely have a new CompletionContext so you wouldn't be able to cache anyway. |
I use Symbol.GetCompletions() for testing a custom completion callback; please do not remove this feature. The alternative Symbol.GetCompletions(CompletionContext) is not suitable because AFAICT there is no way for external code to create a ComplationContext instance; it and the two derived classes all have internal constructors. |
No, the completion items can depend on the parse results of other symbols. Like an Argument<FileInfo> specifies a file and an Option<string> specifies an identifier defined in that file, and the completion delegate reads the file to find out what identifiers are defined there and what completion items should be generated. Also, I believe System.CommandLine currently requires the app to set up the arguments and options of all subcommands in advance (#1956), and if you require it to generate all the completion items in advance too, that will cost time during startup. I think a property |
@KalleOlaviNiemitalo big thanks for all the answers!
PTAL at #1954 and let me know what do you think. |
Why CompletionItem.Label would ever differ from InsertText:
|
Option<bool> runApiCompatOption = new("--run-api-compat", "....");
runApiCompatOption.SetDefaultValue(123); // providing int for a bool
In what scenario the customer needs both Name and HelpName for Argument?
internal HashSet<string>? AllowedValues { get; private set; } and it's used by two extension methods: Argumentpublic class Argument<T> : Argument, IValueDescriptor<T>, System.CommandLine.Binding.IValueDescriptor
.ctor()
.ctor(System.String name, System.String description = null)
.ctor(System.String name, Func<T> defaultValueFactory, System.String description = null)
.ctor(Func<T> defaultValueFactory)
.ctor(System.String name, Func<System.CommandLine.Parsing.ArgumentResult,T> parse, System.Boolean isDefault = False, System.String description = null)
.ctor(Func<System.CommandLine.Parsing.ArgumentResult,T> parse, System.Boolean isDefault = False)
public System.Type ValueType { get; }
/// <param name="parse">A custom argument parser.</param>
/// <param name="isDefault"><see langword="true"/> to use the <paramref name="parse"/> result as default value.</param> I would expect that any custom parser can just return default value if they want to? ArgumentAritypublic struct ArgumentArity : System.ValueType, System.IEquatable<ArgumentArity>
public static ArgumentArity ExactlyOne { get; }
public static ArgumentArity OneOrMore { get; }
public static ArgumentArity Zero { get; }
public static ArgumentArity ZeroOrMore { get; }
public static ArgumentArity ZeroOrOne { get; }
.ctor(System.Int32 minimumNumberOfValues, System.Int32 maximumNumberOfValues)
public System.Int32 MaximumNumberOfValues { get; }
public System.Int32 MinimumNumberOfValues { get; }
public System.Boolean Equals(ArgumentArity other)
public System.Boolean Equals(System.Object obj)
public System.Int32 GetHashCode()
IdentifierSymbolpublic abstract class IdentifierSymbol : Symbol
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get; }
public System.String Name { get; set; }
public System.Void AddAlias(System.String alias)
public System.Boolean HasAlias(System.String alias)
private protected readonly HashSet<string> _aliases = new(StringComparer.Ordinal);
Optionpublic abstract class Option : IdentifierSymbol, System.CommandLine.Binding.IValueDescriptor
public System.Boolean AllowMultipleArgumentsPerToken { get; set; }
public System.String ArgumentHelpName { get; set; }
public ArgumentArity Arity { get; set; }
public System.Boolean IsRequired { get; set; }
public System.Type ValueType { get; }
public System.Void AddValidator(System.Action<System.CommandLine.Parsing.OptionResult> validate)
public System.Collections.Generic.IEnumerable<System.CommandLine.Completions.CompletionItem> GetCompletions(System.CommandLine.Completions.CompletionContext context)
public System.Boolean HasAliasIgnoringPrefix(System.String alias)
public System.Void SetDefaultValue(System.Object value)
public System.Void SetDefaultValueFactory(System.Func<System.Object> defaultValueFactory)
Optionpublic class Option<T> : Option, IValueDescriptor<T>, System.CommandLine.Binding.IValueDescriptor
.ctor(System.String name, System.String description = null)
.ctor(System.String[] aliases, System.String description = null)
.ctor(System.String name, Func<System.CommandLine.Parsing.ArgumentResult,T> parseArgument, System.Boolean isDefault = False, System.String description = null)
.ctor(System.String[] aliases, Func<System.CommandLine.Parsing.ArgumentResult,T> parseArgument, System.Boolean isDefault = False, System.String description = null)
.ctor(System.String name, Func<T> defaultValueFactory, System.String description = null)
.ctor(System.String[] aliases, Func<T> defaultValueFactory, System.String description = null)
public ArgumentArity Arity { get; set; }
public class Option
{
/// <summary>
/// Gets or sets the arity of the option.
/// </summary>
public virtual ArgumentArity Arity
{
get => Argument.Arity;
set => Argument.Arity = value;
}
}
public class Option<T>
{
/// <inheritdoc/>
public override ArgumentArity Arity
{
get => base.Arity;
set => Argument.Arity = value;
}
} Commandpublic class Command : IdentifierSymbol, System.Collections.Generic.IEnumerable<Symbol>, System.Collections.IEnumerable
.ctor(System.String name, System.String description = null)
public System.Collections.Generic.IReadOnlyList<Argument> Arguments { get; }
public System.Collections.Generic.IEnumerable<Symbol> Children { get; }
public ICommandHandler Handler { get; set; }
public System.Collections.Generic.IReadOnlyList<Option> Options { get; }
public System.Collections.Generic.IReadOnlyList<Command> Subcommands { get; }
public System.Boolean TreatUnmatchedTokensAsErrors { get; set; }
public System.Void Add(Option option)
public System.Void Add(Argument argument)
public System.Void Add(Command command)
public System.Void AddArgument(Argument argument)
public System.Void AddCommand(Command command)
public System.Void AddGlobalOption(Option option)
public System.Void AddOption(Option option)
public System.Void AddValidator(System.Action<System.CommandLine.Parsing.CommandResult> validate)
public System.Collections.Generic.IEnumerable<System.CommandLine.Completions.CompletionItem> GetCompletions(System.CommandLine.Completions.CompletionContext context)
public System.Collections.Generic.IEnumerator<Symbol> GetEnumerator()
RootCommand public class RootCommand : Command, System.Collections.Generic.IEnumerable<Symbol>, System.Collections.IEnumerable
public static System.String ExecutableName { get; }
public static System.String ExecutablePath { get; }
.ctor(System.String description = )
|
Argument.Name is culture-invariant and can be compared to names from reflection, while Argument.HelpName is localized and displayed in help. command-line-api/src/System.CommandLine.NamingConventionBinder/CommandResultExtensions.cs Line 21 in e2cdee3
command-line-api/src/System.CommandLine.NamingConventionBinder/ParameterDescriptor.cs Line 26 in e2cdee3
command-line-api/src/System.CommandLine.NamingConventionBinder/PropertyDescriptor.cs Line 23 in e2cdee3
command-line-api/src/System.CommandLine/Help/HelpBuilder.Default.cs Lines 74 to 87 in e2cdee3
|
Besides the properties, another difference is Independent of whether the type stays or goes, it would be nice that APIs accept a Any additional properties (if ever needed) can be added to |
That is definitely one of our goals.
I was just thinking about creating a parameterless class Command
{
public static Command CreateRootCommand() => new Command($appName);
} |
Yes, and if you prefer to not have factory methods. You could keep the |
Based on the feedback from @bartonjs :
Argument
,Option
, andCommand
to disambiguate from other single-word types #1892getDefaultValue
parameter todefaultValueFactory
#1894ExistingOnly
#1897FromAmong
to include a verb #1899LegalFileNamesOnly
to include a verb #1900Parse
extension methods to the appropriateSymbol
types #1901TreatUnmatchedTokensAsErrors
so that it'sfalse
by default and clearer in intent #1902Command.AddOption
,Command.AddCommand
, andCommand.AddArgument
because they're redundant withAdd
#1903Invoke*
andParse
extension methods to their extendedSymbol
types #1905CommandLineConfiguration
to renamedSymbol
types, e.g.CliConfiguration
#1906CommandLineConfiguration
to be mutable and favor properties over constructors #1907ThrowIfInvalid
to clarify the intent #1908CommandLineConfigurationException
#1909CompletionSourceList
extension methods toCompletionSourceList
#1910CompletionSourceList
#1911DirectiveCollection
#1912override
methods correctly. #1914Symbol
to be less likely to collide and to be consistent with the renaming of its derived types. #1916Binding
namespace. #1917BinderBase<T>
,IValueSource
, andIValueDescriptor
are needed in the public API for usage beyondSetHandler
#1918CommandLineBuilder
into the application framework layer #1920CancellationToken
support be available inasync Main
?) #1921CommandLineBuilder
methods to properties onCommandLineConfiguration
#1922RegisterWithDotnetSuggest
to the application framework layer and consider making it internal, as it will ideally be replaced eventually by intrinsic SDK or runtime support #1923UseDefaults
is still needed #1924UseVersionOption
toCommandLineConfiguration
and renaming #1925UseTokenReplacer
toCommandLineConfiguration
and renaming #1926CompletionDelegate
withAction<CompletionContext>
#1927ICompletionSource
can be replaced with a delegate or class #1928*CompletionContext
scenarios using fewer public types #1929HelpBuilder
into a separate package #1930HelpBuilder.Default
as a nested class #1931HelpSectionDelegate
and replace withAction<HelpContext>
#1932TwoColumnHelpRow
#1933CliAction
design that doesn't require custom implementations to override bothInvoke
andInvokeAsync
methods #1934ArgumentResult.OnlyTake
so that the intent is clearer #1935Action<InvocationContext>
and removingIInvocationResult
#1936CommandLineStringSplitter
#1937CommandLineStringSplitter
including its importance in testing #1938ParseArgument<T>
withFunc<ArgumentResult, T>
#1939ref
forout
parameters. #1942ValidateSymbolResult
delegate withAction<T>
#1944Symbol.Aliases
#1945Based on other feedback:
The text was updated successfully, but these errors were encountered: