From cb1d2594dabe1498783c5e338896c35d9475060a Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Thu, 22 Feb 2024 18:03:07 +0800 Subject: [PATCH] work save --- libs/qsynedit/qsynedit/document.cpp | 222 ++++++++++++++++++++++------ libs/qsynedit/qsynedit/document.h | 109 +++++++++++--- libs/qsynedit/qsynedit/painter.cpp | 94 ++++++++---- libs/qsynedit/qsynedit/painter.h | 2 + libs/qsynedit/qsynedit/qsynedit.cpp | 143 +++++++++--------- libs/qsynedit/qsynedit/qsynedit.h | 7 +- 6 files changed, 408 insertions(+), 169 deletions(-) diff --git a/libs/qsynedit/qsynedit/document.cpp b/libs/qsynedit/qsynedit/document.cpp index 6a4da3ff..e72330b8 100644 --- a/libs/qsynedit/qsynedit/document.cpp +++ b/libs/qsynedit/qsynedit/document.cpp @@ -823,6 +823,20 @@ void Document::saveToFile(QFile &file, const QByteArray& encoding, } } +QString Document::glyph(int line, int glyphIdx) +{ + QMutexLocker locker(&mMutex); + return mLines[line]->glyph(glyphIdx); +} + +QString Document::glyphAt(int line, int charPos) +{ + QMutexLocker locker(&mMutex); + QList glyphPositions = mLines[line]->glyphPositions(); + int glyphIdx = charToGlyphIndex(glyphPositions, charPos); + return mLines[line]->glyph(glyphIdx); +} + QList calcGlyphPositions(const QString &text) { QList glyphPositions; @@ -853,41 +867,165 @@ int Document::stringColumns(const QString &str, int colsBefore) const return totalColumns - colsBefore; } +int Document::glyphStart(int line, int glyphIdx) +{ + QMutexLocker locker(&mMutex); + return mLines[line]->glyphStart(glyphIdx); +} + +int Document::glyphLength(int line, int glyphIdx) +{ + QMutexLocker locker(&mMutex); + return mLines[line]->glyphLength(glyphIdx); +} + +int Document::glyphStartColumn(int line, int glyphIdx) +{ + QMutexLocker locker(&mMutex); + return mLines[line]->glyphStartColumn(glyphIdx); +} + +int Document::glyphColumns(int line, int glyphIdx) +{ + QMutexLocker locker(&mMutex); + return mLines[line]->glyphColumns(glyphIdx); +} + +int Document::glyphColumns(const QString &glyph, int colsBefore) const +{ + int glyphCols; + if (glyph.length()==1 && glyph[0].unicode()<0xFF) { + QChar ch = glyph[0]; + if (ch == '\t') { + glyphCols = mTabWidth - colsBefore % mTabWidth; + } else { + int width = mFontMetrics.horizontalAdvance(ch); + glyphCols = std::max(1.0, std::ceil(width / (double)mCharWidth)); + } + } else { + int width = mNonAsciiFontMetrics.horizontalAdvance(glyph); + glyphCols = std::max(1.0, std::ceil(width / (double)mCharWidth)); + } + return glyphCols; + +} + +int Document::charToGlyphIndex(int line, int charIdx) +{ + QMutexLocker locker(&mMutex); + QList glyphPositions = mLines[line]->glyphPositions(); + return charToGlyphIndex(glyphPositions, charIdx); +} + +int Document::charToGlyphIndex(QList glyphPositions, int charIdx) const +{ + Q_ASSERT(charIdx>=0); + for (int i=0;icharIdx) { + Q_ASSERT(i-1>=0); + return i-1; + } + } + Q_ASSERT(glyphPositions.length()-1>=0); + return glyphPositions.length()-1; +} + +int Document::columnToGlyphIndex(int line, int column) +{ + QMutexLocker locker(&mMutex); + QList glyphColumnsList = mLines[line]->glyphColumnsList(); + return columnToGlyphIndex(glyphColumnsList,column); +} + +int Document::columnToGlyphIndex(QList glyphColumnsList, int column) const +{ + Q_ASSERT(column>=1); + for (int i=0;icolumn) { + Q_ASSERT(i-1>=0); + return i-1; + } + } + Q_ASSERT(glyphColumnsList.length()-1>=0); + return glyphColumnsList.length()-1; +} + int Document::charToColumn(int line, int charPos) { QMutexLocker locker(&mMutex); QList glyphPositions = mLines[line]->glyphPositions(); - + int glyphIdx = charToGlyphIndex(glyphPositions, charPos); + return mLines[line]->glyphStartColumn(glyphIdx); } -int Document::charToColumn(const QString &lineText, int charPos) const +int Document::columnToChar(int line, int column) { QMutexLocker locker(&mMutex); - QList glyphPositions = calcGlyphPositions(lineText); - return charToColumn(lineText, glyphPositions, charPos); + QList glyphColumnsList = mLines[line]->glyphColumnsList(); + int glyphIdx = columnToGlyphIndex(glyphColumnsList, column); + return mLines[line]->glyphStart(glyphIdx); } -int Document::charToColumn(const QString &lineText, const QList &glyphPositions, int charPos) const +int Document::charToColumn(int line, const QString newStr, int charPos) { - Q_ASSERT(charPos=0); - int glyphIdx; - for (glyphIdx=0;glyphIdx glyphPositions; + if (mLines[line]->lineText() == newStr) + glyphPositions = mLines[line]->glyphPositions(); + else + glyphPositions = calcGlyphPositions(newStr); + int glyphIdx = charToGlyphIndex(glyphPositions, charPos); + return mLines[line]->glyphStartColumn(glyphIdx); +} + +int Document::columnToChar(int line, const QString newStr, int column) +{ + QMutexLocker locker(&mMutex); + QList glyphColumnsList; + if (mLines[line]->lineText() == newStr) + glyphColumnsList = mLines[line]->glyphColumnsList(); + else { + glyphColumnsList = calcGlyphColumns(mLines[line]->lineText()); } - int cols=0; + int glyphIdx = columnToGlyphIndex(glyphColumnsList, column); + return mLines[line]->glyphStart(glyphIdx); } -int Document::columnToChar(const QString &lineText, int column) const -{ - QList glyphPositions = calcGlyphPositions(lineText); - return columnToChar(lineText, glyphPositions, column); -} +// int Document::charToColumn(int line, int charPos) +// { +// QMutexLocker locker(&mMutex); +// QList glyphPositions = mLines[line]->glyphPositions(); -int Document::columnToChar(const QString &lineText, const QList &glyphPositions, int column) const -{ +// } -} +// int Document::charToColumn(const QString &lineText, int charPos) const +// { +// QMutexLocker locker(&mMutex); +// QList glyphPositions = calcGlyphPositions(lineText); +// return charToColumn(lineText, glyphPositions, charPos); +// } + +// int Document::charToColumn(const QString &lineText, const QList &glyphPositions, int charPos) const +// { +// Q_ASSERT(charPos=0); +// int glyphIdx; +// for (glyphIdx=0;glyphIdx glyphPositions = calcGlyphPositions(lineText); +// return columnToChar(lineText, glyphPositions, column); +// } + +// int Document::columnToChar(const QString &lineText, const QList &glyphPositions, int column) const +// { + +// } void Document::putTextStr(const QString &text) { @@ -932,7 +1070,7 @@ QList Document::calcGlyphColumns(const QString &lineText, const QList { totalColumns = std::max(0,colsBefore); int start,end; - QList glyphColumns; + QList glyphColumnsList; for (int i=0;i Document::calcGlyphColumns(const QString &lineText, const QList end = lineText.length(); } QString glyph = lineText.mid(start,end-start); - int glyphCols; - if (glyph.length()==1 && glyph[0].unicode()<0xFF) { - QChar ch = glyph[0]; - if (ch == '\t') { - glyphCols = mTabWidth - totalColumns % mTabWidth; - } else { - int width = mFontMetrics.horizontalAdvance(ch); - glyphCols = std::max(1.0, std::ceil(width / (double)mCharWidth)); - } - } else { - int width = mNonAsciiFontMetrics.horizontalAdvance(glyph); - glyphCols = std::max(1.0, std::ceil(width / (double)mCharWidth)); - } - glyphColumns.append(totalColumns); + int glyphCols = glyphColumns(glyph,totalColumns); + glyphColumnsList.append(totalColumns+1); totalColumns += glyphCols; } - return glyphColumns; + return glyphColumnsList; +} + +QList Document::calcGlyphColumns(const QString &lineText) const +{ + QList glyphPositions = calcGlyphPositions(lineText); + int totalColumns; + return calcGlyphColumns(lineText,glyphPositions,0,totalColumns); } NewlineType Document::getNewlineType() @@ -993,32 +1126,31 @@ DocumentLine::DocumentLine(): { } -int DocumentLine::glyphEnd(int i) const +int DocumentLine::glyphLength(int i) const { Q_ASSERT(i>=0 && i=0); Q_ASSERT(i>=0 && i& glyphColumns() const { + const QList& glyphColumnsList() const { return mGlyphColumns; } /** * @brief get start index of the chars representing the specified glyph. - * @param i index of the glyph of the line (starting from 0) - * @return + * @param i index of the glyph in the line (starting from 0) + * @return char index in the line text (start from 0) */ int glyphStart(int i) const { Q_ASSERT(i>=0 && i=0); Q_ASSERT(i>=0 && i glyphPositions, int charPos) const; + + /** + * @brief get index of the glyph displayed on the specified column + * + * It's thread safe. + * + * @param line index of the line (starting from 0) + * @param column the column (starting from 1) + * @return glyph index in the line (starting from 0) + */ + int columnToGlyphIndex(int line, int column); + int columnToGlyphIndex(QList glyphColumnsList, int column) const; int charToColumn(int line, int charPos); int columnToChar(int line, int column); int charToColumn(int line, const QString newStr, int charPos); int columnToChar(int line, const QString newStr, int column); - int columnToGlyphIndex(int line, int column); - - - - int charToColumn(const QString& str, int charPos); - int charToColumn(const QString& lineText, const QList &glyphPositions, int charPos); - int columnToChar(const QString& lineText, int column); - int columnToChar(const QString& lineText, const QList &glyphPositions, int column); - bool getAppendNewLineAtEOF(); void setAppendNewLineAtEOF(bool appendNewLineAtEOF); @@ -492,6 +552,7 @@ protected: void internalClear(); private: QList calcGlyphColumns(const QString& lineText, const QList &glyphPositions, int colsBefore, int &totalColumns) const; + QList calcGlyphColumns(const QString& lineText) const; bool tryLoadFileByEncoding(QByteArray encodingName, QFile& file); void loadUTF16BOMFile(QFile& file); void loadUTF32BOMFile(QFile& file); diff --git a/libs/qsynedit/qsynedit/painter.cpp b/libs/qsynedit/qsynedit/painter.cpp index 9a06581f..963ea2c7 100644 --- a/libs/qsynedit/qsynedit/painter.cpp +++ b/libs/qsynedit/qsynedit/painter.cpp @@ -22,6 +22,28 @@ namespace QSynedit { +QSet QSynEditPainter::operatorGlyphs { + "-", + "+", + "*", + "/", + "\\", + "~", + "!", + "@", + "#", + "$", + "%", + "^", + "&", + "|", + "=", + "<", + ">", + "?", + ":",}; + + QSynEditPainter::QSynEditPainter(QSynEdit *edit, QPainter *painter, int FirstRow, int LastRow, int FirstCol, int LastCol) { this->edit = edit; @@ -30,6 +52,27 @@ QSynEditPainter::QSynEditPainter(QSynEdit *edit, QPainter *painter, int FirstRow this->aLastRow = LastRow; this->FirstCol = FirstCol; this->LastCol = LastCol; + // if (operatorGlyphs.isEmpty()) { + // operatorGlyphs.insert("+"); + // operatorGlyphs.insert("-"); + // operatorGlyphs.insert("*"); + // operatorGlyphs.insert("/"); + // operatorGlyphs.insert("\\"); + // operatorGlyphs.insert("~"); + // operatorGlyphs.insert("!"); + // operatorGlyphs.insert("@"); + // operatorGlyphs.insert("#"); + // operatorGlyphs.insert("$"); + // operatorGlyphs.insert("%"); + // operatorGlyphs.insert("^"); + // operatorGlyphs.insert("&"); + // operatorGlyphs.insert("|"); + // operatorGlyphs.insert("="); + // operatorGlyphs.insert("<"); + // operatorGlyphs.insert(">"); + // operatorGlyphs.insert("?"); + // operatorGlyphs.insert(":"); + // } } void QSynEditPainter::paintTextLines(const QRect& clip) @@ -295,14 +338,14 @@ void QSynEditPainter::computeSelectionInfo() QString sLine = edit->lineText().left(edit->mCaretX-1) + edit->mInputPreeditString + edit->lineText().mid(edit->mCaretX-1); - vSelStart.Column = edit->charToColumn(sLine,vStart.ch); + vSelStart.Column = edit->charToColumn(edit->mCaretY-1, sLine,vStart.ch); } if (edit->mInputPreeditString.length() && vEnd.line == edit->mCaretY) { QString sLine = edit->lineText().left(edit->mCaretX-1) + edit->mInputPreeditString + edit->lineText().mid(edit->mCaretX-1); - vSelEnd.Column = edit->charToColumn(sLine,vEnd.ch); + vSelEnd.Column = edit->charToColumn(edit->mCaretY-1, sLine,vEnd.ch); } // In the column selection mode sort the begin and end of the selection, // this makes the painting code simpler. @@ -355,14 +398,12 @@ void QSynEditPainter::paintToken(const QString &token, int tokenCols, int column } else { int tokenColLen=0; startPaint = false; - for (int i=0;itabWidth() - ((columnsBefore+tokenColLen) % edit->tabWidth()); - } else { - charCols = edit->charColumns(token[i]); - } + QList glyphPositions = calcGlyphPositions(token); + for (int i=0; i< glyphPositions.length();i++) { + int glyphStart = glyphPositions[i]; + int glyphLen =(i+1document()->glyphColumns(glyph, columnsBefore+tokenColLen); if (tokenColLen+charCols>=first) { if (!startPaint && (tokenColLen+1!=first)) { nX-= (first - tokenColLen - 1) * edit->mCharWidth; @@ -376,14 +417,17 @@ void QSynEditPainter::paintToken(const QString &token, int tokenCols, int column bool drawed = false; if (painter->fontInfo().fixedPitch() && edit->mOptions.testFlag(eoLigatureSupport) - && !token[i].isSpace() - && (token[i].unicode()<=0xFF)) { + && operatorGlyphs.contains(glyph)) { + QString textToPaint = glyph; while(i+10xFF || token[i+1].isSpace()) + int glyphStart = glyphPositions[i+1]; + int glyphLen =(i+2charColumns(token[i]); - textToPaint+=token[i]; + charCols += edit->document()->glyphColumns(glyph2,0); + textToPaint+=glyph2; } painter->drawText(nX,rcToken.bottom()-painter->fontMetrics().descent() , textToPaint); drawed = true; @@ -899,13 +943,13 @@ void QSynEditPainter::paintLines() if (!edit->mSyntaxer || !edit->mSyntaxer->enabled()) { sToken = sLine; if (bCurrentLine) { - nTokenColumnLen = edit->lineColumns(vLine-1, sLine,0); + nTokenColumnLen = edit->document()->lineColumns(vLine-1, sLine); } else { - nTokenColumnLen = edit->lineColumns(vLine-1); + nTokenColumnLen = edit->document()->lineColumns(vLine-1); } if (edit->mOptions.testFlag(eoShowLineBreaks) && (!bLineSelected) && (!bSpecialLine) && (nTokenColumnLen < vLastChar)) { sToken = sToken + LineBreakGlyph; - nTokenColumnLen += edit->charColumns(LineBreakGlyph); + nTokenColumnLen += edit->document()->glyphColumns(LineBreakGlyph,0); } if (bComplexLine) { setDrawingColors(true); @@ -928,8 +972,8 @@ void QSynEditPainter::paintLines() PEditingArea area = std::make_shared(); int col = edit->charToColumn(edit->mCaretY,edit->mCaretX); int ch = edit->columnToChar(vLine,col); - area->beginX = edit->charToColumn(sLine,ch); - area->endX = edit->charToColumn(sLine,ch + edit->mInputPreeditString.length()); + area->beginX = edit->charToColumn(vLine-1, sLine,ch); + area->endX = edit->charToColumn(vLine-1, sLine,ch + edit->mInputPreeditString.length()); area->type = EditingAreaType::eatUnderLine; area->color = colFG; areaList.append(area); @@ -1061,7 +1105,7 @@ void QSynEditPainter::paintLines() && (edit->mDocument->lineColumns(vLine-1) < vLastChar)) { addHighlightToken(LineBreakGlyph, edit->mDocument->lineColumns(vLine-1) - (vFirstChar - FirstCol), - edit->charColumns(LineBreakGlyph),vLine, edit->mSyntaxer->whitespaceAttribute(),false); + edit->mDocument->glyphColumns(LineBreakGlyph,0),vLine, edit->mSyntaxer->whitespaceAttribute(),false); } } // Draw anything that's left in the TokenAccu record. Fill to the end @@ -1078,15 +1122,15 @@ void QSynEditPainter::paintLines() area->endX+=edit->mInputPreeditString.length(); } } - area->beginX = edit->charToColumn(sLine, area->beginX); - area->endX = edit->charToColumn(sLine,area->endX); + area->beginX = edit->charToColumn(vLine-1, sLine, area->beginX); + area->endX = edit->charToColumn(vLine-1,sLine,area->endX); } if (bCurrentLine && edit->mInputPreeditString.length()>0) { PEditingArea area = std::make_shared(); int col = edit->charToColumn(edit->mCaretY,edit->mCaretX); int ch = edit->columnToChar(vLine,col); - area->beginX = edit->charToColumn(sLine,ch); - area->endX = edit->charToColumn(sLine,ch + edit->mInputPreeditString.length()); + area->beginX = edit->charToColumn(vLine-1,sLine,ch); + area->endX = edit->charToColumn(vLine-1,sLine,ch + edit->mInputPreeditString.length()); area->type = EditingAreaType::eatUnderLine; if (preeditAttr) { area->color = preeditAttr->foreground(); diff --git a/libs/qsynedit/qsynedit/painter.h b/libs/qsynedit/qsynedit/painter.h index dcc8b628..bd9fe636 100644 --- a/libs/qsynedit/qsynedit/painter.h +++ b/libs/qsynedit/qsynedit/painter.h @@ -88,6 +88,8 @@ private: QRect AClip; int aFirstRow, aLastRow, FirstCol, LastCol; SynTokenAccu mTokenAccu; + + static QSet operatorGlyphs; }; } diff --git a/libs/qsynedit/qsynedit/qsynedit.cpp b/libs/qsynedit/qsynedit/qsynedit.cpp index 7247d461..005e8ec9 100644 --- a/libs/qsynedit/qsynedit/qsynedit.cpp +++ b/libs/qsynedit/qsynedit/qsynedit.cpp @@ -841,40 +841,38 @@ int QSynEdit::charToColumn(int aLine, int aChar) const { if (aLine>=1 && aLine <= mDocument->count()) { QString s = getDisplayStringAtLine(aLine); - QString s2 = mDocument->getLine(line-1); - if (s!=s2) - return mDocument->charToColumn(s, aChar); - else { - QList glyphPositions = mDocument->getGlyphPositions(line-1); - return mDocument->charToColumn(s, glyphPositions, aChar); - } + return mDocument->charToColumn(aLine-1, s, aChar-1); } return aChar; } -int QSynEdit::charToColumn(const QString &s, int aChar) const +int QSynEdit::charToColumn(int aLine, const QString &s, int aChar) const { - return mDocument->charToColumn(s, aChar); + if (aLine>=1 && aLine <= mDocument->count()) { + return mDocument->charToColumn(aLine-1, s, aChar-1); + } + return aChar; } +// int QSynEdit::charToColumn(const QString &s, int aChar) const +// { +// return mDocument->charToColumn(s, aChar); +// } + int QSynEdit::columnToChar(int aLine, int aColumn) const { //Q_ASSERT( (aLine <= mDocument->count()) && (aLine >= 1)); if (aLine <= mDocument->count()) { QString s = getDisplayStringAtLine(aLine); - int x = 0; - int len = s.length(); - int i; - for (i=0;i=aColumn) { - break; - } - } - return i+1; + return mDocument->columnToChar(aLine,s,aColumn)+1; + } + return aColumn; +} + +int QSynEdit::columnToChar(int aLine, const QString &s, int aColumn) const +{ + if (aLine <= mDocument->count()) { + return mDocument->columnToChar(aLine,s,aColumn)+1; } return aColumn; } @@ -1309,11 +1307,6 @@ BufferCoord QSynEdit::getPreviousLeftBrace(int x, int y) } } -int QSynEdit::charColumns(QChar ch) const -{ - return mDocument->charColumns(ch); -} - void QSynEdit::showCaret() { if (m_blinkTimerId==0) @@ -2486,7 +2479,7 @@ QRect QSynEdit::calculateCaretRect() const QString sLine = lineText().left(mCaretX-1) + mInputPreeditString + lineText().mid(mCaretX-1); - coord.Column = charToColumn(sLine,mCaretX+mInputPreeditString.length()); + coord.Column = charToColumn(mCaretY-1, sLine,mCaretX+mInputPreeditString.length()); } int rows=1; if (mActiveSelectionMode == SelectionMode::Column) { @@ -2498,7 +2491,9 @@ QRect QSynEdit::calculateCaretRect() const QPoint caretPos = rowColumnToPixels(coord); int caretWidth=mCharWidth; if (mCaretY <= mDocument->count() && mCaretX <= mDocument->getLine(mCaretY-1).length()) { - caretWidth = charColumns(getDisplayStringAtLine(mCaretY)[mCaretX-1])*mCharWidth; + QString glyph = mDocument->glyphAt(mCaretY-1, mCaretX-1); + int colsBefore = mDocument->charToColumn(mCaretY-1, mCaretX-1)-1; + caretWidth = mDocument->glyphColumns(glyph,colsBefore)*mCharWidth; } if (mActiveSelectionMode == SelectionMode::Column) { return QRect(caretPos.x(),caretPos.y(),caretWidth, @@ -2515,7 +2510,9 @@ QRect QSynEdit::calculateInputCaretRect() const QPoint caretPos = rowColumnToPixels(coord); int caretWidth=mCharWidth; if (mCaretY <= mDocument->count() && mCaretX <= mDocument->getLine(mCaretY-1).length()) { - caretWidth = charColumns(mDocument->getLine(mCaretY-1)[mCaretX-1])*mCharWidth; + QString glyph = mDocument->glyphAt(mCaretY-1, mCaretX-1); + int colsBefore = mDocument->charToColumn(mCaretY-1, mCaretX-1)-1; + caretWidth = mDocument->glyphColumns(glyph,colsBefore)*mCharWidth; } return QRect(caretPos.x(),caretPos.y(),caretWidth, mTextHeight); @@ -3595,49 +3592,51 @@ bool QSynEdit::foldCollapsedBetween(int startLine, int endLine) const return false; } -QString QSynEdit::substringByColumns(const QString &s, int startColumn, int &colLen) -{ +// QString QSynEdit::substringByColumns(const QString &s, int startColumn, int &colLen) +// { - int len = s.length(); - int columns = 0; - int i = 0; - int oldColumns=0; - while (columns < startColumn) { - oldColumns = columns; - if (i>=len) - break; - if (s[i] == '\t') - columns += tabWidth() - (columns % tabWidth()); - else - columns += charColumns(s[i]); - i++; - } - QString result; - if (i>=len) { - colLen = 0; - return result; - } - if (colLen>result.capacity()) { - result.resize(colLen); - } - int j=0; - if (i>0) { - result[0]=s[i-1]; - j++; - } - while (i glyphPositions = calcGlyphPositions(s); +// QList glyphColumnList = mDocument; +// while (columns < startColumn) { +// oldColumns = columns; +// if (i>=len) +// break; +// if (s[i] == '\t') +// columns += tabWidth() - (columns % tabWidth()); +// else +// columns += charColumns(s[i]); +// i++; +// } +// QString result; +// if (i>=len) { +// colLen = 0; +// return result; +// } +// if (colLen>result.capacity()) { +// result.resize(colLen); +// } +// int j=0; +// if (i>0) { +// result[0]=s[i-1]; +// j++; +// } +// while (i