dart-lang / code_builder

A fluent API for generating valid Dart source code
https://pub.dev/packages/code_builder
BSD 3-Clause "New" or "Revised" License
427 stars 66 forks source link

Option to generate trailing commas after lists of parameters #365

Closed hacker1024 closed 2 years ago

hacker1024 commented 2 years ago

As far as I'm aware, there's no way to generate trailing commas at the end of constructor/function invocations/declarations. It looks like the emitter is hard-coded to leave them out.

It'd be great if a feature to include them was added. I'm generating code for humans to read, so the styling is important to me.

This could be enabled on a global scale (like the orderDirectives option), or on a local scale as an option in the constructor/function/invocation classes.

hacker1024 commented 2 years ago

A very quick-and-dirty proof-of-concept, adding the exact writeTrailingNamedParameterCommas option that I needed, can be found here: https://github.com/hacker1024/code_builder/commit/7fa1ac26e526763e4cc70c4345b514bb830c78c8

pierremrtn commented 2 years ago

Very interested to have this feature !

srawlins commented 2 years ago

@jakemac53 @natebosch would this be accepted perhaps as a flag on Emitter? Seems like a reasonable place to put it as an opt-in.

This is important now for performance reasons. Adding trailing commas can improve dart format performance by 10x in some cases.

(I guess I don't have to format my generated code but gosh darn it I love formatted code and I don't want to open the floodgates of writing my own HalfDecentFormatter in mockito just to avoid 1000 column lines and unreadable 0-indented swaths of code just so that debugging isn't a nightmare.)

srawlins commented 2 years ago

To get into some details:

natebosch commented 2 years ago

Is the performance differential with trailing commas new?

cc @munificent

@srawlins - Is there any reason not to make this the default and only option?

munificent commented 2 years ago

Is the performance differential with trailing commas new?

Argument lists have always been relatively slow to format because:

  1. The number of ways an argument list can split is linear in the number of arguments.
  2. The way an argument list splits can affect both the way the argument expressions split, and the way surrounding code splits, since the ) is attached to the last argument.

That means that big deeply nested function calls have always been slow to format.

Argument lists are coincidentally faster to format because they use the same code that we use for collection literals. That code formats the list of elements entirely independently of the surrounding collection. We're able to do that for trailing comma argument lists since the ) gets pushed to its own line.

Recently, I managed to get the same code working for cascades, so they're faster too.

Getting that code to work for argument lists without trailing commas would be much harder because argument lists have a range of ways that can split:

  1. Not at all.
  2. Before the first argument.
  3. Between one single pair of positional arguments.
  4. Before all arguments.
  5. Before all named arguments (with all combinations of 1-4 for the preceding positional arguments).

Long term, I hope to move towards something like Flutter's argument list formatting style and eliminating the current (very complex) argument formatting rules, so I haven't wanted to try to optimize it.