FWIW, I’ve never found a formatter (for any language) that works as well as doing it manually…
My main issue is with line-wrapping: formatters don’t split long lines at the most appropriate place. That’s because it’s partly about the syntax (splitting at the lowest-precedence operators — which even IntelliJ’s formatter fails to do), but also about the meaning of the code and trying to make it clearest to the reader; and that’s partly a matter of taste and judgement.
Also, I prefer to split before operators, not after. I know that’s a controversial choice, but for me it makes the structure of the code easier to see when you scan down the left-hand side, makes operators line up nearly, and better matches the way I think about code. (It’s a perpetual annoyance that Kotlin is over-eager to infer a semicolon, so you sometimes need to put an expression in parens to prevent the continuation line giving an error, or — even worse — being silently ignored!)
I disagree with some of the formatter’s other decisions, too (despite tweaking all the settings), but line-wrapping is the major offender. (It’s too eager to put closing parens on new lines, too. That can help to delineate a long parameter list, but when you have closing parens and braces, it’s often clearer to wrap only the braces.)
I find IntelliJ’s auto-indenter pretty good. But I do most of the rest manually.
This does raise the question of why you need to be running a formatter as part of every build? Shouldn’t people be writing well-formatted code in the first place? If not, then you might very well see that as your real problem…
My main goal is to have a well structured code that looks always the same. This is especially important if several developers are working on the same code, because subtle differences in the formatting would pollute pull requests with pointless changes. I don’t want to discuss formatting in PR reviews (what I did too much in the past).
As a downside I’m willing to accept that the outcome is not always my personal favorite, but overall it is the best experience for all team members. That automatic, deterministic formatting is part of many modern tool chains is probably not by accident. gofmt, rustfmt and Prettier come to mind. It is like with laws: You might not always like them, but it is better to have them.
Line wrapping is actually one of the biggest weaknesses of the IntelliJ formatter. Sometime the line length limit is ignored, sometimes a construct that could easily be wrapped to the next line is scattered on a bunch of lines.
In the end I picked ktfmt with the “kotlinlang” style and it works like a charme with Gradle and the IntelliJ plugins.
Why should I write well formatted code if there’s a code formatter which does it for me?
This! And I learned that “well-formatted” means different things for different people. Additionally humans might simply forget to format the code or forget a certain convention.
In my company we use GitHub - pinterest/ktlint: An anti-bikeshedding Kotlin linter with built-in formatter and it works well for us.