From dd5df6912c7d767731fa0f3eb44163e2e8ebc4ee Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Tue, 7 Feb 2023 19:05:39 +0800 Subject: [PATCH] - enhancement: Improve auto indent. --- NEWS.md | 1 + RedPandaIDE/editor.cpp | 1 + libs/qsynedit/qsynedit/qsynedit.cpp | 160 ++---------------- libs/qsynedit/qsynedit/qsynedit.h | 1 - libs/qsynedit/qsynedit/syntaxer/cpp.cpp | 72 ++++---- libs/qsynedit/qsynedit/syntaxer/cpp.h | 4 +- .../qsynedit/syntaxer/customhighlighterv1.cpp | 4 +- libs/qsynedit/qsynedit/syntaxer/glsl.cpp | 73 +++----- libs/qsynedit/qsynedit/syntaxer/glsl.h | 4 +- libs/qsynedit/qsynedit/syntaxer/syntaxer.cpp | 46 +++-- libs/qsynedit/qsynedit/syntaxer/syntaxer.h | 36 ++-- 11 files changed, 144 insertions(+), 258 deletions(-) diff --git a/NEWS.md b/NEWS.md index 25cd99f0..a509cfea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ Red Panda C++ Version 2.11 - fix: Parser can't correctly differentiate function and var initialization. - fix: Respect encoding "Project default" when search/find occurrencies/open project units. - enhancement: Show progress dialog when search/find occurrencies in large projects. + - enhancement: Improve auto indent. Red Panda C++ Version 2.10 diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 9c5af808..b407c031 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -61,6 +61,7 @@ Editor::Editor(QWidget *parent): { } + Editor::Editor(QWidget *parent, const QString& filename, const QByteArray& encoding, Project* pProject, bool isNew, diff --git a/libs/qsynedit/qsynedit/qsynedit.cpp b/libs/qsynedit/qsynedit/qsynedit.cpp index c0136b1c..b93e30cd 100644 --- a/libs/qsynedit/qsynedit/qsynedit.cpp +++ b/libs/qsynedit/qsynedit/qsynedit.cpp @@ -1293,36 +1293,6 @@ void QSynEdit::clearUndo() mRedoList->clear(); } -int QSynEdit::findIndentsStartLine(int line, QVector indents) -{ - line--; - if (line<0 || line>=mDocument->count()) - return -1; - while (line>=1) { - SyntaxState range = mDocument->getSyntaxState(line); - QVector newIndents = range.indents.mid(range.firstIndentThisLine); - int i = 0; - int len = indents.length(); - while (i=0) { - newIndents.remove(idx,newIndents.size()); - } else { - break; - } - i++; - } - if (i>=len) { - return line+1; - } else { - indents = range.matchingIndents + indents.mid(i); - } - line--; - } - return -1; -} - BufferCoord QSynEdit::getPreviousLeftBrace(int x, int y) { QChar Test; @@ -1605,9 +1575,6 @@ int QSynEdit::findCommentStartLine(int searchStartLine) commentStartLine++; break; } - if (!range.matchingIndents.isEmpty() - || range.firstIndentThisLine=1) { //calculate the indents of last statement; indentSpaces = leftSpaces(startLineText); + if (mSyntaxer->language() != ProgrammingLanguage::CPP) + return indentSpaces; SyntaxState rangePreceeding = mDocument->getSyntaxState(startLine-1); mSyntaxer->setState(rangePreceeding); if (addIndent) { @@ -1665,135 +1634,42 @@ int QSynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent firstToken = mSyntaxer->getToken(); attr = mSyntaxer->getTokenAttribute(); } - bool indentAdded = false; - int additionIndent = 0; - QVector matchingIndents; - int l; - if (attr->tokenType() == TokenType::Operator - && (firstToken == '}')) { - // current line starts with '}', we should consider it to calc indents - matchingIndents = rangeAfterFirstToken.matchingIndents; - indentAdded = true; - l = startLine; - } else if (attr->tokenType() == TokenType::Operator - && (firstToken == '{') - && (rangePreceeding.getLastIndent()==IndentForStatement)) { - // current line starts with '{' and last statement not finished, we should consider it to calc indents - matchingIndents = rangeAfterFirstToken.matchingIndents; - indentAdded = true; - l = startLine; - } else if (mSyntaxer->language() == ProgrammingLanguage::CPP - && trimmedLineText.startsWith('#') + qDebug()<preprocessorAttribute()) { - indentAdded = true; indentSpaces=0; - l=0; - } else if (mSyntaxer->language() == ProgrammingLanguage::CPP - && mSyntaxer->isLastLineCommentNotFinished(rangePreceeding.state) + } else if (mSyntaxer->isLastLineCommentNotFinished(rangePreceeding.state) ) { // last line is a not finished comment, if (trimmedLineText.startsWith("*")) { // this line start with "* " // it means this line is a docstring, should indents according to // the line the comment beginning , and add 1 additional space - additionIndent = 1; int commentStartLine = findCommentStartLine(startLine-1); SyntaxState range; - indentSpaces = leftSpaces(mDocument->getLine(commentStartLine-1)); + indentSpaces = leftSpaces(mDocument->getLine(commentStartLine-1))+1; range = mDocument->getSyntaxState(commentStartLine-1); - matchingIndents = range.matchingIndents; - indentAdded = true; - l = commentStartLine; } else { //indents according to the beginning of the comment and 2 additional space - additionIndent = 0; int commentStartLine = findCommentStartLine(startLine-1); SyntaxState range; indentSpaces = leftSpaces(mDocument->getLine(commentStartLine-1))+2; range = mDocument->getSyntaxState(commentStartLine-1); - matchingIndents = range.matchingIndents; - indentAdded = true; - l = startLine; } - } else if ( mSyntaxer->isLastLineCommentNotFinished(statePrePre) - && rangePreceeding.matchingIndents.isEmpty() - && rangePreceeding.firstIndentThisLine>=rangePreceeding.indents.length() - && !mSyntaxer->isLastLineCommentNotFinished(rangePreceeding.state)) { - // the preceeding line is the end of comment - // we should use the indents of the start line of the comment - int commentStartLine = findCommentStartLine(startLine-2); - SyntaxState range; - indentSpaces = leftSpaces(mDocument->getLine(commentStartLine-1)); - range = mDocument->getSyntaxState(commentStartLine-1); - matchingIndents = range.matchingIndents; - indentAdded = true; - l = commentStartLine; + } else if (rangeAfterFirstToken.lastUnindent.type!=IndentType::None + && firstToken=="}") { + IndentInfo matchingIndents = rangeAfterFirstToken.lastUnindent; + indentSpaces = leftSpaces(mDocument->getLine(matchingIndents.line)); + } else if (firstToken=="{") { + IndentInfo matchingIndents = rangeAfterFirstToken.getLastIndent(); + indentSpaces = leftSpaces(mDocument->getLine(matchingIndents.line)); + } else if (rangePreceeding.getLastIndentType()!=IndentType::None) { + IndentInfo matchingIndents = rangePreceeding.getLastIndent(); + indentSpaces = leftSpaces(mDocument->getLine(matchingIndents.line))+tabWidth(); } else { - // we just use infos till preceeding line's end to calc indents - matchingIndents = rangePreceeding.matchingIndents; - l = startLine-1; + indentSpaces = 0; } - - if (!matchingIndents.isEmpty() - ) { - // find the indent's start line, and use it's indent as the default indent; - while (l>=1) { - SyntaxState range = mDocument->getSyntaxState(l-1); - QVector newIndents = range.indents.mid(range.firstIndentThisLine); - int i = 0; - int len = matchingIndents.length(); - while (i=0) { - newIndents.remove(idx,newIndents.length()-idx); - } else { - break; - } - i++; - } - if (i>=len) { - // we found the where the indent started - if (len>0 && !range.matchingIndents.isEmpty() - && - ( matchingIndents.back()== IndentForBrace - || matchingIndents.back() == IndentForStatement - ) ) { - // but it's not a complete statement - matchingIndents = range.matchingIndents; - } else { - indentSpaces = leftSpaces(mDocument->getLine(l-1)); - if (newIndents.length()>0) - indentSpaces+=tabWidth(); - break; - } - } else { - matchingIndents = range.matchingIndents + matchingIndents.mid(i); - } - l--; - } - } - if (!indentAdded) { - if (rangePreceeding.firstIndentThisLine < rangePreceeding.indents.length()) { - indentSpaces += tabWidth(); - indentAdded = true; - } - } - - if (!indentAdded && !startLineText.isEmpty()) { - BufferCoord coord; - QString token; - PTokenAttribute attr; - coord.line = startLine; - coord.ch = document()->getLine(startLine-1).length(); - if (getTokenAttriAtRowCol(coord,token,attr) - && attr->tokenType() == QSynedit::TokenType::Operator - && token == ":") { - indentSpaces += tabWidth(); - indentAdded = true; - } - } - indentSpaces += additionIndent; } } return std::max(0,indentSpaces); diff --git a/libs/qsynedit/qsynedit/qsynedit.h b/libs/qsynedit/qsynedit/qsynedit.h index 7fb7581b..499fcf1c 100644 --- a/libs/qsynedit/qsynedit/qsynedit.h +++ b/libs/qsynedit/qsynedit/qsynedit.h @@ -571,7 +571,6 @@ private: void processGutterClick(QMouseEvent* event); void clearUndo(); - int findIndentsStartLine(int line, QVector indents); BufferCoord getPreviousLeftBrace(int x,int y); bool canDoBlockIndent(); diff --git a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp index ae0bc929..da874f29 100644 --- a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp +++ b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp @@ -386,7 +386,7 @@ void CppSyntaxer::braceCloseProc() } else { mRange.blockEnded++ ; } - popIndents(IndentForBrace); + popIndents(IndentType::Block); } void CppSyntaxer::braceOpenProc() @@ -400,20 +400,17 @@ void CppSyntaxer::braceOpenProc() mRange.braceLevel += 1; mRange.blockLevel += 1; mRange.blockStarted++; - if (mRange.getLastIndent() == IndentForStatement) { + if (mRange.getLastIndentType() == IndentType::Statement) { // if last indent is started by 'if' 'for' etc // just replace it - while (mRange.getLastIndent() == IndentForStatement) - popIndents(IndentForStatement); - pushIndents(IndentForBrace); -// int idx = mRange.indents.length()-1; -// if (idx < mRange.firstIndentThisLine) { -// mRange.firstIndentThisLine = idx; -// } -// mRange.indents.replace(idx,1,BraceIndentType); - } else { - pushIndents(IndentForBrace); - } + int lastLine=-1; + while (mRange.getLastIndentType() == IndentType::Statement) { + popIndents(IndentType::Statement); + lastLine = mRange.lastUnindent.line; + } + pushIndents(IndentType::Block, lastLine); + } else + pushIndents(IndentType::Block); } void CppSyntaxer::colonProc() @@ -575,7 +572,7 @@ void CppSyntaxer::identProc() if (isKeyword(word)) { mTokenId = TokenId::Key; if (CppStatementKeyWords.contains(word)) { - pushIndents(IndentForStatement); + pushIndents(IndentType::Statement); } } else { mTokenId = TokenId::Identifier; @@ -908,7 +905,7 @@ void CppSyntaxer::roundCloseProc() mRange.parenthesisLevel--; if (mRange.parenthesisLevel<0) mRange.parenthesisLevel=0; - popIndents(IndentForParenthesis); + popIndents(IndentType::Parenthesis); } void CppSyntaxer::roundOpenProc() @@ -916,7 +913,7 @@ void CppSyntaxer::roundOpenProc() mRun += 1; mTokenId = TokenId::Symbol; mRange.parenthesisLevel++; - pushIndents(IndentForParenthesis); + pushIndents(IndentType::Parenthesis); } void CppSyntaxer::semiColonProc() @@ -925,8 +922,8 @@ void CppSyntaxer::semiColonProc() mTokenId = TokenId::Symbol; if (mRange.state == RangeState::rsAsm) mRange.state = RangeState::rsUnknown; - while (mRange.getLastIndent() == IndentForStatement) { - popIndents(IndentForStatement); + while (mRange.getLastIndentType() == IndentType::Statement) { + popIndents(IndentType::Statement); } } @@ -997,7 +994,7 @@ void CppSyntaxer::squareCloseProc() mRange.bracketLevel--; if (mRange.bracketLevel<0) mRange.bracketLevel=0; - popIndents(IndentForBracket); + popIndents(IndentType::Bracket); } void CppSyntaxer::squareOpenProc() @@ -1005,7 +1002,7 @@ void CppSyntaxer::squareOpenProc() mRun+=1; mTokenId = TokenId::Symbol; mRange.bracketLevel++; - pushIndents(IndentForBracket); + pushIndents(IndentType::Bracket); } void CppSyntaxer::starProc() @@ -1365,26 +1362,28 @@ void CppSyntaxer::processChar() } } -void CppSyntaxer::popIndents(int indentType) +void CppSyntaxer::popIndents(IndentType indentType) { - while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) { +// qDebug()<<"----"; +// for (IndentInfo info:mRange.indents) +// qDebug()<<(int)info.type< &CppSyntaxer::customTypeKeywords() const @@ -1572,11 +1571,6 @@ void CppSyntaxer::setLine(const QString &newLine, int lineNumber) mLineSize = mLine.size(); mLineNumber = lineNumber; mRun = 0; - mRange.blockStarted = 0; - mRange.blockEnded = 0; - mRange.blockEndedLastLine = 0; - mRange.firstIndentThisLine = mRange.indents.length(); - mRange.matchingIndents.clear(); next(); } @@ -1592,9 +1586,8 @@ void CppSyntaxer::setState(const SyntaxState& rangeState) mRange.blockStarted = 0; mRange.blockEnded = 0; mRange.blockEndedLastLine = 0; - mRange.firstIndentThisLine = mRange.indents.length(); + mRange.lastUnindent=IndentInfo{IndentType::None,0}; mRange.hasTrailingSpaces = false; - mRange.matchingIndents.clear(); } void CppSyntaxer::resetState() @@ -1608,8 +1601,7 @@ void CppSyntaxer::resetState() mRange.blockEnded = 0; mRange.blockEndedLastLine = 0; mRange.indents.clear(); - mRange.firstIndentThisLine = 0; - mRange.matchingIndents.clear(); + mRange.lastUnindent=IndentInfo{IndentType::None,0}; mRange.hasTrailingSpaces = false; mAsmStart = false; } diff --git a/libs/qsynedit/qsynedit/syntaxer/cpp.h b/libs/qsynedit/qsynedit/syntaxer/cpp.h index 71ac082b..6ce7f9b9 100644 --- a/libs/qsynedit/qsynedit/syntaxer/cpp.h +++ b/libs/qsynedit/qsynedit/syntaxer/cpp.h @@ -134,8 +134,8 @@ private: void unknownProc(); void xorSymbolProc(); void processChar(); - void popIndents(int indentType); - void pushIndents(int indentType); + void popIndents(IndentType indentType); + void pushIndents(IndentType indentType, int line=-1); private: bool mAsmStart; diff --git a/libs/qsynedit/qsynedit/syntaxer/customhighlighterv1.cpp b/libs/qsynedit/qsynedit/syntaxer/customhighlighterv1.cpp index eddc3eb1..15091283 100644 --- a/libs/qsynedit/qsynedit/syntaxer/customhighlighterv1.cpp +++ b/libs/qsynedit/qsynedit/syntaxer/customhighlighterv1.cpp @@ -13,8 +13,8 @@ void CustomHighlighterV1::resetState() mRange.bracketLevel = 0; mRange.parenthesisLevel = 0; mRange.indents.clear(); - mRange.firstIndentThisLine = 0; - mRange.matchingIndents.clear(); + mRange.lastUnindent=IndentInfo{IndentType::None,0}; + mRange.hasTrailingSpaces=false; } QString CustomHighlighterV1::languageName() diff --git a/libs/qsynedit/qsynedit/syntaxer/glsl.cpp b/libs/qsynedit/qsynedit/syntaxer/glsl.cpp index e21f01fc..d150a87e 100644 --- a/libs/qsynedit/qsynedit/syntaxer/glsl.cpp +++ b/libs/qsynedit/qsynedit/syntaxer/glsl.cpp @@ -308,7 +308,7 @@ void GLSLSyntaxer::braceCloseProc() } else { mRange.blockEnded++ ; } - popIndents(IndentForBrace); + popIndents(IndentType::Block); } void GLSLSyntaxer::braceOpenProc() @@ -318,20 +318,17 @@ void GLSLSyntaxer::braceOpenProc() mRange.braceLevel += 1; mRange.blockLevel += 1; mRange.blockStarted += 1; - if (mRange.getLastIndent() == IndentForStatement) { + if (mRange.getLastIndentType() == IndentType::Statement) { // if last indent is started by 'if' 'for' etc // just replace it - while (mRange.getLastIndent() == IndentForStatement) - popIndents(IndentForStatement); - pushIndents(IndentForBrace); -// int idx = mRange.indents.length()-1; -// if (idx < mRange.firstIndentThisLine) { -// mRange.firstIndentThisLine = idx; -// } -// mRange.indents.replace(idx,1,BraceIndentType); - } else { - pushIndents(IndentForBrace); - } + int lastLine=-1; + while (mRange.getLastIndentType() == IndentType::Statement) { + popIndents(IndentType::Statement); + lastLine = mRange.lastUnindent.line; + } + pushIndents(IndentType::Block, lastLine); + } else + pushIndents(IndentType::Block); } void GLSLSyntaxer::colonProc() @@ -465,7 +462,7 @@ void GLSLSyntaxer::identProc() if (isKeyword(word)) { mTokenId = TokenId::Key; if (GLSLStatementKeyWords.contains(word)) { - pushIndents(IndentForStatement); + pushIndents(IndentType::Statement); } } else { mTokenId = TokenId::Identifier; @@ -803,7 +800,7 @@ void GLSLSyntaxer::roundCloseProc() mRange.parenthesisLevel--; if (mRange.parenthesisLevel<0) mRange.parenthesisLevel=0; - popIndents(IndentForParenthesis); + popIndents(IndentType::Parenthesis); } void GLSLSyntaxer::roundOpenProc() @@ -811,15 +808,15 @@ void GLSLSyntaxer::roundOpenProc() mRun += 1; mTokenId = TokenId::Symbol; mRange.parenthesisLevel++; - pushIndents(IndentForParenthesis); + pushIndents(IndentType::Parenthesis); } void GLSLSyntaxer::semiColonProc() { mRun += 1; mTokenId = TokenId::Symbol; - while (mRange.getLastIndent() == IndentForStatement) { - popIndents(IndentForStatement); + while (mRange.getLastIndentType() == IndentType::Statement) { + popIndents(IndentType::Statement); } } @@ -870,7 +867,7 @@ void GLSLSyntaxer::squareCloseProc() mRange.bracketLevel--; if (mRange.bracketLevel<0) mRange.bracketLevel=0; - popIndents(IndentForBracket); + popIndents(IndentType::Bracket); } void GLSLSyntaxer::squareOpenProc() @@ -878,7 +875,7 @@ void GLSLSyntaxer::squareOpenProc() mRun+=1; mTokenId = TokenId::Symbol; mRange.bracketLevel++; - pushIndents(IndentForBracket); + pushIndents(IndentType::Bracket); } void GLSLSyntaxer::starProc() @@ -1227,26 +1224,24 @@ void GLSLSyntaxer::processChar() } } -void GLSLSyntaxer::popIndents(int indentType) +void GLSLSyntaxer::popIndents(IndentType indentType) { - while (!mRange.indents.isEmpty() && mRange.indents.back()!=indentType) { + while (!mRange.indents.isEmpty() && mRange.indents.back().type!=indentType) { mRange.indents.pop_back(); } if (!mRange.indents.isEmpty()) { - int idx = mRange.indents.length()-1; - if (idx < mRange.firstIndentThisLine) { - mRange.matchingIndents.append(mRange.indents[idx]); - } + mRange.lastUnindent=mRange.indents.back(); mRange.indents.pop_back(); + } else { + mRange.lastUnindent=IndentInfo{indentType,0}; } } -void GLSLSyntaxer::pushIndents(int indentType) +void GLSLSyntaxer::pushIndents(IndentType indentType, int line) { - int idx = mRange.indents.length(); - if (idx indents; // indents stack (needed by auto indent) - int firstIndentThisLine; /* index of first indent that appended to the indents - * stack at this line ( need by auto indent) */ - QVector matchingIndents; /* the indent matched ( and removed ) - but not started at this line - (need by auto indent) */ + QVector indents; + IndentInfo lastUnindent; +// QVector indents; // indents stack (needed by auto indent) +// int firstIndentThisLine; /* index of first indent that appended to the indents +// * stack at this line ( need by auto indent) */ +// QVector matchingIndents; /* the indent matched ( and removed ) +// but not started at this line +// (need by auto indent) */ bool hasTrailingSpaces; bool operator==(const SyntaxState& s2); - int getLastIndent(); + IndentInfo getLastIndent(); + IndentType getLastIndentType(); SyntaxState(); };