C++ indenter: Separate indent into logical indent and padding.

This commit is contained in:
Christian Kamm
2010-09-10 14:12:14 +02:00
parent eed852d8be
commit 642b6fb0d3
5 changed files with 265 additions and 159 deletions

View File

@@ -1499,17 +1499,21 @@ void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedCha
CppTools::QtStyleCodeFormatter codeFormatter(ts); CppTools::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block); codeFormatter.updateStateUntil(block);
const int depth = codeFormatter.indentFor(block); int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
// only reindent the current line when typing electric characters if the // only reindent the current line when typing electric characters if the
// indent is the same it would be if the line were empty // indent is the same it would be if the line were empty
if (isElectricCharacter(typedChar)) { if (isElectricCharacter(typedChar)) {
const int newlineIndent = codeFormatter.indentForNewLineAfter(block.previous()); int newlineIndent;
if (ts.indentationColumn(block.text()) != newlineIndent) int newlinePadding;
codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
if (ts.indentationColumn(block.text()) != newlineIndent + newlinePadding)
return; return;
} }
ts.indentLine(block, depth); ts.indentLine(block, indent + padding, padding);
} }
void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar) void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
@@ -1529,7 +1533,10 @@ void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar type
QTextCursor tc = textCursor(); QTextCursor tc = textCursor();
tc.beginEditBlock(); tc.beginEditBlock();
do { do {
ts.indentLine(block, codeFormatter.indentFor(block)); int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
ts.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block); codeFormatter.updateLineStateChange(block);
block = block.next(); block = block.next();
} while (block.isValid() && block != end); } while (block.isValid() && block != end);

View File

@@ -72,7 +72,10 @@ void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
codeFormatter.updateStateUntil(block); codeFormatter.updateStateUntil(block);
do { do {
tabSettings.indentLine(block, codeFormatter.indentFor(block)); int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
tabSettings.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block); codeFormatter.updateLineStateChange(block);
block = block.next(); block = block.next();
} while (block.isValid() && block != end); } while (block.isValid() && block != end);

View File

