Clang-format line breaks
So, having messed around in the clang format code and made some patches, here's my two cents:
Clang format is based on,
- parsing the AST using
libclang
, which basically eliminates all whitespace - breaking up the token sequence into "unwrapped lines" which are like "logical" code lines
- Applying rules / configuration info to sometimes split up "unwrapped lines" into smaller units
- Spit it all back out again with new whitespace / indentation
It's not easy to make it respect the original whitepsace, that sort of gets tossed when you first parse the code.
- parsing the AST using
You can control where it places line breaks, most easily, by
- setting the column limit
- using the "bin pack parameters" options
- setting penalties for various kinds of breaks -- break after return type of a function, break before first call parameter, break a string literal, break a comment...
- placing comments at the end of a line (clang format cannot remove the comment and must therefore split the line)
- use the clang-format off / on directives
Here's one thing you could try:
std::vector<std::string> get_vec()
{
return std::vector<std::string> { //
"this is a test", //
"some of the lines are longer", //
"than other, but I would like", //
"to keep them on separate lines" //
};
}
The advantage of this over // clang-format off
is that, if you later change the tab width or some other option, those code lines will still get those formatting changes so you don't need to manually go into the // clang-format off
regions to fix it. However it's still a bit of a hack, YMMV.
Ultimately, clang-format
is very much about imposing a uniform format over an entire code base, making sure that all string literals are formatted in the same style everywhere in your program. If you want to have micro-level control over line-break decisions, that's not really in the spirit of the tool, and you'll have to do things like disable it.
This can sometimes be frustrating esp. when you want to do things with arrays and have columns aligned or something -- for instance, here's some natural code from lua C api:
static luaL_Reg const methods[] = {
{"matches", &dispatch::intf_match_unit},
{"to_recall", &dispatch::intf_put_recall_unit},
{"to_map", &dispatch::intf_put_unit},
{"erase", &dispatch::intf_erase_unit},
{"clone", intf_copy_unit},
{"extract", &dispatch::intf_extract_unit},
{"advance", intf_advance_unit},
};
When clang-format runs over that, it's generally not going to align the right column, its going to place it a fixed number of spaces after the commas and there's not much you can do about it afaik.
Or, if you have 4 x 4 matrix for use with OpenGL:
constexpr float shadow_skew_hardcoded[16] =
{ 1.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
If you let clang-format run over things like this it's just going to mangle them, and afaik there's no easy way to make it format them nicely, so you just have to resort either to the "lots of trivial comments" hack, or use clang-format off when you have something like this. These are just intrinsic limitations of the tool. If you aren't happy ever to have to do things like that then it's probably not the tool for you.
clang format line break in the wrong place - part 2
You can use PenaltyReturnTypeOnItsOwnLine
option with higher value to affect this behavior, making such situations less likely.
PenaltyReturnTypeOnItsOwnLine: 9000
In your case, though, it places const
-qualifier in a separate line. AFAIK, this is not possible to fix now.
void print_table(std::ofstream& ss, const std::string& title, const std::set<part_reporter_pair>& version_set)
const;
clang-format: how to change behavior of line break
You could try the following parameters in your .clang-format
file (How do I specify a clang-format file?):
AlignOperands: true
PenaltyBreakAssignment: 21
PenaltyBreakBeforeFirstCallParameter: 1
AlignOperands
: you want to align the operands after a break line (as you alignanother_variable
below)PenaltyBreakAssignment
:21
because is the shortest value suitable for your case (you have available a playground here)PenaltyBreakBeforeFirstCallParameter
: as documentation describes: The penalty for breaking a function call after call(., so it should be greater than0
.
You can learn more on what a penalty is on clang-format
: In clang-format, what do the penalties do?
Another related and insightful answer: Clang-format: How to avoid new line breaks
PS: consider using smart pointers in C++ ;)
Clang-format: How to avoid new line breaks
For the first case, you need:
AlignOperands: Align
PenaltyBreakAssignment: 6
The first should be straightforward; it is exactly for what you want. The second is needed to tweak clang-format to not prefer breaking the assignment and having the right hand operand on single line. You may need to experiment with different values since this is relative to other penalties. 6 was the lowest penalty that passed on your example code.
For the second case, you can bump up the penalty further, while lowering a conflicting penalty. The "assignment" penalty seems to apply here although technically it is not an assignment but copy initialisation:
PenaltyBreakAssignment: 20
PenaltyBreakBeforeFirstCallParameter: 0
For what it's worth, these penalties default to 2 for assignment and 19 for first call param at least in the version of clang-format that I tested.
Related Topics
Different Ways of Initializing an Object in C++
When and Why Would You Use Static with Constexpr
How to Use Memcpy in C++ to Copy Classes That Have No Pointers or Virtual Functions
What Would a Std::Map Extended Initializer List Look Like
C++ Template Function Compiles in Header But Not Implementation
Using 'Const' in Class's Functions
How to Pass a C++ Lambda to a C-Callback That Expects a Function Pointer and a Context
Opensouce C/C++ Math Expression Parser Library
Checking If Two Cubic BéZier Curves Intersect
Why the Size of a Pointer to a Function Is Different from the Size of a Pointer to a Member Function
Calling Constructor of a Class Member in Constructor
Getting Clang to Work on Windows
Why "Universal References" Have the Same Syntax as Rvalue References
Performance Penalty for Working with Interfaces in C++
Why Is Std::Vector::Operator[] 5 to 10 Times Faster Than Std::Vector::At()