From f7514e424ecb6faa69608a4848d10601323ee272 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Tue, 5 Mar 2024 21:20:47 +0800 Subject: [PATCH] refactor: Check string/rawstring/character status while completing symbols in c/c++ file --- RedPandaIDE/editor.cpp | 148 +++++------------------- RedPandaIDE/editor.h | 3 +- libs/qsynedit/qsynedit/qsynedit.cpp | 12 ++ libs/qsynedit/qsynedit/qsynedit.h | 1 + libs/qsynedit/qsynedit/syntaxer/cpp.cpp | 108 ++++++++++++----- libs/qsynedit/qsynedit/syntaxer/cpp.h | 13 ++- 6 files changed, 129 insertions(+), 156 deletions(-) diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 6158fd58..a6d71b9e 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -732,15 +732,8 @@ void Editor::keyPressEvent(QKeyEvent *event) clearUserCodeInTabStops(); } else { QString s = lineText().mid(0,caretX()-1).trimmed(); - if (caretY()==1) { - syntaxer()->resetState(); - } else { - syntaxer()->setState(document()->getSyntaxState(caretY()-2)); - } - syntaxer()->setLine(s,caretY()); - syntaxer()->nextToEol(); - int state = syntaxer()->getState().state; - if (syntaxer()->isCommentNotFinished(state)) { + QSynedit::SyntaxState state = calcSyntaxStateAtLine(caretY()-1, s); + if (syntaxer()->isCommentNotFinished(state.state)) { if (s=="/**") { //javadoc style docstring s = lineText().mid(caretX()-1).trimmed(); if (s=="*/") { @@ -2961,7 +2954,7 @@ bool Editor::handleDoubleQuoteCompletion() QuoteStatus status = getQuoteStatus(); QChar ch = getCurrentChar(); if (ch == '"') { - if ((status == QuoteStatus::DoubleQuote || status == QuoteStatus::RawString) + if ((status == QuoteStatus::DoubleQuote || status == QuoteStatus::RawStringEnd) && !selAvail()) { setCaretXY( QSynedit::BufferCoord{caretX() + 1, caretY()}); // skip over return true; @@ -3100,118 +3093,31 @@ ParserLanguage Editor::calcParserLanguage() Editor::QuoteStatus Editor::getQuoteStatus() { QuoteStatus Result = QuoteStatus::NotQuote; - if ((caretY()>1) && syntaxer()->isStringNotFinished(document()->getSyntaxState(caretY() - 2).state)) - Result = QuoteStatus::DoubleQuote; - - QString Line = document()->getLine(caretY()-1); - int posX = caretX()-1; - if (posX >= Line.length()) { - posX = Line.length()-1; - } - for (int i=0; ilanguage()==QSynedit::ProgrammingLanguage::CPP) { + QString s = lineText().mid(0,caretX()-1); + QSynedit::SyntaxState state = calcSyntaxStateAtLine(caretY()-1, s); + std::shared_ptr cppSyntaxer = std::dynamic_pointer_cast(syntaxer()); + if (syntaxer()->isStringNotFinished(state.state)) { + if (cppSyntaxer->isStringToNextLine(state.state)) + return QuoteStatus::DoubleQuoteEscape; + else + return QuoteStatus::DoubleQuote; } + if (cppSyntaxer->isCharNotFinished(state.state)) { + if (cppSyntaxer->isCharEscaping(state.state)) + return QuoteStatus::SingleQuoteEscape; + else + return QuoteStatus::SingleQuote; + } + if (cppSyntaxer->isRawStringNoEscape(state.state)) + return QuoteStatus::RawStringNoEscape; + if (cppSyntaxer->isRawStringStart(state.state)) + return QuoteStatus::RawString; + if (cppSyntaxer->isRawStringEnd(state.state)) + return QuoteStatus::RawStringEnd; + return QuoteStatus::NotQuote; + } else { + return QuoteStatus::NotQuote; } return Result; } diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index 152b32ea..0781d3b8 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -84,7 +84,8 @@ public: DoubleQuote, DoubleQuoteEscape, RawString, - RawStringNoEscape + RawStringNoEscape, + RawStringEnd }; enum class WordPurpose { diff --git a/libs/qsynedit/qsynedit/qsynedit.cpp b/libs/qsynedit/qsynedit/qsynedit.cpp index 969c60b5..bfcd85b3 100644 --- a/libs/qsynedit/qsynedit/qsynedit.cpp +++ b/libs/qsynedit/qsynedit/qsynedit.cpp @@ -2985,6 +2985,18 @@ void QSynEdit::decPaintLock() } } +SyntaxState QSynEdit::calcSyntaxStateAtLine(int line, const QString &newLineText) +{ + if (line == 0) { + syntaxer()->resetState(); + } else { + syntaxer()->setState(mDocument->getSyntaxState(line-1)); + } + syntaxer()->setLine(newLineText,line); + syntaxer()->nextToEol(); + return syntaxer()->getState(); +} + int QSynEdit::clientWidth() const { return viewport()->size().width(); diff --git a/libs/qsynedit/qsynedit/qsynedit.h b/libs/qsynedit/qsynedit/qsynedit.h index a0cb849b..a49678d8 100644 --- a/libs/qsynedit/qsynedit/qsynedit.h +++ b/libs/qsynedit/qsynedit/qsynedit.h @@ -504,6 +504,7 @@ protected: void doSelectLine(); void incPaintLock(); void decPaintLock(); + SyntaxState calcSyntaxStateAtLine(int line, const QString &newLineText); private: BufferCoord ensureBufferCoordValid(const BufferCoord& coord); void beginEditingWithoutUndo(); diff --git a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp index 41d759ab..602cae6e 100644 --- a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp +++ b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp @@ -263,6 +263,36 @@ const PTokenAttribute &CppSyntaxer::localVarAttribute() const return mLocalVarAttribute; } +bool CppSyntaxer::isStringToNextLine(int state) +{ + return state == RangeState::rsStringNextLine; +} + +bool CppSyntaxer::isRawStringStart(int state) +{ + return state == RangeState::rsRawString; +} + +bool CppSyntaxer::isRawStringNoEscape(int state) +{ + return state == RangeState::rsRawStringNotEscaping; +} + +bool CppSyntaxer::isRawStringEnd(int state) +{ + return state == RangeState::rsRawStringEnd; +} + +bool CppSyntaxer::isCharNotFinished(int state) +{ + return state == RangeState::rsChar || state == RangeState::rsCharEscaping; +} + +bool CppSyntaxer::isCharEscaping(int state) +{ + return state == RangeState::rsCharEscaping; +} + CppSyntaxer::TokenId CppSyntaxer::getTokenId() { return mTokenId; @@ -370,17 +400,25 @@ void CppSyntaxer::procAnsiCStyleComment() void CppSyntaxer::procAsciiChar() { mTokenId = TokenId::Char; - do { - if (mLine[mRun] == '\\') { - if (mRun+1=mLineSize) { + mRun++; + mRange.state = RangeState::rsCharEscaping; + return; + } else if (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\') { mRun+=1; } + } else if (isSpaceChar(mLine[mRun])) { + return; } mRun+=1; - } while (mRun < mLineSize && mLine[mRun]!='\''); - if (mRun(""); while (mRun127 || mLine[mRun].unicode()<=32)) { mRange.state = RangeState::rsUnknown; @@ -983,7 +1020,6 @@ void CppSyntaxer::procRawString() case '(': if (mRange.state==RangeState::rsRawString) { mRange.state = RangeState::rsRawStringNotEscaping; - rawStringInitialDCharSeq += "\""; mRange.extraData = std::make_shared(rawStringInitialDCharSeq); } break; @@ -991,20 +1027,24 @@ void CppSyntaxer::procRawString() if (mRange.state == RangeState::rsRawStringNotEscaping) { rawStringInitialDCharSeq = mRange.extraData->toString(); if ( mLine.mid(mRun+1,rawStringInitialDCharSeq.length()) == rawStringInitialDCharSeq) { - mRun = mRun+1+rawStringInitialDCharSeq.length(); - mRange.state = RangeState::rsUnknown; + mRun = mRun+rawStringInitialDCharSeq.length(); + mRange.state = RangeState::rsRawStringEnd; mRange.extraData = nullptr; - return; } } break; + case '\"': + if (mRange.state == RangeState::rsRawStringEnd) { + mRange.state = RangeState::rsUnknown; + mRun++; + return; + } + break; } if (mRange.state == RangeState::rsRawString) rawStringInitialDCharSeq += mLine[mRun]; - mRun+=1; + mRun++; } - if (mRun>=mLineSize && mRange.state != RangeState::rsRawStringNotEscaping) - mRange.state = RangeState::rsUnknown; } void CppSyntaxer::procRoundClose() @@ -1253,7 +1293,7 @@ void CppSyntaxer::procStringEscapeSeq() void CppSyntaxer::procString() { if (mRun >= mLineSize) { - mRange.state = RangeState::rsUnknown; + mRange.state = RangeState::rsStringUnfinished; return; } mTokenId = TokenId::String; @@ -1266,7 +1306,7 @@ void CppSyntaxer::procString() } else if (mLine[mRun]=='\\') { if (mRun == mLineSize-1) { mRun++; - mRange.state = RangeState::rsString; + mRange.state = RangeState::rsStringNextLine; return; } if (mRun+1=mLineSize) + mRange.state = RangeState::rsStringUnfinished; + else + mRange.state = RangeState::rsUnknown; } void CppSyntaxer::procStringStart() @@ -1311,7 +1354,7 @@ void CppSyntaxer::procStringStart() mRange.state = RangeState::rsString; mRun += 1; if (mRun>=mLineSize) { - mRange.state = RangeState::rsUnknown; + mRange.state = RangeState::rsStringUnfinished; return; } //procString(); @@ -1349,6 +1392,9 @@ void CppSyntaxer::processChar() procAndSymbol(); break; case '\'': + mTokenId = TokenId::Char; + mRange.state = RangeState::rsChar; + mRun++; procAsciiChar(); break; case '}': @@ -1525,7 +1571,7 @@ bool CppSyntaxer::isCommentNotFinished(int state) const bool CppSyntaxer::isStringNotFinished(int state) const { - return state == RangeState::rsString; + return state == RangeState::rsString || state==RangeState::rsStringNextLine || state==RangeState::rsStringUnfinished; } bool CppSyntaxer::isDocstringNotFinished(int state) const @@ -1591,6 +1637,13 @@ int CppSyntaxer::getTokenPos() void CppSyntaxer::next() { + if (mRun==0) { + switch(mRange.state) { + case RangeState::rsString: + case RangeState::rsChar: + mRange.state = RangeState::rsUnknown; + } + } mTokenPos = mRun; if (mLineSize == 0 && mRange.state == RangeState::rsString) mRange.state=RangeState::rsUnknown; @@ -1613,6 +1666,7 @@ void CppSyntaxer::next() procDocstring(); break; case RangeState::rsString: + case RangeState::rsStringNextLine: //qDebug()<<"*1-0-0*"; procString(); break; @@ -1633,16 +1687,7 @@ void CppSyntaxer::next() procStringEscapeSeq(); break; case RangeState::rsChar: - //qDebug()<<"*7-0-0*"; - if (mRun>=mLineSize) { - procNull(); - } else if (mLine[mRun]=='\'') { - mRange.state = rsUnknown; - mTokenId = TokenId::Char; - mRun+=1; - } else { - procAsciiChar(); - } + procAsciiChar(); break; case RangeState::rsDefineIdentifier: //qDebug()<<"*8-0-0*"; @@ -1654,7 +1699,6 @@ void CppSyntaxer::next() break; case RangeState::rsRawStringNotEscaping: case RangeState::rsRawString: - case RangeState::rsRawStringEnd: //qDebug()<<"*9-0-0*"; procRawString(); break; diff --git a/libs/qsynedit/qsynedit/syntaxer/cpp.h b/libs/qsynedit/qsynedit/syntaxer/cpp.h index 0b4fdf43..dc0e0231 100644 --- a/libs/qsynedit/qsynedit/syntaxer/cpp.h +++ b/libs/qsynedit/qsynedit/syntaxer/cpp.h @@ -46,11 +46,13 @@ public: }; enum RangeState { - rsUnknown, rsAnsiC, rsDirective, rsDirectiveComment, rsString, + rsUnknown, rsAnsiC, rsDirective, rsDirectiveComment, + rsString, rsStringNextLine, rsStringUnfinished, rsMultiLineString, rsMultiLineDirective, rsCppComment, rsDocstring, rsStringEscapeSeq, - rsRawString, rsSpace,rsRawStringNotEscaping,rsRawStringEnd,rsChar, + rsRawString, rsSpace,rsRawStringNotEscaping,rsRawStringEnd, + rsChar, rsCharEscaping, rsDefineIdentifier, rsDefineRemaining, }; @@ -88,6 +90,13 @@ public: static const QSet ValidIntegerSuffixes; + bool isStringToNextLine(int state); + bool isRawStringStart(int state); + bool isRawStringNoEscape(int state); + bool isRawStringEnd(int state); + bool isCharNotFinished(int state); + bool isCharEscaping(int state); + TokenId getTokenId(); private: void procAndSymbol();