@@ -52,6 +52,7 @@ CodeFormatter::BlockData::BlockData()
CodeFormatter::CodeFormatter() CodeFormatter::CodeFormatter()
: m_indentDepth(0) : m_indentDepth(0)
, m_paddingDepth(0)
, m_tabSize(4) , m_tabSize(4)
{ {
} }
@@ -461,19 +462,21 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
saveCurrentState(block); saveCurrentState(block);
} }
int CodeFormatter::indentFor(const QTextBlock &block) void CodeFormatter::indentFor(const QTextBlock &block, int *indent, int *padding)
{ {
// qDebug() << "indenting for" << block.blockNumber() + 1; // qDebug() << "indenting for" << block.blockNumber() + 1;
restoreCurrentState(block.previous()); restoreCurrentState(block.previous());
correctIndentation(block); correctIndentation(block);
return m_indentDepth; *indent = m_indentDepth;
*padding = m_paddingDepth;
} }
int CodeFormatter::indentForNewLineAfter(const QTextBlock &block) void CodeFormatter::indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding)
{ {
restoreCurrentState(block); restoreCurrentState(block);
return m_indentDepth; *indent = m_indentDepth;
*padding = m_paddingDepth;
} }
void CodeFormatter::updateStateUntil(const QTextBlock &endBlock) void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
@@ -574,8 +577,9 @@ void CodeFormatter::invalidateCache(QTextDocument *document)
void CodeFormatter::enter(int newState) void CodeFormatter::enter(int newState)
{ {
int savedIndentDepth = m_indentDepth; int savedIndentDepth = m_indentDepth;
onEnter(newState, &m_indentDepth, &savedIndentDepth); int savedPaddingDepth = m_paddingDepth;
State s(newState, savedIndentDepth); onEnter(newState, &m_indentDepth, &savedIndentDepth, &m_paddingDepth, &savedPaddingDepth);
State s(newState, savedIndentDepth, savedPaddingDepth);
m_currentState.push(s); m_currentState.push(s);
m_newStates.push(s); m_newStates.push(s);
} }
@@ -592,6 +596,7 @@ void CodeFormatter::leave(bool statementDone)
// restore indent depth // restore indent depth
State poppedState = m_currentState.pop(); State poppedState = m_currentState.pop();
m_indentDepth = poppedState.savedIndentDepth; m_indentDepth = poppedState.savedIndentDepth;
m_paddingDepth = poppedState.savedPaddingDepth;
int topState = m_currentState.top().type; int topState = m_currentState.top().type;
@@ -622,7 +627,7 @@ void CodeFormatter::correctIndentation(const QTextBlock &block)
const int lexerState = tokenizeBlock(block); const int lexerState = tokenizeBlock(block);
Q_ASSERT(m_currentState.size() >= 1); Q_ASSERT(m_currentState.size() >= 1);
adjustIndent(m_tokens, lexerState, &m_indentDepth); adjustIndent(m_tokens, lexerState, &m_indentDepth, &m_paddingDepth);
} }
bool CodeFormatter::tryExpression(bool alsoExpression) bool CodeFormatter::tryExpression(bool alsoExpression)
@@ -837,6 +842,7 @@ void CodeFormatter::saveCurrentState(const QTextBlock &block)
blockData.m_beginState = m_beginState; blockData.m_beginState = m_beginState;
blockData.m_endState = m_currentState; blockData.m_endState = m_currentState;
blockData.m_indentDepth = m_indentDepth; blockData.m_indentDepth = m_indentDepth;
blockData.m_paddingDepth = m_paddingDepth;
QTextBlock saveableBlock(block); QTextBlock saveableBlock(block);
saveBlockData(&saveableBlock, blockData); saveBlockData(&saveableBlock, blockData);
@@ -848,6 +854,7 @@ void CodeFormatter::restoreCurrentState(const QTextBlock &block)
BlockData blockData; BlockData blockData;
if (loadBlockData(block, &blockData)) { if (loadBlockData(block, &blockData)) {
m_indentDepth = blockData.m_indentDepth; m_indentDepth = blockData.m_indentDepth;
m_paddingDepth = blockData.m_paddingDepth;
m_currentState = blockData.m_endState; m_currentState = blockData.m_endState;
m_beginState = m_currentState; m_beginState = m_currentState;
return; return;
@@ -857,13 +864,14 @@ void CodeFormatter::restoreCurrentState(const QTextBlock &block)
m_currentState = initialState(); m_currentState = initialState();
m_beginState = m_currentState; m_beginState = m_currentState;
m_indentDepth = 0; m_indentDepth = 0;
m_paddingDepth = 0;
} }
QStack<CodeFormatter::State> CodeFormatter::initialState() QStack<CodeFormatter::State> CodeFormatter::initialState()
{ {
static QStack<CodeFormatter::State> initialState; static QStack<CodeFormatter::State> initialState;
if (initialState.isEmpty()) if (initialState.isEmpty())
initialState.push(State(topmost_intro, 0)); initialState.push(State(topmost_intro, 0, 0));
return initialState; return initialState;
} }
@@ -892,14 +900,15 @@ int CodeFormatter::tokenizeBlock(const QTextBlock &block, bool *endedJoined)
return lexerState; return lexerState;
} }
void CodeFormatter::dump() void CodeFormatter::dump() const
{ {
qDebug() << "Current token index" << m_tokenIndex; qDebug() << "Current token index" << m_tokenIndex;
qDebug() << "Current state:"; qDebug() << "Current state:";
foreach (State s, m_currentState) { foreach (State s, m_currentState) {
qDebug() << s.type << s.savedIndentDepth; qDebug() << s.type << s.savedIndentDepth << s.savedPaddingDepth;
} }
qDebug() << "Current indent depth:" << m_indentDepth; qDebug() << "Current indent depth:" << m_indentDepth;
qDebug() << "Current padding depth:" << m_paddingDepth;
} }
@@ -1007,7 +1016,7 @@ int QtStyleCodeFormatter::loadLexerState(const QTextBlock &block) const
return BaseTextDocumentLayout::lexerState(block); return BaseTextDocumentLayout::lexerState(block);
} }
void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth) const void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const
{ {
const State &parentState = state(); const State &parentState = state();
const Token &tk = currentToken(); const Token &tk = currentToken();
@@ -1018,6 +1027,9 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
if (!lastToken) if (!lastToken)
nextTokenStart = column(tokenAt(tokenIndex() + 1).begin()); nextTokenStart = column(tokenAt(tokenIndex() + 1).begin());
if (shouldClearPaddingOnEnter(newState))
*paddingDepth = 0;
switch (newState) { switch (newState) {
case namespace_start: case namespace_start:
if (firstToken) if (firstToken)
@@ -1029,14 +1041,19 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case class_start: case class_start:
if (firstToken) if (firstToken)
*savedIndentDepth = tokenPosition; *savedIndentDepth = tokenPosition;
*indentDepth = tokenPosition + 2*m_indentSize; *indentDepth = tokenPosition;
*paddingDepth = 2*m_indentSize;
break; break;
case template_param: case template_param:
if (!lastToken) if (!lastToken)
*indentDepth = tokenPosition + tk.length(); *paddingDepth = tokenPosition-*indentDepth + tk.length();
else else {
*indentDepth += 2*m_indentSize; if (*paddingDepth == 0)
*paddingDepth = 2*m_indentSize;
else
*paddingDepth += m_indentSize;
}
break; break;
case statement_with_condition: case statement_with_condition:
@@ -1046,17 +1063,18 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case return_statement: case return_statement:
if (firstToken) if (firstToken)
*savedIndentDepth = tokenPosition; *savedIndentDepth = tokenPosition;
*indentDepth = *savedIndentDepth + 2*m_indentSize; *paddingDepth = 2*m_indentSize;
break; break;
case declaration_start: case declaration_start:
if (firstToken) if (firstToken)
*savedIndentDepth = tokenPosition; *savedIndentDepth = tokenPosition;
*indentDepth = *savedIndentDepth;
// continuation indent in function bodies only, to not indent // continuation indent in function bodies only, to not indent
// after the return type in "void\nfoo() {}" // after the return type in "void\nfoo() {}"
for (int i = 0; state(i).type != topmost_intro; ++i) { for (int i = 0; state(i).type != topmost_intro; ++i) {
if (state(i).type == defun_open) { if (state(i).type == defun_open) {
*indentDepth = *savedIndentDepth + 2*m_indentSize; *paddingDepth = 2*m_indentSize;
break; break;
} }
} }
@@ -1065,42 +1083,42 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case arglist_open: case arglist_open:
case condition_paren_open: case condition_paren_open:
if (!lastToken) if (!lastToken)
*indentDepth = tokenPosition + 1; *paddingDepth = tokenPosition-*indentDepth + 1;
else else
*indentDepth += m_indentSize; *paddingDepth += m_indentSize;
break; break;
case ternary_op: case ternary_op:
if (!lastToken) if (!lastToken)
*indentDepth = tokenPosition + tk.length() + 1; *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
else else
*indentDepth += m_indentSize; *paddingDepth += m_indentSize;
break; break;
case stream_op: case stream_op:
*indentDepth = tokenPosition + tk.length() + 1; *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
break; break;
case stream_op_cont: case stream_op_cont:
if (firstToken) if (firstToken)
*savedIndentDepth = *indentDepth = tokenPosition + tk.length() + 1; *savedPaddingDepth = *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1;
break; break;
case member_init_open: case member_init_open:
// undo the continuation indent of the parent // undo the continuation indent of the parent
*savedIndentDepth = parentState.savedIndentDepth; *savedPaddingDepth = 0;
if (firstToken) if (firstToken)
*indentDepth = tokenPosition; *paddingDepth = tokenPosition-*indentDepth;
else else
*indentDepth = *savedIndentDepth + m_indentSize - 2; // they'll get another 2 from member_init *paddingDepth = m_indentSize - 2; // they'll get another 2 from member_init
break; break;
case member_init: case member_init:
*indentDepth = *savedIndentDepth + 2; // savedIndentDepth is the position of ':' *paddingDepth += 2; // savedIndentDepth is the position of ':'
break; break;
case member_init_paren_open: case member_init_paren_open:
*indentDepth = *savedIndentDepth + m_indentSize; *paddingDepth += m_indentSize;
break; break;
case case_cont: case case_cont:
@@ -1111,18 +1129,16 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case enum_open: case enum_open:
case defun_open: { case defun_open: {
// undo the continuation indent of the parent // undo the continuation indent of the parent
*savedIndentDepth = parentState.savedIndentDepth; *savedPaddingDepth = 0;
bool followedByData = (!lastToken && !tokenAt(tokenIndex() + 1).isComment()); bool followedByData = (!lastToken && !tokenAt(tokenIndex() + 1).isComment());
if (firstToken || followedByData) if (followedByData)
*savedIndentDepth = tokenPosition; *savedPaddingDepth = tokenPosition-*indentDepth;
*indentDepth = *savedIndentDepth; *indentDepth += m_indentSize;
if (followedByData) { if (followedByData) {
*indentDepth = column(tokenAt(tokenIndex() + 1).begin()); *paddingDepth = column(tokenAt(tokenIndex() + 1).begin()) - *indentDepth;
} else if (m_indentDeclarationMembers) {
*indentDepth += m_indentSize;
} }
break; break;
} }
@@ -1147,13 +1163,13 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case brace_list_open: case brace_list_open:
if (!lastToken) { if (!lastToken) {
if (parentState.type == initializer) if (parentState.type == initializer)
*savedIndentDepth = tokenPosition; *savedPaddingDepth = tokenPosition-*indentDepth;
*indentDepth = nextTokenStart; *paddingDepth = nextTokenStart-*indentDepth;
} else { } else {
// avoid existing continuation indents // avoid existing continuation indents
if (parentState.type == initializer) if (parentState.type == initializer)
*savedIndentDepth = state(1).savedIndentDepth; *savedPaddingDepth = state(1).savedPaddingDepth;
*indentDepth = *savedIndentDepth + m_indentSize; *paddingDepth = *savedPaddingDepth + m_indentSize;
} }
break; break;
@@ -1164,14 +1180,14 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case condition_open: case condition_open:
// undo the continuation indent of the parent // undo the continuation indent of the parent
*indentDepth = parentState.savedIndentDepth; *paddingDepth = parentState.savedPaddingDepth;
*savedIndentDepth = *indentDepth; *savedPaddingDepth = *paddingDepth;
// fixed extra indent when continuing 'if (', but not for 'else if (' // fixed extra indent when continuing 'if (', but not for 'else if ('
if (tokenPosition <= *indentDepth + m_indentSize) if (tokenPosition <= *indentDepth + m_indentSize)
*indentDepth += 2*m_indentSize; *paddingDepth = 2*m_indentSize;
else else
*indentDepth = tokenPosition + 1; *paddingDepth = tokenPosition-*indentDepth + 1;
break; break;
case substatement: case substatement:
@@ -1209,7 +1225,7 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
} }
} }
void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const
{ {
State topState = state(); State topState = state();
State previousState = state(1); State previousState = state(1);
@@ -1245,33 +1261,38 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
case T_COLON: case T_COLON:
// ### ok for constructor initializer lists - what about ? and bitfields? // ### ok for constructor initializer lists - what about ? and bitfields?
if (topState.type == expression && previousState.type == declaration_start) { if (topState.type == expression && previousState.type == declaration_start) {
*indentDepth = previousState.savedIndentDepth + m_indentSize; *paddingDepth = 4;
} else if (topState.type == ternary_op) { } else if (topState.type == ternary_op) {
*indentDepth -= 2; *paddingDepth -= 2;
} }
break; break;
case T_LBRACE: { case T_LBRACE: {
if (topState.type == case_cont) { if (topState.type == case_cont) {
*indentDepth = topState.savedIndentDepth; *indentDepth = topState.savedIndentDepth;
*paddingDepth = 0;
// function definition - argument list is expression state // function definition - argument list is expression state
} else if (topState.type == expression && previousState.type == declaration_start) { } else if (topState.type == expression && previousState.type == declaration_start) {
*indentDepth = previousState.savedIndentDepth; *indentDepth = previousState.savedIndentDepth;
if (m_indentDeclarationBraces) if (m_indentDeclarationBraces)
*indentDepth += m_indentSize; *indentDepth += m_indentSize;
*paddingDepth = 0;
} else if (topState.type == class_start) { } else if (topState.type == class_start) {
*indentDepth = topState.savedIndentDepth; *indentDepth = topState.savedIndentDepth;
if (m_indentDeclarationBraces) if (m_indentDeclarationBraces)
*indentDepth += m_indentSize; *indentDepth += m_indentSize;
*paddingDepth = 0;
} else if (topState.type == substatement) { } else if (topState.type == substatement) {
*indentDepth = topState.savedIndentDepth; *indentDepth = topState.savedIndentDepth;
if (m_indentSubstatementBraces) if (m_indentSubstatementBraces)
*indentDepth += m_indentSize; *indentDepth += m_indentSize;
*paddingDepth = 0;
} else if (topState.type != defun_open } else if (topState.type != defun_open
&& topState.type != block_open && topState.type != block_open
&& topState.type != substatement_open && topState.type != substatement_open
&& topState.type != brace_list_open && topState.type != brace_list_open
&& !topWasMaybeElse) { && !topWasMaybeElse) {
*indentDepth = topState.savedIndentDepth; *indentDepth = topState.savedIndentDepth;
*paddingDepth = 0;
} }
break; break;
@@ -1279,18 +1300,25 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
case T_RBRACE: { case T_RBRACE: {
if (topState.type == block_open && previousState.type == case_cont) { if (topState.type == block_open && previousState.type == case_cont) {
*indentDepth = previousState.savedIndentDepth; *indentDepth = previousState.savedIndentDepth;
*paddingDepth = previousState.savedPaddingDepth;
break; break;
} }
for (int i = 0; state(i).type != topmost_intro; ++i) { for (int i = 0; state(i).type != topmost_intro; ++i) {
const int type = state(i).type; const int type = state(i).type;
if (type == defun_open if (type == class_open
|| type == substatement_open
|| type == class_open
|| type == brace_list_open
|| type == namespace_open || type == namespace_open
|| type == block_open || type == enum_open
|| type == enum_open) { || type == defun_open) {
*indentDepth = state(i).savedIndentDepth; *indentDepth = state(i).savedIndentDepth;
if (m_indentDeclarationBraces)
*indentDepth += m_indentSize;
*paddingDepth = state(i).savedPaddingDepth;
break;
} else if (type == substatement_open
|| type == brace_list_open
|| type == block_open) {
*indentDepth = state(i).savedIndentDepth;
*paddingDepth = state(i).savedPaddingDepth;
break; break;
} }
} }
@@ -1331,7 +1359,7 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
case T_LESS_LESS: case T_LESS_LESS:
case T_GREATER_GREATER: case T_GREATER_GREATER:
if (topState.type == stream_op || topState.type == stream_op_cont) if (topState.type == stream_op || topState.type == stream_op_cont)
*indentDepth -= 3; // to align << with << *paddingDepth -= 3; // to align << with <<
break; break;
case T_COMMENT: case T_COMMENT:
case T_DOXY_COMMENT: case T_DOXY_COMMENT:
@@ -1348,3 +1376,28 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i
break; break;
} }
} }
bool QtStyleCodeFormatter::shouldClearPaddingOnEnter(int state)
{
switch (state) {
case defun_open:
case class_start:
case class_open:
case enum_start:
case enum_open:
case namespace_start:
case namespace_open:
case template_start:
case if_statement:
case else_clause:
case for_statement:
case switch_statement:
case statement_with_condition:
case do_statement:
case return_statement:
case block_open:
case substatement_open:
return true;
}
return false;
}

View File

@@ -68,16 +68,16 @@ public:
// calculates the state change introduced by changing a single line // calculates the state change introduced by changing a single line
void updateLineStateChange(const QTextBlock &block); void updateLineStateChange(const QTextBlock &block);
int indentFor(const QTextBlock &block); void indentFor(const QTextBlock &block, int *indent, int *padding);
int indentForNewLineAfter(const QTextBlock &block); void indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding);
void setTabSize(int tabSize); void setTabSize(int tabSize);
void invalidateCache(QTextDocument *document); void invalidateCache(QTextDocument *document);
protected: protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const = 0; virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const = 0;
virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const = 0; virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const = 0;
class State; class State;
class BlockData class BlockData
@@ -88,6 +88,7 @@ protected:
QStack<State> m_beginState; QStack<State> m_beginState;
QStack<State> m_endState; QStack<State> m_endState;
int m_indentDepth; int m_indentDepth;
int m_paddingDepth;
int m_blockRevision; int m_blockRevision;
}; };
@@ -174,20 +175,24 @@ protected:
public: public:
State() State()
: savedIndentDepth(0) : savedIndentDepth(0)
, savedPaddingDepth(0)
, type(0) , type(0)
{} {}
State(quint8 ty, quint16 savedDepth) State(quint8 ty, quint16 savedIndentDepth, qint16 savedPaddingDepth)
: savedIndentDepth(savedDepth) : savedIndentDepth(savedIndentDepth)
, savedPaddingDepth(savedPaddingDepth)
, type(ty) , type(ty)
{} {}
quint16 savedIndentDepth; quint16 savedIndentDepth;
quint16 savedPaddingDepth;
quint8 type; quint8 type;
bool operator==(const State &other) const { bool operator==(const State &other) const {
return type == other.type return type == other.type
&& savedIndentDepth == other.savedIndentDepth; && savedIndentDepth == other.savedIndentDepth
&& savedPaddingDepth == other.savedPaddingDepth;
} }
}; };
@@ -201,6 +206,8 @@ protected:
bool isBracelessState(int type) const; bool isBracelessState(int type) const;
void dump() const;
private: private:
void recalculateStateAfter(const QTextBlock &block); void recalculateStateAfter(const QTextBlock &block);
void saveCurrentState(const QTextBlock &block); void saveCurrentState(const QTextBlock &block);
@@ -220,8 +227,6 @@ private:
void leave(bool statementDone = false); void leave(bool statementDone = false);
void correctIndentation(const QTextBlock &block); void correctIndentation(const QTextBlock &block);
void dump();
private: private:
static QStack<State> initialState(); static QStack<State> initialState();
@@ -234,8 +239,8 @@ private:
CPlusPlus::Token m_currentToken; CPlusPlus::Token m_currentToken;
int m_tokenIndex; int m_tokenIndex;
// should store indent level and padding instead
int m_indentDepth; int m_indentDepth;
int m_paddingDepth;
int m_tabSize; int m_tabSize;
@@ -256,8 +261,8 @@ public:
void setIndentDeclarationMembers(bool onOff); void setIndentDeclarationMembers(bool onOff);
protected: protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth) const; virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const;
virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth) const; virtual void adjustIndent(const QList<CPlusPlus::Token> &tokens, int lexerState, int *indentDepth, int *paddingDepth) const;
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const; virtual void saveBlockData(QTextBlock *block, const BlockData &data) const;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const; virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const;
@@ -265,6 +270,8 @@ protected:
virtual void saveLexerState(QTextBlock *block, int state) const; virtual void saveLexerState(QTextBlock *block, int state) const;
virtual int loadLexerState(const QTextBlock &block) const; virtual int loadLexerState(const QTextBlock &block) const;
static bool shouldClearPaddingOnEnter(int state);
private: private:
int m_indentSize; int m_indentSize;
bool m_indentSubstatementBraces; bool m_indentSubstatementBraces;

