When writing new code that relies on JUCE, it’s nice to follow the style conventions from the JUCE coding standards so that everything looks consistent, and to reduce cognitive overhead when jumping between JUCE files and project files.
I’m not a big fan of manually typing spaces to align function arguments and things, so one of my favourite tools is clang-format. I can just write whatever I want, without thinking about formatting, and it tidies up after me. This is great, because now I can just concentrate on the actual problems I’m trying to solve!
It’s possible to get pretty close to the JUCE code style with the ‘official’ version of clang-format, but there’s a few style rules that it can’t handle:
Adding multiple spaces after an inheritance colon
Omitting spaces before empty braces/parens, but adding a space before braces/parens that have contents
Adding a space after the unary logical not operator
To work around these issues, I’ve patched clang-format to add the formatting rules above. I’ve been using this patched version for a few months now and I’ve found it really helpful, so I thought that it might be helpful to other JUCE devs too. If you want to try it out, you can grab it here.
I wanted to try and get this stuff merged into the official version of clang-format, but I haven’t found the llvm mailing list very responsive. On the off-chance that any llvm devs are reading this, please take pity and review my PR!
Does this read .clang-format-ignore? I struggled to work out how to make the version of clang-format that comes as part of the macOS homebrew install ignore files defined in such a file and resorted to building a BASH script to emulate it, but would love to know the “correct” way to ignore formatting of certain files.
That’s a good question. The binaries on the page I linked above were built fairly recently, and other than the new formatting rules they should do everything that ‘normal’ clang-format does.
That being said, I haven’t heard of .clang-format-ignore before, and I can’t find documentation about it. clang-format is designed to be run on individual files or code provided by stdin and I don’t think it natively supports reformatting entire directories, so I don’t know how an ‘ignore’ feature would really work. If you want to ignore a file, just don’t feed it to clang-format.
I think that the approach of invoking clang-format from a script which knows how to read a .clang-format-ignore file seems like a better solution than modifying clang-format itself.
I also couldn’t find any documentation about it, but noticed a few repos that had .clang-format-ignore files in them. My script does the job, just wondered if it was something about the homebrew version or me not being able to get the search terms right!
It seems your PR got a response a month ago: https://reviews.llvm.org/D55170 — is there any chance you work out their code review? I can try to volunteer here, though my C++ experience isn’t that good.
The ‘parens spacing’ and ‘logical not spacing’ patches have been merged upstream. I have a couple more patches that I’d like to push, but I need to spend some time tidying them up first.
My recommendation for now would be to build clang-format using master on this repo: https://github.com/llvm/llvm-project (unless your package manager happens to have a really recent package).
You can use this with the config posted above, but you’ll need to adjust/remove the SpaceBeforeCpp11BracedList and SpacesBeforeInheritanceColon options.
Unfortunately, clang-format tends to destroy the formatting by turning the whole statement into a single line. I tried to experiment with several options (e.g. BinPackArguments, AllowAllArgumentsOnNextLine, …) with no luck. I know I can disable formatting for a specific range, but that would be less than ideal. Do you guys have any suggestion for this?
I think the main thing you need to do to get this kind of formatting is to set the ‘ColumnLimit’ to ‘0’, and then clang-format will let you choose where to put newlines, rather than attempting to make each line as long as possible within the column limit.
As I mentioned above, I got a couple of patches merged, but I haven’t got the fix for spacing around curly-braces merged yet. The version of clang-format in homebrew seems to be from January, so I guess building from source is still the best way to get an up-to-date version.
The .clang-format config file I’ve been using looks like this. You could try it out with whatever clang-format binary you’re able to access, and just remove any keys that clang-format chokes on.
Ah, sorry to hear about that. AFAIK defining function-style macros doesn’t work if you leave a space before the parens (it turns into a non-function-style replacement):
#define MY_COOL_FN(foo, bar) ...
^ no space here!
I imagine that clang-format is hard-coded to always omit spaces before parens in macro definitions as a precaution. Could you check by setting your config to use Always instead of NonEmptyParentheses? I’d expect that to be broken too.
It has been 9 months. iiuc, many of the PRs are in clang-format already.
Would be nice if the JUCE team would have their formatting within the JUCE repo.
For personal JUCE projects, I’m now just copying latest message here and modify it to clang-format 10, which is harder to maintain I guess