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();
} 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; i<posX;i++) {
if (i+1<Line.length() && (Line[i] == 'R') && (Line[i+1] == '"') && (Result == QuoteStatus::NotQuote)) {
Result = QuoteStatus::RawString;
i++; // skip R
} else if (Line[i] == '(') {
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;
}
} else {
switch(Result) {
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;
}
if (syntaxer()->language()==QSynedit::ProgrammingLanguage::CPP) {
QString s = lineText().mid(0,caretX()-1);
QSynedit::SyntaxState state = calcSyntaxStateAtLine(caretY()-1, s);
std::shared_ptr<QSynedit::CppSyntaxer> cppSyntaxer = std::dynamic_pointer_cast<QSynedit::CppSyntaxer>(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;
}

View File

@ -84,7 +84,8 @@ public:
DoubleQuote,
DoubleQuoteEscape,
RawString,
RawStringNoEscape
RawStringNoEscape,
RawStringEnd
};
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
{
return viewport()->size().width();

View File

@ -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();

View File

@ -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 && (mLine[mRun+1] == '\'' || mLine[mRun+1] == '\\')) {
while (mRun < mLineSize) {
if (mLine[mRun] =='\'') {
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;
}
} else if (isSpaceChar(mLine[mRun])) {
return;
}
mRun+=1;
} while (mRun < mLineSize && mLine[mRun]!='\'');
if (mRun<mLineSize && mLine[mRun] == '\'')
mRun+=1;
mRange.state = RangeState::rsUnknown;
}
if (mRun<mLineSize)
mRange.state = RangeState::rsUnknown;
}
void CppSyntaxer::procBraceClose()
@ -968,8 +1006,7 @@ void CppSyntaxer::procRawString()
mRange.extraData = std::make_shared<QVariant>("");
while (mRun<mLineSize) {
if (mRange.state!=RangeState::rsRawStringNotEscaping &&
(mLine[mRun]=='"'
|| mLine[mRun].isSpace()
(mLine[mRun].isSpace()
|| mLine[mRun].unicode()>127
|| 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<QVariant>(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) {
@ -1302,7 +1342,10 @@ void CppSyntaxer::procString()
}
mRun+=1;
}
mRange.state = RangeState::rsUnknown;
if (mRun>=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;

View File

@ -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<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();
private:
void procAndSymbol();