- enhancement: more accurate auto indent calculation

This commit is contained in:
royqh1979@gmail.com 2021-10-29 12:25:04 +08:00
parent 19e7143efc
commit 5aa91e1bc1
5 changed files with 83 additions and 80 deletions

View File

@ -1371,8 +1371,8 @@ int SynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent)
line = std::min(line, mLines->count()+1); line = std::min(line, mLines->count()+1);
if (line<=1) if (line<=1)
return 0; return 0;
// find the first non-empty preceeding line
int startLine = line-1; int startLine = line-1;
int indentSpaces = 0;
QString s; QString s;
while (startLine>=1) { while (startLine>=1) {
s = mLines->getString(startLine-1); s = mLines->getString(startLine-1);
@ -1381,25 +1381,37 @@ int SynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent)
} }
startLine -- ; startLine -- ;
} }
int indentSpaces = 0;
if (startLine>=1) { if (startLine>=1) {
indentSpaces = leftSpaces(s); indentSpaces = leftSpaces(s);
if (addIndent) { if (addIndent) {
SynRangeState range = mLines->ranges(startLine-1); SynRangeState rangePreceeding = mLines->ranges(startLine-1);
if ((!range.indentStartLines.isEmpty() if (!rangePreceeding.lastMatchingIndent.isNull()) {
&& range.indentStartLines.back() == startLine-1) // find the indent's start line, and use it's indent as the default indent;
int l = startLine-1;
while (l>=1) {
SynRangeState range = mLines->ranges(l-1);
if (range.indents.mid(range.firstIndentThisLine).contains(rangePreceeding.lastMatchingIndent)) {
indentSpaces = leftSpaces(mLines->getString(l-1));
break;
}
l--;
}
}
if ((rangePreceeding.firstIndentThisLine < rangePreceeding.indents.length()) // there are indents added at this (preceeding) line
|| (s.trimmed().endsWith(':')) || (s.trimmed().endsWith(':'))
) { ) {
indentSpaces += mTabWidth; indentSpaces += mTabWidth;
} }
mHighlighter->setState(range); mHighlighter->setState(rangePreceeding);
mHighlighter->setLine(lineText,line-1); mHighlighter->setLine(lineText.trimmed(),line-1);
mHighlighter->nextToEol(); SynRangeState rangeAfterFirstToken = mHighlighter->getRangeState();
SynRangeState newRange = mHighlighter->getRangeState(); if (rangeAfterFirstToken.indents.length() < rangePreceeding.indents.length()) {
while (!newRange.indentStartLines.isEmpty() && newRange.indentStartLines.back()==line-1) {
newRange.indentStartLines.pop_back();
}
if (newRange.indentStartLines.length() < range.indentStartLines.length())
indentSpaces -= mTabWidth; indentSpaces -= mTabWidth;
} else if (rangeAfterFirstToken.getLastIndent() == BraceIndentType
&& rangePreceeding.getLastIndent() == StatementIndentType) {
indentSpaces -= mTabWidth;
}
} }
} }
return std::max(0,indentSpaces); return std::max(0,indentSpaces);

View File

@ -211,17 +211,16 @@ SynHighlighterAttribute::SynHighlighterAttribute(const QString &name):
bool SynRangeState::operator==(const SynRangeState &s2) bool SynRangeState::operator==(const SynRangeState &s2)
{ {
// indents contains the information of brace/parenthesis/brackets embedded levels
return (state == s2.state) return (state == s2.state)
&& (spaceState == s2.spaceState) && (spaceState == s2.spaceState)
&& (braceLevel == s2.braceLevel)
&& (bracketLevel == s2.bracketLevel)
&& (parenthesisLevel == s2.parenthesisLevel)
&& (leftBraces == s2.leftBraces)
&& (leftParenthesis = s2.leftParenthesis)
&& (leftBrackets == s2.leftBrackets)
&& (rightBraces == s2.rightBraces)
&& (rightParenthesis = s2.rightParenthesis)
&& (rightBrackets == s2.rightBrackets)
&& (indents == s2.indents) && (indents == s2.indents)
; ;
} }
QChar SynRangeState::getLastIndent()
{
if (indents.isEmpty())
return QChar();
return indents.back();
}

View File