View File

@@ -52,22 +52,44 @@ private Q_SLOTS:
struct Line { struct Line {
Line(QString l) Line(QString l)
: line(l) : line(l)
, expectedIndent(-1)
, expectedPadding(0)
{ {
for (int i = 0; i < l.size(); ++i) { for (int i = 0; i < l.size(); ++i) {
if (!l.at(i).isSpace()) { if (!l.at(i).isSpace()) {
expectedIndent = i; expectedIndent = i;
return; break;
}
}
if (expectedIndent == -1)
expectedIndent = l.size();
if (expectedIndent < l.size() && l.at(expectedIndent) == '~') {
line[expectedIndent] = ' ';
for (int i = expectedIndent + 1; i < l.size(); ++i) {
if (!l.at(i).isSpace()) {
expectedPadding = i - expectedIndent;
break;
}
} }
} }
expectedIndent = l.size();
} }
Line(QString l, int expect) Line(QString l, int expectIndent, int expectPadding = 0)
: line(l), expectedIndent(expect) : line(l), expectedIndent(expectIndent), expectedPadding(expectPadding)
{} {
for (int i = 0; i < line.size(); ++i) {
if (line.at(i) == '~') {
line[i] = ' ';
break;
}
if (!line.at(i).isSpace())
break;
}
}
QString line; QString line;
int expectedIndent; int expectedIndent;
int expectedPadding;
}; };
QString concatLines(QList<Line> lines) QString concatLines(QList<Line> lines)
@@ -98,10 +120,15 @@ void checkIndent(QList<Line> data, int style = 0)
foreach (const Line &l, data) { foreach (const Line &l, data) {
QTextBlock b = document.findBlockByLineNumber(i); QTextBlock b = document.findBlockByLineNumber(i);
if (l.expectedIndent != -1) { if (l.expectedIndent != -1) {
int actualIndent = formatter.indentFor(b); int indent, padding;
if (actualIndent != l.expectedIndent) { formatter.indentFor(b, &indent, &padding);
if (indent != l.expectedIndent) {
QFAIL(QString("Wrong indent in line %1 with text '%2', expected indent %3, got %4").arg( QFAIL(QString("Wrong indent in line %1 with text '%2', expected indent %3, got %4").arg(
QString::number(i+1), l.line, QString::number(l.expectedIndent), QString::number(actualIndent)).toLatin1().constData()); QString::number(i+1), l.line, QString::number(l.expectedIndent), QString::number(indent)).toLatin1().constData());
}
if (padding != l.expectedPadding) {
QFAIL(QString("Wrong padding in line %1 with text '%2', expected padding %3, got %4").arg(
QString::number(i+1), l.line, QString::number(l.expectedPadding), QString::number(padding)).toLatin1().constData());
} }
} }
formatter.updateLineStateChange(b); formatter.updateLineStateChange(b);
@@ -265,11 +292,11 @@ void tst_CodeFormatter::ifStatementLongCondition()
data << Line("void foo()") data << Line("void foo()")
<< Line("{") << Line("{")
<< Line(" if (foo &&") << Line(" if (foo &&")
<< Line(" bar") << Line(" ~ bar")
<< Line(" || (a + b > 4") << Line(" ~ || (a + b > 4")
<< Line(" && foo(bar)") << Line(" ~ && foo(bar)")
<< Line(" )") << Line(" ~ )")
<< Line(" ) {") << Line(" ~ ) {")
<< Line(" foo;") << Line(" foo;")
<< Line(" }") << Line(" }")
<< Line("}"); << Line("}");
@@ -486,31 +513,31 @@ void tst_CodeFormatter::expressionContinuation()
QList<Line> data; QList<Line> data;
data << Line("void foo() {") data << Line("void foo() {")
<< Line(" return (a <= b &&") << Line(" return (a <= b &&")
<< Line(" c <= d);") << Line(" ~ c <= d);")
<< Line(" return (qMax <= qMin() &&") << Line(" return (qMax <= qMin() &&")
<< Line(" qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));") << Line(" ~ qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));")
<< Line(" return a") << Line(" return a")
<< Line(" == b && c == d;") << Line(" ~ == b && c == d;")
<< Line(" return a ==") << Line(" return a ==")
<< Line(" b && c == d;") << Line(" ~ b && c == d;")
<< Line(" return a == b") << Line(" return a == b")
<< Line(" && c == d;") << Line(" ~ && c == d;")
<< Line(" return a == b &&") << Line(" return a == b &&")
<< Line(" c == d;") << Line(" ~ c == d;")
<< Line(" return a == b && c") << Line(" return a == b && c")
<< Line(" == d;") << Line(" ~ == d;")
<< Line(" return a == b && c ==") << Line(" return a == b && c ==")
<< Line(" d;") << Line(" ~ d;")
<< Line(" return a == b && c == d;") << Line(" return a == b && c == d;")
<< Line(" qDebug() << foo") << Line(" qDebug() << foo")
<< Line(" << bar << moose") << Line(" ~ << bar << moose")
<< Line(" << bar +") << Line(" ~ << bar +")
<< Line(" foo - blah(1)") << Line(" ~ foo - blah(1)")
<< Line(" << '?'") << Line(" ~ << '?'")
<< Line(" << \"\\n\";") << Line(" ~ << \"\\n\";")
<< Line(" i += foo(") << Line(" i += foo(")
<< Line(" bar,") << Line(" ~ bar,")
<< Line(" 2);") << Line(" ~ 2);")
<< Line("}") << Line("}")
; ;
checkIndent(data); checkIndent(data);
@@ -545,15 +572,15 @@ void tst_CodeFormatter::ternary()
data << Line("void foo() {") data << Line("void foo() {")
<< Line(" int i = a ? b : c;") << Line(" int i = a ? b : c;")
<< Line(" foo += a_bigger_condition ?") << Line(" foo += a_bigger_condition ?")
<< Line(" b") << Line(" ~ b")
<< Line(" : c;") << Line(" ~ : c;")
<< Line(" int i = a ?") << Line(" int i = a ?")
<< Line(" b : c;") << Line(" ~ b : c;")
<< Line(" int i = a ? b") << Line(" int i = a ? b")
<< Line(" : c +") << Line(" ~ : c +")
<< Line(" 2;") << Line(" ~ 2;")
<< Line(" int i = (a ? b : c) + (foo") << Line(" int i = (a ? b : c) + (foo")
<< Line(" bar);") << Line(" ~ bar);")
<< Line("}") << Line("}")
; ;
checkIndent(data); checkIndent(data);
@@ -582,21 +609,21 @@ void tst_CodeFormatter::bug2()
QList<Line> data; QList<Line> data;
data << Line("void foo() {") data << Line("void foo() {")
<< Line(" const int sourceY = foo(") << Line(" const int sourceY = foo(")
<< Line(" bar(") << Line(" ~ bar(")
<< Line(" car(a,") << Line(" ~ car(a,")
<< Line(" b),") << Line(" ~ b),")
<< Line(" b),") << Line(" ~ b),")
<< Line(" foo);") << Line(" ~ foo);")
<< Line(" const int sourceY =") << Line(" const int sourceY =")
<< Line(" foo(") << Line(" ~ foo(")
<< Line(" bar(a,") << Line(" ~ bar(a,")
<< Line(" b),") << Line(" ~ b),")
<< Line(" b);") << Line(" ~ b);")
<< Line(" int j;") << Line(" int j;")
<< Line(" const int sourceY =") << Line(" const int sourceY =")
<< Line(" (direction == DirectionEast || direction == DirectionWest) ?") << Line(" ~ (direction == DirectionEast || direction == DirectionWest) ?")
<< Line(" (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2)") << Line(" ~ (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2)")
<< Line(" : (direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top());") << Line(" ~ : (direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top());")
<< Line("}") << Line("}")
; ;
checkIndent(data); checkIndent(data);
@@ -610,15 +637,15 @@ void tst_CodeFormatter::braceList()
<< Line(" b,") << Line(" b,")
<< Line("};") << Line("};")
<< Line("enum Foo { a = 2,") << Line("enum Foo { a = 2,")
<< Line(" a = 3,") << Line(" ~ a = 3,")
<< Line(" b = 4") << Line(" ~ b = 4")
<< Line(" };") << Line("~ };")
<< Line("void foo () {") << Line("void foo () {")
<< Line(" int a[] = { foo, bar, ") << Line(" int a[] = { foo, bar, ")
<< Line(" car };") << Line(" ~ car };")
<< Line(" int a[] = {") << Line(" int a[] = {")
<< Line(" a, b,") << Line(" ~ a, b,")
<< Line(" c") << Line(" ~ c")
<< Line(" };") << Line(" };")
<< Line(" int k;") << Line(" int k;")
; ;
@@ -669,23 +696,23 @@ void tst_CodeFormatter::memberInitializer()
{ {
QList<Line> data; QList<Line> data;
data << Line("void foo()") data << Line("void foo()")
<< Line(" : baR()") << Line("~ : baR()")
<< Line(" , m_member(23)") << Line("~ , m_member(23)")
<< Line("{") << Line("{")
<< Line("}") << Line("}")
<< Line("class Foo {") << Line("class Foo {")
<< Line(" Foo()") << Line(" Foo()")
<< Line(" : baR(),") << Line(" ~ : baR(),")
<< Line(" moodoo(barR + ") << Line(" ~ moodoo(barR + ")
<< Line(" 42),") << Line(" ~ 42),")
<< Line(" xyz()") << Line(" ~ xyz()")
<< Line(" {}") << Line(" {}")
<< Line("};") << Line("};")
<< Line("class Foo {") << Line("class Foo {")
<< Line(" Foo() :") << Line(" Foo() :")
<< Line(" baR(),") << Line(" ~ baR(),")
<< Line(" moo(barR)") << Line(" ~ moo(barR)")
<< Line(" , moo(barR)") << Line(" ~ , moo(barR)")
<< Line(" {}") << Line(" {}")
<< Line("}") << Line("}")
; ;
@@ -700,11 +727,20 @@ void tst_CodeFormatter::templates()
<< Line("private:") << Line("private:")
<< Line("};") << Line("};")
<< Line("template <class T,") << Line("template <class T,")
<< Line(" typename F, int i") << Line("~ typename F, int i")
<< Line(" >") << Line("~ >")
<< Line("class Foo {") << Line("class Foo {")
<< Line("private:") << Line("private:")
<< Line("};") << Line("};")
<< Line("template <template <class F,")
<< Line("~ class D>,")
<< Line("~ typename F>")
<< Line("class Foo { };")
<< Line("template <")
<< Line("~ template <")
<< Line("~ class F, class D>,")
<< Line("~ typename F>")
<< Line("class Foo { };")
; ;
checkIndent(data); checkIndent(data);
} }
@@ -806,17 +842,17 @@ void tst_CodeFormatter::streamOp()
data data
<< Line("void foo () {") << Line("void foo () {")
<< Line(" qDebug() << foo") << Line(" qDebug() << foo")
<< Line(" << bar << moose") << Line(" ~ << bar << moose")
<< Line(" << bar +") << Line(" ~ << bar +")
<< Line(" foo - blah(1)") << Line(" ~ foo - blah(1)")
<< Line(" << '?'") << Line(" ~ << '?'")
<< Line(" << \"\\n\";") << Line(" ~ << \"\\n\";")
<< Line(" qDebug() << foo") << Line(" qDebug() << foo")
<< Line(" << bar << moose", 13) << Line(" << bar << moose", 4, 9)
<< Line(" << bar +") << Line(" ~ << bar +")
<< Line(" foo - blah(1)") << Line(" ~ foo - blah(1)")
<< Line(" << '?'") << Line(" ~ << '?'")
<< Line(" << \"\\n\";") << Line(" ~ << \"\\n\";")
; ;
checkIndent(data); checkIndent(data);
} }
@@ -843,26 +879,26 @@ void tst_CodeFormatter::nestedInitializer()
QList<Line> data; QList<Line> data;
data data
<< Line("SomeStruct v[] = {") << Line("SomeStruct v[] = {")
<< Line(" {2}, {3},") << Line("~ {2}, {3},")
<< Line(" {4}, {5},") << Line("~ {4}, {5},")
<< Line("};") << Line("};")
<< Line("S v[] = {{1}, {2},") << Line("S v[] = {{1}, {2},")
<< Line(" {3}, {4},") << Line("~ {3}, {4},")
<< Line(" };") << Line("~ };")
<< Line("SomeStruct v[] = {") << Line("SomeStruct v[] = {")
<< Line(" {") << Line("~ {")
<< Line(" {2, 3,") << Line("~ {2, 3,")
<< Line(" 4, 5},") << Line("~ 4, 5},")
<< Line(" {1},") << Line("~ {1},")
<< Line(" }") << Line("~ }")
<< Line("};") << Line("};")
<< Line("SomeStruct v[] = {{{2, 3},") << Line("SomeStruct v[] = {{{2, 3},")
<< Line(" {4, 5}") << Line("~ {4, 5}")
<< Line(" },") << Line("~ },")
<< Line(" {{2, 3},") << Line("~ {{2, 3},")
<< Line(" {4, 5},") << Line("~ {4, 5},")
<< Line(" }") << Line("~ }")
<< Line(" };") << Line("~ };")
<< Line("int i;") << Line("int i;")
; ;
checkIndent(data); checkIndent(data);