Skip to content

vine: rewrite formatter#559

Merged
tjjfvi merged 17 commits intodevfrom
refmt
May 7, 2026
Merged

vine: rewrite formatter#559
tjjfvi merged 17 commits intodevfrom
refmt

Conversation

@tjjfvi
Copy link
Copy Markdown
Member

@tjjfvi tjjfvi commented May 3, 2026

The old formatter had a number of limitations – perhaps most notably, it was very 'greedy'; when a syntax node was deciding to be multiline or not, it would only check if it would fit in the max width minus what was written so far onto the line. This means it wouldn't take into account anything after it on the same line, and so quite often things would be formatted like

fn some_function(with: A, really: Long, parameter: List, that: Should, be: Broken) -> List[
  N32,
] {
  // ...
}

This occured because when it was printing the parameter list, it only looked at the length of fn some_function(...), which was below the max limit, and so it printed it on a single line. Only once it got to the return type did it realize something was going over the maximum width, so it breaks the return type, which looks really bad.

In the new formatting algorithm, each node receives information about what comes both before and after it on the same line, and decides whether or not to break on that basis. This means that the above example will instead get formatted as

fn some_function(
  with: A,
  really: Long,
  parameter: List,
  that: Should,
  be: Broken,
) -> List[N32] {
  // ...
}

Which is a lot nicer. This happens because the parameter list can see that the return type after it would cause the line to overflow.

If, on the other hand, the parameters were fine, and it was the return type that was super long, it would get formatted like so:

fn some_function(short: Params, dont: Break) ->
  WoahThisIsAReallyLongReturnType[WhyIsItSoLong]
{
  // ...
}

This is because each syntax node can either configure the order in which its children will break, or have it be automatic, in which case larger children will get broken first. Function signatures have the order be automatic, so when the parameter list is excessively long, it's broken, but when the return type is excessively long, it's broken instead.

Other improvements to the formatting include:

  • line comments will be respected in all blocks (previously, they would be removed in empty blocks and blocks with only one statement)
  • many more syntax elements can be broken (perhaps most notably, binary operators and method chains)
  • if expressions can now be single-line
  • the maximum width is now respected precisely (when possible), as opposed to approximately
    • this includes indent width
  • the maximum width can now be configured from the command line

More improvements to the formatter are needed (e.g. respecting comments), but I believe this new formatting algorithm is quite solid, and the remaining changes will mostly be in how the Content passed to the algorithm is generated.

I also added a vine show command, which prints a Vine file formatted to the width of the terminal and syntax highlighted. (yes I added syntax highlighting to the formatter. no I'm not sorry.) It also has a --watch mode which reformats the file as the terminal is resized; it's not super useful from an end-user perspective, but it is fun to play with, and is very useful for debugging/testing the formatter.

@tjjfvi tjjfvi requested a review from nilscrm May 3, 2026 00:13
@github-actions github-actions Bot changed the base branch from main to dev May 3, 2026 00:13
@tjjfvi tjjfvi force-pushed the refmt branch 2 times, most recently from 3e5e96f to b9ef5bc Compare May 3, 2026 13:55
Comment thread tests/aoc_2024/day_03.vi Outdated
Comment thread tests/programs/life.vi Outdated
Comment thread vine/src/features/if_.rs Outdated
Comment thread tests/programs/array_smoothsort.vi Outdated
Comment thread tests/aoc_2024/day_03.vi Outdated
Copy link
Copy Markdown
Contributor

@nilscrm nilscrm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very neat

@tjjfvi tjjfvi added this pull request to the merge queue May 7, 2026
Merged via the queue into dev with commit 095a401 May 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants