summaryrefslogtreecommitdiff
path: root/src/plugins/clangformat
diff options
context:
space:
mode:
authorIvan Donchevskii <ivan.donchevskii@qt.io>2019-03-11 11:10:12 +0100
committerIvan Donchevskii <ivan.donchevskii@qt.io>2019-03-11 10:32:23 +0000
commit5006bfb1572c64da2ac3d5104074c50cbdfa785a (patch)
treeed89520fb911c4b35feeed9d866cfd07a30730b4 /src/plugins/clangformat
parent2d3e8ef77b7b69a806343758a0047024e67f0761 (diff)
downloadqt-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.cpp115
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 &currentBlock)
{
- 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 &currentBlock,
+ 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 &currentBlock,
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);
}