refactor: Check string/rawstring/character status while completing symbols in c/c++ file

This commit is contained in:
Roy Qu 2024-03-05 21:20:47 +08:00
parent 417c33a8dc
commit f7514e424e
6 changed files with 129 additions and 156 deletions

View File

@ -732,15 +732,8 @@ void Editor::keyPressEvent(QKeyEvent *event)
clearUserCodeInTabStops(); clearUserCodeInTabStops();
} else { } else {
QString s = lineText().mid(0,caretX()-1).trimmed(); QString s = lineText().mid(0,caretX()-1).trimmed();
if (caretY()==1) { QSynedit::SyntaxState state = calcSyntaxStateAtLine(caretY()-1, s);
syntaxer()->resetState(); if (syntaxer()->isCommentNotFinished(state.state)) {
} else {
syntaxer()->setState(document()->getSyntaxState(caretY()-2));
}
syntaxer()->setLine(s,caretY());
syntaxer()->nextToEol();
int state = syntaxer()->getState().state;
if (syntaxer()->isCommentNotFinished(state)) {
if (s=="/**") { //javadoc style docstring if (s=="/**") { //javadoc style docstring
s = lineText().mid(caretX()-1).trimmed(); s = lineText().mid(caretX()-1).trimmed();
if (s=="*/") { if (s=="*/") {
@ -2961,7 +2954,7 @@ bool Editor::handleDoubleQuoteCompletion()
QuoteStatus status = getQuoteStatus(); QuoteStatus status = getQuoteStatus();
QChar ch = getCurrentChar(); QChar ch = getCurrentChar();
if (ch == '"') { if (ch == '"') {
if ((status == QuoteStatus::DoubleQuote || status == QuoteStatus::RawString) if ((status == QuoteStatus::DoubleQuote || status == QuoteStatus::RawStringEnd)
&& !selAvail()) { && !selAvail()) {
setCaretXY( QSynedit::BufferCoord{caretX() + 1, caretY()}); // skip over setCaretXY( QSynedit::BufferCoord{caretX() + 1, caretY()}); // skip over
return true; return true;
@ -3100,118 +3093,31 @@ ParserLanguage Editor::calcParserLanguage()
Editor::QuoteStatus Editor::getQuoteStatus() Editor::QuoteStatus Editor::getQuoteStatus()
{ {
QuoteStatus Result = QuoteStatus::NotQuote; QuoteStatus Result = QuoteStatus::NotQuote;
if ((caretY()>1) && syntaxer()->isStringNotFinished(document()->getSyntaxState(caretY() - 2).state)) if (syntaxer()->language()==QSynedit::ProgrammingLanguage::CPP) {
Result = QuoteStatus::DoubleQuote; QString s = lineText().mid(0,caretX()-1);
QSynedit::SyntaxState state = calcSyntaxStateAtLine(caretY()-1, s);
QString Line = document()->getLine(caretY()-1); std::shared_ptr<QSynedit::CppSyntaxer> cppSyntaxer = std::dynamic_pointer_cast<QSynedit::CppSyntaxer>(syntaxer());
int posX = caretX()-1; if (syntaxer()->isStringNotFinished(state.state)) {
if (posX >= Line.length()) { if (cppSyntaxer->isStringToNextLine(state.state))
posX = Line.length()-1; return QuoteStatus::DoubleQuoteEscape;
else
return QuoteStatus::DoubleQuote;
} }
for (int i=0; i<posX;i++) { if (cppSyntaxer->isCharNotFinished(state.state)) {
if (i+1<Line.length() && (Line[i] == 'R') && (Line[i+1] == '"') && (Result == QuoteStatus::NotQuote)) { if (cppSyntaxer->isCharEscaping(state.state))
Result = QuoteStatus::RawString; return QuoteStatus::SingleQuoteEscape;
i++; // skip R else
} else if (Line[i] == '(') { return QuoteStatus::SingleQuote;
switch(Result) {
case QuoteStatus::RawString:
Result=QuoteStatus::RawStringNoEscape;
break;
default:
break;
}
} else if (Line[i] == ')') {
switch(Result) {
case QuoteStatus::RawStringNoEscape:
Result=QuoteStatus::RawString;
break;
default:
break;
}
} else if (Line[i] == '"') {
switch(Result) {
case QuoteStatus::NotQuote:
Result = QuoteStatus::DoubleQuote;
break;
case QuoteStatus::SingleQuote:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::SingleQuoteEscape:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::DoubleQuote:
Result = QuoteStatus::NotQuote;
break;
case QuoteStatus::DoubleQuoteEscape:
Result = QuoteStatus::DoubleQuote;
break;
case QuoteStatus::RawString:
Result=QuoteStatus::NotQuote;
break;
default:
break;
}
} else if (Line[i] == '\'') {
switch(Result) {
case QuoteStatus::NotQuote:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::SingleQuote:
Result = QuoteStatus::NotQuote;
break;
case QuoteStatus::SingleQuoteEscape:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::DoubleQuote:
Result = QuoteStatus::DoubleQuote;
break;
case QuoteStatus::DoubleQuoteEscape:
Result = QuoteStatus::DoubleQuote;
break;
default:
break;
}
} else if (Line[i] == '\\') {
switch(Result) {
case QuoteStatus::NotQuote:
Result = QuoteStatus::NotQuote;
break;
case QuoteStatus::SingleQuote:
Result = QuoteStatus::SingleQuoteEscape;
break;
case QuoteStatus::SingleQuoteEscape:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::DoubleQuote:
Result = QuoteStatus::DoubleQuoteEscape;
break;
case QuoteStatus::DoubleQuoteEscape:
Result = QuoteStatus::DoubleQuote;
break;
default:
break;
} }
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 { } else {
switch(Result) { return QuoteStatus::NotQuote;
case QuoteStatus::NotQuote:
Result = QuoteStatus::NotQuote;
break;
case QuoteStatus::SingleQuote:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::SingleQuoteEscape:
Result = QuoteStatus::SingleQuote;
break;
case QuoteStatus::DoubleQuote:
Result = QuoteStatus::DoubleQuote;
break;
case QuoteStatus::DoubleQuoteEscape:
Result = QuoteStatus::DoubleQuote;
break;
default:
break;
}
}
} }
return Result; return Result;
} }

View File

@ -84,7 +84,8 @@ public:
DoubleQuote, DoubleQuote,
DoubleQuoteEscape, DoubleQuoteEscape,
RawString, RawString,
RawStringNoEscape RawStringNoEscape,
RawStringEnd
}; };
enum class WordPurpose { enum class WordPurpose {

View File

@ -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 int QSynEdit::clientWidth() const
{ {
return viewport()->size().width(); return viewport()->size().width();

View File

@ -504,6 +504,7 @@ protected:
void doSelectLine(); void doSelectLine();
void incPaintLock(); void incPaintLock();
void decPaintLock(); void decPaintLock();
SyntaxState calcSyntaxStateAtLine(int line, const QString &newLineText);
private: private:
BufferCoord ensureBufferCoordValid(const BufferCoord& coord); BufferCoord ensureBufferCoordValid(const BufferCoord& coord);
void beginEditingWithoutUndo(); void beginEditingWithoutUndo();

View File

@ -263,6 +263,36 @@ const PTokenAttribute &CppSyntaxer::localVarAttribute() const
return mLocalVarAttribute; 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() CppSyntaxer::TokenId CppSyntaxer::getTokenId()
{ {
return mTokenId; return mTokenId;
@ -370,16 +400,24 @@ void CppSyntaxer::procAnsiCStyleComment()
void CppSyntaxer::procAsciiChar() void CppSyntaxer::procAsciiChar()
{ {
mTokenId = TokenId::Char; mTokenId = TokenId::Char;
do { while (mRun < mLineSize) {
if (mLine[mRun] == '\\') { if (mLine[mRun] =='\'') {
if (mRun+1<mLineSize && (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\')) { mRun++;
break;
} if (mLine[mRun] == '\\') {
if (mRun+1>=mLineSize) {
mRun++;
mRange.state = RangeState::rsCharEscaping;
return;
} else if (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\') {
mRun+=1; mRun+=1;
} }
} else if (isSpaceChar(mLine[mRun])) {
return;
} }
mRun+=1; mRun+=1;
} while (mRun < mLineSize && mLine[mRun]!='\''); }
if (mRun<mLineSize && mLine[mRun] == '\'') if (mRun<mLineSize)
mRun+=1;
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsUnknown;
} }
@ -968,8 +1006,7 @@ void CppSyntaxer::procRawString()
mRange.extraData = std::make_shared<QVariant>(""); mRange.extraData = std::make_shared<QVariant>("");
while (mRun<mLineSize) { while (mRun<mLineSize) {
if (mRange.state!=RangeState::rsRawStringNotEscaping && if (mRange.state!=RangeState::rsRawStringNotEscaping &&
(mLine[mRun]=='"' (mLine[mRun].isSpace()
|| mLine[mRun].isSpace()
|| mLine[mRun].unicode()>127 || mLine[mRun].unicode()>127
|| mLine[mRun].unicode()<=32)) { || mLine[mRun].unicode()<=32)) {
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsUnknown;
@ -983,7 +1020,6 @@ void CppSyntaxer::procRawString()
case '(': case '(':
if (mRange.state==RangeState::rsRawString) { if (mRange.state==RangeState::rsRawString) {
mRange.state = RangeState::rsRawStringNotEscaping; mRange.state = RangeState::rsRawStringNotEscaping;
rawStringInitialDCharSeq += "\"";
mRange.extraData = std::make_shared<QVariant>(rawStringInitialDCharSeq); mRange.extraData = std::make_shared<QVariant>(rawStringInitialDCharSeq);
} }
break; break;
@ -991,20 +1027,24 @@ void CppSyntaxer::procRawString()
if (mRange.state == RangeState::rsRawStringNotEscaping) { if (mRange.state == RangeState::rsRawStringNotEscaping) {
rawStringInitialDCharSeq = mRange.extraData->toString(); rawStringInitialDCharSeq = mRange.extraData->toString();
if ( mLine.mid(mRun+1,rawStringInitialDCharSeq.length()) == rawStringInitialDCharSeq) { if ( mLine.mid(mRun+1,rawStringInitialDCharSeq.length()) == rawStringInitialDCharSeq) {
mRun = mRun+1+rawStringInitialDCharSeq.length(); mRun = mRun+rawStringInitialDCharSeq.length();
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsRawStringEnd;
mRange.extraData = nullptr; mRange.extraData = nullptr;
return;
} }
} }
break; break;
case '\"':
if (mRange.state == RangeState::rsRawStringEnd) {
mRange.state = RangeState::rsUnknown;
mRun++;
return;
}
break;
} }
if (mRange.state == RangeState::rsRawString) if (mRange.state == RangeState::rsRawString)
rawStringInitialDCharSeq += mLine[mRun]; rawStringInitialDCharSeq += mLine[mRun];
mRun+=1; mRun++;
} }
if (mRun>=mLineSize && mRange.state != RangeState::rsRawStringNotEscaping)
mRange.state = RangeState::rsUnknown;
} }
void CppSyntaxer::procRoundClose() void CppSyntaxer::procRoundClose()
@ -1253,7 +1293,7 @@ void CppSyntaxer::procStringEscapeSeq()
void CppSyntaxer::procString() void CppSyntaxer::procString()
{ {
if (mRun >= mLineSize) { if (mRun >= mLineSize) {
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsStringUnfinished;
return; return;
} }
mTokenId = TokenId::String; mTokenId = TokenId::String;
@ -1266,7 +1306,7 @@ void CppSyntaxer::procString()
} else if (mLine[mRun]=='\\') { } else if (mLine[mRun]=='\\') {
if (mRun == mLineSize-1) { if (mRun == mLineSize-1) {
mRun++; mRun++;
mRange.state = RangeState::rsString; mRange.state = RangeState::rsStringNextLine;
return; return;
} }
if (mRun+1<mLineSize) { if (mRun+1<mLineSize) {
@ -1302,6 +1342,9 @@ void CppSyntaxer::procString()
} }
mRun+=1; mRun+=1;
} }
if (mRun>=mLineSize)
mRange.state = RangeState::rsStringUnfinished;
else
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsUnknown;
} }
@ -1311,7 +1354,7 @@ void CppSyntaxer::procStringStart()
mRange.state = RangeState::rsString; mRange.state = RangeState::rsString;
mRun += 1; mRun += 1;
if (mRun>=mLineSize) { if (mRun>=mLineSize) {
mRange.state = RangeState::rsUnknown; mRange.state = RangeState::rsStringUnfinished;
return; return;
} }
//procString(); //procString();
@ -1349,6 +1392,9 @@ void CppSyntaxer::processChar()
procAndSymbol(); procAndSymbol();
break; break;
case '\'': case '\'':
mTokenId = TokenId::Char;
mRange.state = RangeState::rsChar;
mRun++;
procAsciiChar(); procAsciiChar();
break; break;
case '}': case '}':
@ -1525,7 +1571,7 @@ bool CppSyntaxer::isCommentNotFinished(int state) const
bool CppSyntaxer::isStringNotFinished(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 bool CppSyntaxer::isDocstringNotFinished(int state) const
@ -1591,6 +1637,13 @@ int CppSyntaxer::getTokenPos()
void CppSyntaxer::next() void CppSyntaxer::next()
{ {
if (mRun==0) {
switch(mRange.state) {
case RangeState::rsString:
case RangeState::rsChar:
mRange.state = RangeState::rsUnknown;
}
}
mTokenPos = mRun; mTokenPos = mRun;
if (mLineSize == 0 && mRange.state == RangeState::rsString) if (mLineSize == 0 && mRange.state == RangeState::rsString)
mRange.state=RangeState::rsUnknown; mRange.state=RangeState::rsUnknown;
@ -1613,6 +1666,7 @@ void CppSyntaxer::next()
procDocstring(); procDocstring();
break; break;
case RangeState::rsString: case RangeState::rsString:
case RangeState::rsStringNextLine:
//qDebug()<<"*1-0-0*"; //qDebug()<<"*1-0-0*";
procString(); procString();
break; break;
@ -1633,16 +1687,7 @@ void CppSyntaxer::next()
procStringEscapeSeq(); procStringEscapeSeq();
break; break;
case RangeState::rsChar: 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; break;
case RangeState::rsDefineIdentifier: case RangeState::rsDefineIdentifier:
//qDebug()<<"*8-0-0*"; //qDebug()<<"*8-0-0*";
@ -1654,7 +1699,6 @@ void CppSyntaxer::next()
break; break;
case RangeState::rsRawStringNotEscaping: case RangeState::rsRawStringNotEscaping:
case RangeState::rsRawString: case RangeState::rsRawString:
case RangeState::rsRawStringEnd:
//qDebug()<<"*9-0-0*"; //qDebug()<<"*9-0-0*";
procRawString(); procRawString();
break; break;

View File

@ -46,11 +46,13 @@ public:
}; };
enum RangeState { enum RangeState {
rsUnknown, rsAnsiC, rsDirective, rsDirectiveComment, rsString, rsUnknown, rsAnsiC, rsDirective, rsDirectiveComment,
rsString, rsStringNextLine, rsStringUnfinished,
rsMultiLineString, rsMultiLineDirective, rsCppComment, rsMultiLineString, rsMultiLineDirective, rsCppComment,
rsDocstring, rsDocstring,
rsStringEscapeSeq, rsStringEscapeSeq,
rsRawString, rsSpace,rsRawStringNotEscaping,rsRawStringEnd,rsChar, rsRawString, rsSpace,rsRawStringNotEscaping,rsRawStringEnd,
rsChar, rsCharEscaping,
rsDefineIdentifier, rsDefineRemaining, rsDefineIdentifier, rsDefineRemaining,
}; };
@ -88,6 +90,13 @@ public:
static const QSet<QString> ValidIntegerSuffixes; static const QSet<QString> 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(); TokenId getTokenId();
private: private:
void procAndSymbol(); void procAndSymbol();