Skip to content

System.CommandLine: Completions #84179

Open

Description

Background and motivation

In #68578 (comment), we have introduced a set of symbol types for building a parsable hierarchy.
In #84177 (comment) a set of parsing APIs that expose information required by completions.

In this issue, we want to propose a set of APIs for completions.

API Proposal

namespace System.CommandLine.Completions;

The types presented in the details below are complete, none of our other proposals is extending them.

namespace System.CommandLine.Completions;

/// <summary>
/// Provides details about a command line completion item.
/// </summary>
/// reference: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
public class CompletionItem : IEquatable<CompletionItem>
{
    /// <param name="label">The label value, which is the text displayed to users and, unless <paramref name="insertText"/> is set, is also used to populate the <see cref="InsertText"/> property.</param>
    /// <param name="kind">The kind of completion item.</param>
    /// <param name="sortText">The value used to sort the completion item in a list. If this is not provided, then <paramref name="label"/>  is used.</param>
    /// <param name="insertText">The text to be inserted by this completion item. If this is not provided, then <paramref name="label"/>  is used.</param>
    /// <param name="documentation">Documentation about the completion item.</param>
    /// <param name="detail">Additional details regarding the completion item.</param>
    public CompletionItem(string label, string kind = "Value", string? sortText = null, string? insertText = null, 
        string? documentation = null, string? detail = null);

    /// <summary>
    /// The label value, which is the text displayed to users.
    /// </summary>
    public string Label { get; }

    /// <summary>
    /// The kind of completion item.
    /// </summary>
    public string? Kind { get; }

    /// <summary>
    /// The value used to sort the completion item in a list.
    /// </summary>
    public string SortText { get; }

    /// <summary>
    /// The text to be inserted by this completion item.
    /// </summary>
    public string? InsertText { get; }

    /// <summary>
    /// Documentation about the completion item.
    /// </summary>
    public string? Documentation { get; set; }

    /// <summary>
    /// Additional details regarding the completion item.
    /// </summary>
    public string? Detail { get; }
}

/// <summary>
/// Supports command line completion operations.
/// </summary>
public class CompletionContext
{
    /// The text of the word to be completed, if any.
    public string WordToComplete { get; }

    /// The parse result for which completions are being requested.
    public ParseResult ParseResult { get; }

    /// <summary>
    /// Gets an empty CompletionContext.
    /// </summary>
    /// <remarks>Can be used for testing purposes.</remarks>
    public static CompletionContext Empty { get; }
}

/// <summary>
/// Provides details for calculating completions in the context of complete, unsplit command line text.
/// </summary>
public class TextCompletionContext : CompletionContext
{
    /// <summary>
    /// The position of the cursor within the command line. 
    /// </summary>
    public int CursorPosition { get; }

    /// <summary>
    /// The complete text of the command line prior to splitting, including any additional whitespace.
    /// </summary>
    public string CommandLineText { get; }

    /// <summary>
    /// Creates a new instance of <see cref="TextCompletionContext"/> at the specified cursor position.
    /// </summary>
    /// <param name="position">The cursor position at which completions are calculated.</param>
    public TextCompletionContext AtCursorPosition(int position);
}

namespace System.CommandLine

namespace System.CommandLine;

public abstract class CliSymbol
{
    /// <summary>
    /// Gets completions for the symbol.
    /// </summary>
    public abstract IEnumerable<CompletionItem> GetCompletions(CompletionContext context);
}

public abstract class CliArgument : CliSymbol
{
    /// <summary>
    /// Gets the list of completion sources for the argument.
    /// </summary>
    public List<Func<CompletionContext, IEnumerable<CompletionItem>>> CompletionSources { get; }
}

public abstract class CliOption : CliSymbol
{
    /// <summary>
    /// Gets the list of completion sources for the option.
    /// </summary>
    public List<Func<CompletionContext, IEnumerable<CompletionItem>>> CompletionSources { get; }
}

public sealed class ParseResult
{
    /// <summary>
    /// Gets completions based on a given parse result.
    /// </summary>
    /// <param name="position">The position at which completions are requested.</param>
    /// <returns>A set of completions for completion.</returns>
    public IEnumerable<CompletionItem> GetCompletions(int? position = null);
}

API Usage

Defining completion sources:

CliOption<string> fruitOption = new("--fruit");
fruitOption.CompletionSources.Add("apple", "banana", "cherry");

CliOption<string> vegetableOption = new("--vegetable");
vegetableOption.CompletionSources.Add("asparagus", "broccoli", "carrot");

CliCommand eatCommand = new ("eat")
{
    fruitOption,
    vegetableOption
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions