Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

CompletionSources not sorted properly when building HelpName default suggestions

Đang mở
#2,705 2 bình luận 1 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@zjdangge đang làm issue này rồi.

Từ ngày 15/10/2026.

  • #2858 của @zjdangge — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
45/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
csharp
Lĩnh vực
cli

Hướng nghiên cứu

Bắt đầu tại dòng 142 của src/command-line-api/src/System.CommandLine/Option.cs và tái hiện thứ tự bằng mẫu CompletionItem trong issue. Theo dõi cách các giá trị CompletionContext rỗng và một phần được đưa vào quá trình sắp xếp, sau đó xác minh rằng các gợi ý trợ giúp và tính năng hoàn thành bằng tab tuân theo thứ tự được hiển thị trong issue.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

The sorting logic done here when building the default help text from the list of completions is backward:

https://github.com/dotnet/dotnet/blob/2db1f5ee2bdda2e8d873769325fabede32e420e0/src/command-line-api/src/System.CommandLine/Option.cs#L142

Since the ThenBy is on the Label, the resulting sorted collection is re-sorted by Label, as a primary order, not as a secondary order like SQL.

And, to hoist the current entry to the top of the list, the OrderBy needs to be OrderByDescending.

Here is an example that shows the bad behavior:


public static class Program
{
    static CompletionItem[] sampleCompletions =
    [
      new ( "5", sortText: "05" ),
      new ( "10", sortText: "10" ),
      new ( "6", sortText: "06" ),
      new ( "20", sortText: "10" ),
      new ( "30", sortText: "30" )
    ];

    public static async Task<int> Main ( string[] argv)
    {
    RootCommand root   = new ( "example" );
    Option<int> option = new ( "option" );
    option.CompletionSources.Add ( static ctx => sampleCompletions );
    root.Options.Add ( option );
    await root.Parse ( [ "--help" ] ).InvokeAsync ( );
    }
}

Output:
```text
Description:
  example

Usage:
  SnapsInAZfs [options]

Options:
  option <10|20|30|5|6>
  -?, -h, --help         Show help and usage information
  --version              Show version information

Note the improperly ordered suggestions in the HelpName for option.

Here is why, isolated to what the line referenced at the top of the issue does:

      CompletionContext theCompletionContext = CompletionContext.Empty;
      IOrderedEnumerable<CompletionItem> improperlyOrdered = sampleCompletions
                                                            .OrderBy ( item => item.SortText.IndexOfCaseInsensitive ( theCompletionContext.WordToComplete ) )
                                                            .ThenBy ( item => item. Label, StringComparer.OrdinalIgnoreCase );

      foreach ( CompletionItem c in improperlyOrdered )
      {
        Console.WriteLine ( c.Label );
      }

Output:

10
20
30
5
6

Here is the fixed sorting code, as it applies to building HelpText (an empty context gets passed in):

    IOrderedEnumerable<CompletionItem> properlyOrdered = sampleCompletions
                                                        .OrderByDescending ( item => item.Label.IndexOfCaseInsensitive ( theCompletionContext.WordToComplete ) )
                                                        .ThenBy ( item => item.SortText, StringComparer.OrdinalIgnoreCase );

    foreach ( CompletionItem c in properlyOrdered )
    {
      Console.WriteLine ( c.Label );
    }

Output:

5
6
10
20
30

And here is how it would look during tab completion, if the user had already entered "2" and then presses tab (simulated by giving it the "2" directly):

    IOrderedEnumerable<CompletionItem> properlyOrderedWithPartialEntry = sampleCompletions
                                                                        .OrderByDescending ( item => item.Label.IndexOfCaseInsensitive ( "2" ) )
                                                                        .ThenBy ( item => item.SortText, StringComparer.OrdinalIgnoreCase );

    foreach ( CompletionItem c in properlyOrderedWithPartialEntry )
    {
      Console.WriteLine ( c.Label );
    }

Output:

20
5
6
10
30

The actual code to replace what is there now would be:
This is incorrect. See my follow-up comment that fixes it.

            return completions
                   .OrderByDescending(item => item.Label.IndexOfCaseInsensitive(context.WordToComplete))
                   .ThenBy(symbol => symbol.SortText, StringComparer.OrdinalIgnoreCase);

Also, it may be worth pointing out that the extension method IndexOfCaseInsensitive does not use the same StringComparer as the code here. It uses invariant culture. This uses ordinal. So the two sorts aren't the same, necessarily, even if the values are identical.

Ngôn ngữ chính
C#
Star
3.7k
Fork
434
Merge trung bình
6 giờ 27 phút
Pull request đã merge (30 ngày)
2

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của dotnet/command-line-api

Tất cả issue của dotnet/command-line-api

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.