@ -13,23 +13,24 @@
constexpr QChar BraceIndentType('{'); constexpr QChar BraceIndentType('{');
constexpr QChar ParenthesisIndentType('('); constexpr QChar ParenthesisIndentType('(');
constexpr QChar BracketIndentType('['); constexpr QChar BracketIndentType('[');
constexpr QChar StatementIndentType('K'); constexpr QChar StatementIndentType('S');
struct SynRangeState { struct SynRangeState {
int state; int state; // current syntax parsing state
int spaceState; int spaceState; // the last syntax parsing state before meeting space
int braceLevel; int braceLevel; // current braces embedding level (needed by rainbow color)
int bracketLevel; int bracketLevel; // current brackets embedding level (needed by rainbow color)
int parenthesisLevel; int parenthesisLevel; // current parenthesis embedding level (needed by rainbow color)
int leftBraces; int leftBraces; // unpairing left braces in the current line ( needed by block folding)
int rightBraces; int rightBraces; // unparing right braces in the current line (needed by block folding)
int leftBrackets; QString indents; // indents stack (each char represents an indent) (needed by auto indent)
int rightBrackets; int firstIndentThisLine; /* index of first indent that appended to the indents
int leftParenthesis; * stack at this line ( need by auto indent) */
int rightParenthesis; QChar lastMatchingIndent; /* the last indent matched ( and removed )
QString indents; but not started at this line
QVector<int> indentStartLines; (need by auto indent) */
bool operator==(const SynRangeState& s2); bool operator==(const SynRangeState& s2);
QChar getLastIndent();
}; };
typedef int SynTokenKind; typedef int SynTokenKind;

View File

