From 5aa91e1bc17b6a9c581b462307eeedfc2e7d1410 Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Fri, 29 Oct 2021 12:25:04 +0800 Subject: [PATCH] - enhancement: more accurate auto indent calculation --- RedPandaIDE/qsynedit/SynEdit.cpp | 36 +++++++---- RedPandaIDE/qsynedit/highlighter/base.cpp | 17 +++-- RedPandaIDE/qsynedit/highlighter/base.h | 29 +++++---- RedPandaIDE/qsynedit/highlighter/cpp.cpp | 78 ++++++++++------------- RedPandaIDE/qsynedit/highlighter/cpp.h | 3 +- 5 files changed, 83 insertions(+), 80 deletions(-) diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index f9d469fa..5c2a3623 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -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(); + 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; } - if (newRange.indentStartLines.length() < range.indentStartLines.length()) - indentSpaces-=mTabWidth; } } return std::max(0,indentSpaces); diff --git a/RedPandaIDE/qsynedit/highlighter/base.cpp b/RedPandaIDE/qsynedit/highlighter/base.cpp index ca92d70b..a57b370c 100644 --- a/RedPandaIDE/qsynedit/highlighter/base.cpp +++ b/RedPandaIDE/qsynedit/highlighter/base.cpp @@ -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(); +} diff --git a/RedPandaIDE/qsynedit/highlighter/base.h b/RedPandaIDE/qsynedit/highlighter/base.h index b55351ab..b778281f 100644 --- a/RedPandaIDE/qsynedit/highlighter/base.h +++ b/RedPandaIDE/qsynedit/highlighter/base.h @@ -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 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; diff --git a/RedPandaIDE/qsynedit/highlighter/cpp.cpp b/RedPandaIDE/qsynedit/highlighter/cpp.cpp index 3a6adcf6..1e5cd80f 100644 --- a/RedPandaIDE/qsynedit/highlighter/cpp.cpp +++ b/RedPandaIDE/qsynedit/highlighter/cpp.cpp @@ -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