diff options
author | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2019-03-11 11:10:12 +0100 |
---|---|---|
committer | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2019-03-11 10:32:23 +0000 |
commit | 5006bfb1572c64da2ac3d5104074c50cbdfa785a (patch) | |
tree | ed89520fb911c4b35feeed9d866cfd07a30730b4 /src/plugins/clangformat | |
parent | 2d3e8ef77b7b69a806343758a0047024e67f0761 (diff) | |
download | qt-creator-5006bfb1572c64da2ac3d5104074c50cbdfa785a.tar.gz |
ClangFormat: Simplify the dummy text for empty line heuristics
The text to fill the empty line mostly depends not on the
fact of being inside parenthesis or not but rather on the
last preceding meaningful character.
Let's check for this character and sometimes for the following
one to better understand the current context and pick the
proper dummy text.
With this behavior improvement we can better indent empty lines
inside initializer lists with empty lines inside.
Change-Id: Id2f27454ef56dfdf8c15b5efb14c4d09242908a9
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
Diffstat (limited to 'src/plugins/clangformat')
-rw-r--r-- | src/plugins/clangformat/clangformatbaseindenter.cpp | 115 |
1 files changed, 53 insertions, 62 deletions
diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 83e877259c..bdf384863a 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -127,48 +127,51 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } -// We don't need other types so far. -enum class CharacterType { OpeningParen, OpeningBrace, Invalid }; +QTextBlock reverseFindLastEmptyBlock(QTextBlock start) +{ + if (start.position() > 0) { + start = start.previous(); + while (start.position() > 0 && start.text().trimmed().isEmpty()) + start = start.previous(); + if (!start.text().trimmed().isEmpty()) + start = start.next(); + } + return start; +} -CharacterType firstOpeningParenOrBraceBeforeBlock(const QTextBlock &block) +enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown }; + +QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) { - if (block.text().trimmed().startsWith(')')) - return CharacterType::OpeningParen; + const QTextDocument *doc = currentBlock.document(); + int currentPos = currentBlock.position(); + while (currentPos < doc->characterCount() && doc->characterAt(currentPos).isSpace()) + ++currentPos; + return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null; +} - QTextCursor cursor(block); - const QTextDocument *doc = block.document(); - - cursor.movePosition(QTextCursor::PreviousCharacter); - QChar currentChar = doc->characterAt(cursor.position()); - - int parenCount = 0; - int braceCount = 0; - - while (cursor.position() > 0 && parenCount <= 0 && braceCount <= 0) { - cursor.movePosition(QTextCursor::PreviousCharacter); - currentChar = doc->characterAt(cursor.position()); - if (currentChar == '(') - ++parenCount; - else if (currentChar == ')') - --parenCount; - else if (currentChar == '{') - ++braceCount; - else if (currentChar == '}') - --braceCount; +CharacterContext characterContext(const QTextBlock ¤tBlock, + const QTextBlock &previousNonEmptyBlock) +{ + const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + if (prevLineText.endsWith(',')) { + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); + // We don't need to add comma in case it's the last argument. + if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') + return CharacterContext::LastAfterComma; + return CharacterContext::AfterComma; } - if (braceCount > 0) - return CharacterType::OpeningBrace; - if (parenCount > 0) - return CharacterType::OpeningParen; + if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}')) + return CharacterContext::NewStatement; - return CharacterType::Invalid; + return CharacterContext::Continuation; } // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, - QByteArray &dummyText, + CharacterContext &charContext, const QTextBlock &block, bool secondTry) { @@ -188,24 +191,24 @@ int forceIndentWithExtraText(QByteArray &buffer, int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { - if (dummyText.isEmpty()) { - const CharacterType charType = firstOpeningParenOrBraceBeforeBlock(block); + if (charContext == CharacterContext::LastAfterComma) { + charContext = CharacterContext::AfterComma; + } else if (charContext == CharacterContext::Unknown) { + QTextBlock lastBlock = reverseFindLastEmptyBlock(block); + if (lastBlock.position() > 0) + lastBlock = lastBlock.previous(); + // If we don't know yet the dummy text, let's guess it and use for this line and before. - if (charType != CharacterType::OpeningParen) { - // Use the complete statement if we are not inside parenthesis. - dummyText = "a;a;"; - } else { - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - } - dummyText = prevBlock.text().endsWith(',') ? "&& a," : "&& a"; - } + charContext = characterContext(block, lastBlock); + } + + QByteArray dummyText; + if (charContext == CharacterContext::NewStatement) { + dummyText = "a;a;"; + } else if (charContext == CharacterContext::AfterComma) { + dummyText = "&& a,"; + } else { + dummyText = "&& a"; } buffer.insert(utf8Offset, dummyText); @@ -349,18 +352,6 @@ bool doNotIndentInContext(QTextDocument *doc, int pos) return false; } -QTextBlock reverseFindLastEmptyBlock(QTextBlock start) -{ - if (start.position() > 0) { - start = start.previous(); - while (start.position() > 0 && start.text().trimmed().isEmpty()) - start = start.previous(); - if (!start.text().trimmed().isEmpty()) - start = start.next(); - } - return start; -} - int formattingRangeStart(const QTextBlock ¤tBlock, const QByteArray &buffer, int documentRevision) @@ -405,11 +396,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer adjustFormatStyleForLineBreak(style, replacementsToKeep); if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { - QByteArray dummyText; + CharacterContext currentCharContext = CharacterContext::Unknown; // Iterate backwards to reuse the same dummy text for all empty lines. for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) { utf8Length += forceIndentWithExtraText(buffer, - dummyText, + currentCharContext, m_doc->findBlockByNumber(index), secondTry); } |