Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1160,6 +1160,16 @@ /// \endcode bool JavaScriptWrapImports; + /// If true, no line breaks are optimized out (works only with ColumnLimit = 0) + /// \code + /// true: false: + /// if (a vs. if (a && b) { + /// && b) { + /// bar(); bar(); + /// } } + /// \endcode + bool KeepLineBreaksForNonEmptyLines; + /// If true, the empty line at the start of blocks is kept. /// \code /// true: false: @@ -1726,6 +1736,7 @@ IndentWrappedFunctionNames == R.IndentWrappedFunctionNames && JavaScriptQuotes == R.JavaScriptQuotes && JavaScriptWrapImports == R.JavaScriptWrapImports && + KeepLineBreaksForNonEmptyLines == R.KeepLineBreaksForNonEmptyLines && KeepEmptyLinesAtTheStartOfBlocks == R.KeepEmptyLinesAtTheStartOfBlocks && MacroBlockBegin == R.MacroBlockBegin && Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -416,6 +416,8 @@ Style.IndentWrappedFunctionNames); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); + IO.mapOptional("KeepLineBreaksForNonEmptyLines", + Style.KeepLineBreaksForNonEmptyLines); IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", Style.KeepEmptyLinesAtTheStartOfBlocks); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); @@ -676,6 +678,7 @@ LLVMStyle.JavaScriptWrapImports = true; LLVMStyle.TabWidth = 8; LLVMStyle.MaxEmptyLinesToKeep = 1; + LLVMStyle.KeepLineBreaksForNonEmptyLines = false; LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto; @@ -741,6 +744,7 @@ {"^", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}}; GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IndentCaseLabels = true; + GoogleStyle.KeepLineBreaksForNonEmptyLines = false; GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never; GoogleStyle.ObjCSpaceAfterProperty = false; Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -672,7 +672,7 @@ LineFormatter(ContinuationIndenter *Indenter, WhitespaceManager *Whitespaces, const FormatStyle &Style, UnwrappedLineFormatter *BlockFormatter) - : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style), + : Indenter(Indenter), Style(Style), Whitespaces(Whitespaces), BlockFormatter(BlockFormatter) {} virtual ~LineFormatter() {} @@ -715,7 +715,8 @@ // assert so that we can simply call this function for all tokens. return true; - if (NewLine) { + if (NewLine || (Previous.Children[0]->First->MustBreakBefore && + Style.KeepLineBreaksForNonEmptyLines)) { int AdditionalIndent = State.Stack.back().Indent - Previous.Children[0]->Level * Style.IndentWidth; @@ -760,10 +761,10 @@ } ContinuationIndenter *Indenter; + const FormatStyle &Style; private: WhitespaceManager *Whitespaces; - const FormatStyle &Style; UnwrappedLineFormatter *BlockFormatter; }; @@ -786,7 +787,7 @@ while (State.NextToken) { bool Newline = Indenter->mustBreak(State) || - (Indenter->canBreak(State) && State.NextToken->NewlinesBefore > 0); + (State.NextToken->NewlinesBefore > 0 && Indenter->canBreak(State)); unsigned Penalty = 0; formatChildren(State, Newline, /*DryRun=*/false, Penalty); Indenter->addTokenToState(State, Newline, /*DryRun=*/false); Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -2517,6 +2517,8 @@ else readTokenWithJavaScriptASI(); FormatTok->Previous = Previous; + if (FormatTok->NewlinesBefore && Style.KeepLineBreaksForNonEmptyLines) + FormatTok->MustBreakBefore = true; } void UnwrappedLineParser::distributeComments( Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -349,6 +349,22 @@ " void funk() {}\n" "};", Style)); + + Style.KeepLineBreaksForNonEmptyLines = true; + Style.ColumnLimit = 0; + EXPECT_EQ("if (a\n" + " && b) {\n" + "}", + format("if (a\n" + " && b) {\n" + "}", + Style)); + + EXPECT_EQ("[]() {\n" + " foo(); }", + format("[]() {\n" + "foo(); }", + Style)); } TEST_F(FormatTest, RecognizesBinaryOperatorKeywords) {