keep-sorted Documentation

repository·main·Indexed 18 days ago

https://github.com/google/keep-sorted

A language-agnostic tool designed to sort lines located between specific comment-delimited markers (keep-sorted start and keep-sorted end) within a file. It supports nested blocks, custom sorting logic via RE2 regular expressions, numeric sorting, and integration with pre-commit. The tool provides two primary CLI modes: 'fix' to automatically sort content and 'lint' to check for unsorted blocks.

Tokens
4.1K
Snippets
19
Records
23
Agent score
62%

What's inside keep-sorted

  1. What is keep-sorted

    main
    keep-sorted is a language-agnostic formatter designed to sort lines located between two specific markers within a larger file. It is useful for maintaining alphabetical order in lists, imports, or configuration blocks while leaving the rest of the file untouched.
  2. Ignore prefixes during sorting

    main

    Use ignore_prefixes=prefix1,prefix2 to exclude specific prefixes from the sorting logic. If a line starts with one of these prefixes, it is treated as an empty string for sorting purposes.

    +// keep-sorted start ignore_prefixes=fs.setBoolFlag,fs.setIntFlag
     fs.setBoolFlag("paws_with_cute_toebeans", true)
     fs.setIntFlag("pretty_whiskered_kitten", 6)
     fs.setBoolFlag("whiskered_adorable_dog", true)
     // keep-sorted end
  3. Configure post-sorting formatting

    main

    Adjust the output appearance after sorting:

    • remove_duplicates=no: By default, keep-sorted removes duplicate lines. Set to no to preserve them. Note that duplicates with different attached comments are preserved by default.
    • newline_separated=N: Adds blank lines between sorted items. Use newline_separated=yes for one blank line, or newline_separated=N for $N$ blank lines.
    +# keep-sorted start remove_duplicates=no
     rotation: bar
     rotation: bar
     rotation: baz
     # keep-sorted end
    +# keep-sorted start newline_separated=2
     Apples
     
     
     Bananas
     # keep-sorted end
  4. Skip lines at the start or end of a block

    main

    Use skip_lines to prevent specific lines from being included in the sort, such as table headers or footers.

    • A positive value skips lines at the start of the sorted region.
    • A negative value skips lines at the end of the sorted region.

    Example: skip_lines=2,-2 skips the first 2 lines and the last 2 lines of the block.

    +<!-- keep-sorted start skip_lines=2,-2 -->
     Item  | Cost
     ----- | -----
     Apple  | $1.09
     Lemon  | $1.50
     ----- | -----
     Total  | $4.69
    +<!-- keep-sorted end -->
  5. Manage sticky comments and prefixes

    main

    By default, comments embedded in a sorted block stick to their successor. The comment must use the same marker as the keep-sorted instruction (e.g., # for # keep-sorted start).

    Supported markers: //, /*, #, --, ;, and <!--.

    • Disable sticky comments: Use sticky_comments=no to prevent comments from moving with the lines they precede.
    • Custom sticky prefixes: Use sticky_prefixes=prefix1,prefix2 to make other specific prefixes stick to their successors. Prefixes cannot contain spaces.
    +# keep-sorted start sticky_comments=no
    # alice
    # bob
    # charlie
    username: al1
    username: bo2
    username: ch3
     # keep-sorted end
    +// keep-sorted start sticky_prefixes=/*,@Annotation
     Baz baz;
     /* Foo */
     @Annotation
     Foo foo;
     // keep-sorted end
  6. How to use keep-sorted markers in files

    main

    To define a block of text for keep-sorted to manage, surround the lines with keep-sorted start and keep-sorted end markers inside comments. The markers must match the comment syntax of the language you are using (e.g., // for Java, # for Python).

    keep-sorted also supports nested blocks, allowing you to sort multiple independent lists within a single larger sorted block.

    @Component(
        modules = {
          // keep-sorted start
          AuthModule.class,
          GetRequestModule.class,
          LoggingModule.class,
          // keep-sorted end
        })
  7. How keep-sorted handles whitespace and indentation

    main

    keep-sorted aims to mimic human sorting behavior regarding whitespace:

    • Indentation: With the default group=yes setting, lines with increasing indentation are grouped together during sorting.
    • Leading Whitespace: Leading whitespace is ignored when comparing strings for sorting order.
    • Trailing Newlines: keep-sorted preserves any number of trailing newlines at the end of a block; it will not remove them.
    • Internal Linebreaks: Non-trailing linebreaks (linebreaks within the content) are moved to the beginning of the content block. If remove_duplicates=yes is set, these moved linebreaks are deduplicated.
  8. Group lines using prefixes or regex

    main

    You can define group boundaries using prefixes or regular expressions:

    • Prefix grouping: Use group_prefixes=prefix1,prefix2 to treat any line starting with these prefixes as a continuation of the previous line.
    • Regex-delimited grouping: Use group_start_regex or group_end_regex with RE2 regular expressions.
      • group_start_regex: The matching line starts a new group.
      • group_end_regex: The matching line ends the current group.
      • These options are mutually exclusive.
      • Use newline_separated=yes if the regex should trigger based on line breaks.
    +// keep-sorted start group_prefixes=and,with
     hamburger
     with lettuce
     and tomatoes
     peanut butter
     and jelly
     spaghetti
     with meatballs
    +// keep-sorted end
    +// keep-sorted start group_start_regex=["^define\\b"] newline_separated=yes
     // Some other comment for bar
     define bar =
     ghi + jkl;
    
     // Some comment for foo
     define foo =
     abc + def;
    +// keep-sorted end
  9. Configure sorting behavior (Case, Numeric, Regex, Order)

    main

    Control how the logical lines are ordered using these options:

    • case=no: Sort case-insensitively (default is case-sensitive).
    • numeric=yes: Interpret sequences of digits as numeric values rather than lexical strings.
    • by_regex=...: Sort based on the results of RE2 regular expressions. If capturing groups are used, only the captured text is used for sorting.
      • Note: . matches \n by default (adds s flag). Use (?-s) to disable.
    • order=desc: Sort in descending order (default is ascending).
    • prefix_order=p1,p2,...: Define a custom order for lines starting with specific prefixes. Unmatched lines are placed after matched ones. Use an empty prefix (,,) to place unmatched lines between specific prefixes.
    +# keep-sorted start case=no
     alpha
     Bravo
     charlie
     Delta
     echo
     Foxtrot
     # keep-sorted end
    +# keep-sorted start numeric=yes
      'PROGRESS_1_PERCENT',
      'PROGRESS_5_PERCENT',
      'PROGRESS_10_PERCENT',
      'PROGRESS_50_PERCENT',
      'PROGRESS_100_PERCENT',
      # keep-sorted end
    +// keep-sorted start prefix_order=INIT_,,FINAL_
     INIT_BAR,
     INIT_FOO,
     DO_SOMETHING_WITH_BAR,
     DO_SOMETHING_WITH_FOO,
     FINAL_BAR,
     FINAL_FOO
     // keep-sorted end
  10. Configure line continuation and block grouping

    main

    Pre-sorting options define what constitutes a single logical line.

    • Line continuations: By default, increasing indentation groups lines with the line above. Disable this using group=no.
    • Blocks: Use block=yes to handle complex structures like Go structs or JSON objects. It identifies groups by balancing typical symbols (parentheses, braces, brackets, and quotes).

    Warning: keep-sorted is not language-aware; it sorts groups as basic strings. Mixing line breaks and whitespace may cause unexpected results. Angle brackets (< and >) are not supported in block mode.

    Note: Braces inside string literals (starting/ending with ', ''', ", """, or `) are ignored for balancing.

    +// keep-sorted start group=no
         new Baz()
     private final Bar bar;
     private final Baz baz =
     private final Foo foo;
     // keep-sorted end
      widgets := []widget{
    +   // keep-sorted start block=yes
        {
          Name: "abc",
        },
        {
          Name: "def",
        },
    +   // keep-sorted end
      }