- 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);
if (line<=1)
return 0;
// find the first non-empty preceeding line
int startLine = line-1;
int indentSpaces = 0;
QString s;
while (startLine>=1) {
s = mLines->getString(startLine-1);
@ -1381,25 +1381,37 @@ int SynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent)
}
startLine -- ;
}
int indentSpaces = 0;
if (startLine>=1) {
indentSpaces = leftSpaces(s);
if (addIndent) {
SynRangeState range = mLines->ranges(startLine-1);
if ((!range.indentStartLines.isEmpty()
&& range.indentStartLines.back() == startLine-1)
SynRangeState rangePreceeding = mLines->ranges(startLine-1);
if (!rangePreceeding.lastMatchingIndent.isNull()) {
// 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(':'))
) {
indentSpaces += mTabWidth;
}
mHighlighter->setState(range);
mHighlighter->setLine(lineText,line-1);
mHighlighter->nextToEol();
SynRangeState newRange = mHighlighter->getRangeState();
while (!newRange.indentStartLines.isEmpty() && newRange.indentStartLines.back()==line-1) {
newRange.indentStartLines.pop_back();
}
if (newRange.indentStartLines.length() < range.indentStartLines.length())
mHighlighter->setState(rangePreceeding);
mHighlighter->setLine(lineText.trimmed(),line-1);
SynRangeState rangeAfterFirstToken = mHighlighter->getRangeState();
if (rangeAfterFirstToken.indents.length() < rangePreceeding.indents.length()) {
indentSpaces -= mTabWidth;
} else if (rangeAfterFirstToken.getLastIndent() == BraceIndentType
&& rangePreceeding.getLastIndent() == StatementIndentType) {
indentSpaces -= mTabWidth;
}
}
}
return std::max(0,indentSpaces);

View File

@ -211,17 +211,16 @@ SynHighlighterAttribute::SynHighlighterAttribute(const QString &name):
bool SynRangeState::operator==(const SynRangeState &s2)
{
// indents contains the information of brace/parenthesis/brackets embedded levels
return (state == s2.state)
&& (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)
;
}
QChar SynRangeState::getLastIndent()
{
if (indents.isEmpty())
return QChar();
return indents.back();
}

View File

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

View File

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

View File

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