@ -375,7 +375,7 @@ void SynEditCppHighlighter::braceCloseProc()
} else { } else {
mRange.rightBraces++ ; mRange.rightBraces++ ;
} }
popIndentsByType(BraceIndentType); popIndents(BraceIndentType);
} }
void SynEditCppHighlighter::braceOpenProc() void SynEditCppHighlighter::braceOpenProc()
@ -392,11 +392,15 @@ void SynEditCppHighlighter::braceOpenProc()
if (!mRange.indents.isEmpty() && mRange.indents.back() == StatementIndentType) { if (!mRange.indents.isEmpty() && mRange.indents.back() == StatementIndentType) {
// if last indent is started by 'if' 'for' etc // if last indent is started by 'if' 'for' etc
// just replace it // just replace it
mRange.indents.replace(mRange.indents.length()-1,1,BraceIndentType); popIndents(StatementIndentType);
mRange.indentStartLines.replace(mRange.indents.length()-1,mLineNumber); pushIndents(BraceIndentType);
// int idx = mRange.indents.length()-1;
// if (idx < mRange.firstIndentThisLine) {
// mRange.firstIndentThisLine = idx;
// }
// mRange.indents.replace(idx,1,BraceIndentType);
} else { } else {
mRange.indents.append(BraceIndentType); pushIndents(BraceIndentType);
mRange.indentStartLines.append(mLineNumber);
} }
} }
@ -540,8 +544,7 @@ void SynEditCppHighlighter::identProc()
if (isKeyword(word)) { if (isKeyword(word)) {
mTokenId = TokenKind::Key; mTokenId = TokenKind::Key;
if (StatementKeyWords.contains(word)) { if (StatementKeyWords.contains(word)) {
mRange.indents.append(StatementIndentType); pushIndents(StatementIndentType);
mRange.indentStartLines.append(mLineNumber);
} }
} else { } else {
mTokenId = TokenKind::Identifier; mTokenId = TokenKind::Identifier;
@ -903,12 +906,7 @@ void SynEditCppHighlighter::roundCloseProc()
mTokenId = TokenKind::Symbol; mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundClose; mExtTokenId = ExtTokenKind::RoundClose;
mRange.parenthesisLevel--; mRange.parenthesisLevel--;
if (mRange.leftParenthesis>0) { popIndents(ParenthesisIndentType);
mRange.leftParenthesis--;
} else {
mRange.rightParenthesis++ ;
}
popIndentsByType(ParenthesisIndentType);
} }
void SynEditCppHighlighter::roundOpenProc() void SynEditCppHighlighter::roundOpenProc()
@ -917,9 +915,7 @@ void SynEditCppHighlighter::roundOpenProc()
mTokenId = TokenKind::Symbol; mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::RoundOpen; mExtTokenId = ExtTokenKind::RoundOpen;
mRange.parenthesisLevel++; mRange.parenthesisLevel++;
mRange.leftParenthesis++; pushIndents(ParenthesisIndentType);
mRange.indents.append(ParenthesisIndentType);
mRange.indentStartLines.append(mLineNumber);
} }
void SynEditCppHighlighter::semiColonProc() void SynEditCppHighlighter::semiColonProc()
@ -930,8 +926,7 @@ void SynEditCppHighlighter::semiColonProc()
if (mRange.state == RangeState::rsAsm) if (mRange.state == RangeState::rsAsm)
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsUnknown;
if (mRange.indents.back() == StatementIndentType) { if (mRange.indents.back() == StatementIndentType) {
mRange.indents.remove(mRange.indents.length()-1,1); popIndents(StatementIndentType);
mRange.indentStartLines.pop_back();
} }
} }
@ -986,12 +981,7 @@ void SynEditCppHighlighter::squareCloseProc()
mTokenId = TokenKind::Symbol; mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareClose; mExtTokenId = ExtTokenKind::SquareClose;
mRange.bracketLevel--; mRange.bracketLevel--;
if (mRange.leftBrackets>0) { popIndents(BracketIndentType);
mRange.leftBrackets--;
} else {
mRange.rightBrackets++ ;
}
popIndentsByType(BracketIndentType);
} }
void SynEditCppHighlighter::squareOpenProc() void SynEditCppHighlighter::squareOpenProc()
@ -1000,9 +990,7 @@ void SynEditCppHighlighter::squareOpenProc()
mTokenId = TokenKind::Symbol; mTokenId = TokenKind::Symbol;
mExtTokenId = ExtTokenKind::SquareOpen; mExtTokenId = ExtTokenKind::SquareOpen;
mRange.bracketLevel++; mRange.bracketLevel++;
mRange.leftBrackets++; pushIndents(BracketIndentType);
mRange.indents.append(BracketIndentType);
mRange.indentStartLines.append(mLineNumber);
} }
void SynEditCppHighlighter::starProc() void SynEditCppHighlighter::starProc()
@ -1366,17 +1354,26 @@ void SynEditCppHighlighter::processChar()
} }
} }
void SynEditCppHighlighter::popIndentsByType(QChar indentType) void SynEditCppHighlighter::popIndents(QChar indentType)
{ {
while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) { while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) {
mRange.indents.remove(mRange.indents.length()-1,1); mRange.indents.remove(mRange.indents.length()-1,1);
mRange.indentStartLines.pop_back();
} }
if (!mRange.indents.isEmpty()) { if (!mRange.indents.isEmpty()) {
mRange.indents.remove(mRange.indents.length()-1,1); int idx = mRange.indents.length()-1;
mRange.indentStartLines.pop_back(); if (idx < mRange.firstIndentThisLine) {
mRange.lastMatchingIndent = mRange.indents[idx];
}
mRange.indents.remove(idx,1);
}
} }
void SynEditCppHighlighter::pushIndents(QChar indentType)
{
int idx = mRange.indents.length();
if (idx<mRange.firstIndentThisLine)
mRange.firstIndentThisLine = idx;
mRange.indents.append(indentType);
} }
bool SynEditCppHighlighter::getTokenFinished() const bool SynEditCppHighlighter::getTokenFinished() const
@ -1532,11 +1529,9 @@ void SynEditCppHighlighter::setLine(const QString &newLine, int lineNumber)
mLineNumber = lineNumber; mLineNumber = lineNumber;
mRun = 0; mRun = 0;
mRange.leftBraces = 0; mRange.leftBraces = 0;
mRange.leftBrackets = 0;
mRange.leftParenthesis = 0;
mRange.rightBraces = 0; mRange.rightBraces = 0;
mRange.rightBrackets = 0; mRange.firstIndentThisLine = mRange.indents.length();
mRange.rightParenthesis = 0; mRange.lastMatchingIndent = QChar();
next(); next();
} }
@ -1602,11 +1597,9 @@ void SynEditCppHighlighter::setState(const SynRangeState& rangeState)
mRange = rangeState; mRange = rangeState;
// current line's left / right parenthesis count should be reset before parsing each line // current line's left / right parenthesis count should be reset before parsing each line
mRange.leftBraces = 0; mRange.leftBraces = 0;
mRange.leftBrackets = 0;
mRange.leftParenthesis = 0;
mRange.rightBraces = 0; mRange.rightBraces = 0;
mRange.rightBrackets = 0; mRange.firstIndentThisLine = mRange.indents.length();
mRange.rightParenthesis = 0; mRange.lastMatchingIndent = QChar();
} }
void SynEditCppHighlighter::resetState() void SynEditCppHighlighter::resetState()
@ -1617,13 +1610,10 @@ void SynEditCppHighlighter::resetState()
mRange.bracketLevel = 0; mRange.bracketLevel = 0;
mRange.parenthesisLevel = 0; mRange.parenthesisLevel = 0;
mRange.leftBraces = 0; mRange.leftBraces = 0;
mRange.leftBrackets = 0;
mRange.leftParenthesis = 0;
mRange.rightBraces = 0; mRange.rightBraces = 0;
mRange.rightBrackets = 0;
mRange.rightParenthesis = 0;
mRange.indents = ""; mRange.indents = "";
mRange.indentStartLines.clear(); mRange.firstIndentThisLine = 0;
mRange.lastMatchingIndent = QChar();
mAsmStart = false; mAsmStart = false;
} }

View File

@ -125,7 +125,8 @@ private:
void unknownProc(); void unknownProc();
void xorSymbolProc(); void xorSymbolProc();
void processChar(); void processChar();
void popIndentsByType(QChar indentType); void popIndents(QChar indentType);
void pushIndents(QChar indentType);
private: private:
bool mAsmStart; bool mAsmStart;