work save

This commit is contained in:
royqh1979@gmail.com 2021-05-18 15:49:58 +08:00
parent cd75fefcc6
commit c7a7f69285
9 changed files with 315 additions and 306 deletions

View File

@ -325,19 +325,8 @@ DisplayCoord SynEdit::pixelsToRowColumn(int aX, int aY)
DisplayCoord SynEdit::bufferToDisplayPos(const BufferCoord &p)
{
DisplayCoord result {p.Char,p.Line};
// Account for tabs
if (p.Line-1 < mLines->count()) {
QString s = mLines->getString(p.Line - 1);
int l = s.length();
int x = 0;
for (int i=0;i<p.Char-1;i++) {
if (i<=l && s[i] == '\t')
x+=mTabWidth - (x % mTabWidth);
else
x+=charColumns(s[i]);
}
result.Column = x + 1;
}
// Account for tabs and charColumns
result.Column = charToColumn(p.Line,p.Char);
// Account for code folding
if (mUseCodeFolding)
result.Row = foldLineToRow(result.Row);
@ -373,6 +362,41 @@ BufferCoord SynEdit::displayToBufferPos(const DisplayCoord &p)
}
}
int SynEdit::charToColumn(int aLine, int aChar)
{
if (aLine < mLines->count()) {
QString s = mLines->getString(aLine - 1);
int l = s.length();
int x = 0;
for (int i=0;i<aChar-1;i++) {
if (i<=l && s[i] == '\t')
x+=mTabWidth - (x % mTabWidth);
else
x+=charColumns(s[i]);
}
return x+1;
}
throw BaseError(SynEdit::tr("Line %1 is out of range").arg(aLine));
}
int SynEdit::stringColumns(const QString &line)
{
int columns = 0;
if (!line.isEmpty()) {
int charCols;
for (int i=0;i<line.length();i++) {
QChar ch = line[i];
if (ch == '\t') {
charCols = mTabWidth - columns % mTabWidth;
} else {
charCols = charColumns(ch);
}
columns+=charCols;
}
}
return columns;
}
int SynEdit::rowToLine(int aRow)
{
return displayToBufferPos({1, aRow}).Line;
@ -1278,6 +1302,11 @@ void SynEdit::doChange()
emit Changed();
}
int SynEdit::tabWidth() const
{
return mTabWidth;
}
void SynEdit::paintEvent(QPaintEvent *event)
{
if (mPainterLock>0)

View File

@ -162,6 +162,8 @@ public:
DisplayCoord pixelsToRowColumn(int aX, int aY);
DisplayCoord bufferToDisplayPos(const BufferCoord& p);
BufferCoord displayToBufferPos(const DisplayCoord& p);
int charToColumn(int aLine, int aChar);
int stringColumns(const QString& line);
int rowToLine(int aRow);
int lineToRow(int aLine);
int foldRowToLine(int Row);
@ -212,6 +214,8 @@ public:
int maxScrollWidth() const;
void setMaxScrollWidth(int Value);
int tabWidth() const;
signals:
void Changed();
@ -234,6 +238,9 @@ signals:
void scrolled(SynScrollBarKind ScrollBar);
void statusChanged(SynStatusChanges changes);
void fontChanged();
void tabSizeChanged();
private:
void clearAreaList(SynEditingAreaList areaList);
void computeCaret(int X, int Y);
@ -411,4 +418,6 @@ protected:
friend class SynEditTextPainter;
};
class
#endif // SYNEDIT_H

View File

@ -4,22 +4,25 @@
#include <QTextCodec>
#include <QTextStream>
#include <stdexcept>
#include "SynEdit.h"
#include "../utils.h"
SynEditStringList::SynEditStringList(QObject* parent):
QObject(parent)
SynEditStringList::SynEditStringList(SynEdit *pEdit, QObject *parent):
QObject(parent),
mEdit(pEdit)
{
mAppendNewLineAtEOF = true;
mFileEndingType = FileEndingType::Windows;
mIndexOfLongestLine = -1;
mUpdateCount = 0;
setTabWidth(8);
}
static void ListIndexOutOfBounds(int index) {
throw IndexOutOfRange(index);
}
int SynEditStringList::parenthesisLevels(int Index)
{
if (Index>=0 && Index < mList.size()) {
@ -44,24 +47,24 @@ int SynEditStringList::braceLevels(int Index)
return 0;
}
QString SynEditStringList::expandedStrings(int Index)
{
if (Index>=0 && Index < mList.size()) {
if (mList[Index]->fFlags & SynEditStringFlag::sfHasNoTabs)
return mList[Index]->fString;
else
return ExpandString(Index);
} else
return QString();
}
//QString SynEditStringList::expandedStrings(int Index)
//{
// if (Index>=0 && Index < mList.size()) {
// if (mList[Index]->fFlags & SynEditStringFlag::sfHasNoTabs)
// return mList[Index]->fString;
// else
// return ExpandString(Index);
// } else
// return QString();
//}
int SynEditStringList::expandedStringLength(int Index)
int SynEditStringList::lineColumns(int Index)
{
if (Index>=0 && Index < mList.size()) {
if (mList[Index]->fFlags & sfExpandedLengthUnknown)
return ExpandString(Index).length();
else
return mList[Index]->fExpandedLength;
if (mList[Index]->fColumns == -1) {
return calculateLineColumns(Index);
} else
return mList[Index]->fColumns;
} else
return 0;
}
@ -73,7 +76,7 @@ int SynEditStringList::lengthOfLongestLine()
mIndexOfLongestLine = -1;
if (mList.count() > 0 ) {
for (int i=0;i<mList.size();i++) {
int len = expandedStringLength(i);
int len = lineColumns(i);
if (len > MaxLen) {
MaxLen = len;
mIndexOfLongestLine = i;
@ -82,7 +85,7 @@ int SynEditStringList::lengthOfLongestLine()
}
}
if (mIndexOfLongestLine >= 0)
return mList[mIndexOfLongestLine]->fExpandedLength;
return mList[mIndexOfLongestLine]->fColumns;
else
return 0;
}
@ -207,23 +210,6 @@ void SynEditStringList::endUpdate()
}
}
int SynEditStringList::tabWidth()
{
return mTabWidth;
}
void SynEditStringList::setTabWidth(int value)
{
if (value != mTabWidth) {
mTabWidth = value;
mConvertTabsProc = GetBestConvertTabsProcEx(mTabWidth);
mIndexOfLongestLine = -1;
for (PSynEditStringRec& line:mList) {
line->fExpandedLength = -1;
line->fFlags = SynEditStringFlag::sfExpandedLengthUnknown;
}
}
}
int SynEditStringList::add(const QString &s)
{
@ -365,7 +351,6 @@ void SynEditStringList::putString(int Index, const QString &s) {
}
beginUpdate();
mIndexOfLongestLine = -1;
mList[Index]->fFlags = SynEditStringFlag::sfExpandedLengthUnknown;
mList[Index]->fString = s;
emit putted(Index,1);
endUpdate();
@ -390,24 +375,12 @@ void SynEditStringList::SetUpdateState(bool Updating)
emit changed();
}
QString SynEditStringList::ExpandString(int Index)
int SynEditStringList::calculateLineColumns(int Index)
{
QString Result("");
PSynEditStringRec line = mList[Index];
if (line->fString.isEmpty()) {
line->fFlags = SynEditStringFlag::sfHasNoTabs;
line->fExpandedLength = 0;
} else {
bool hasTabs;
Result = mConvertTabsProc(line->fString,mTabWidth,hasTabs);
line->fExpandedLength = Result.length();
if (hasTabs) {
line->fFlags = SynEditStringFlag::sfHasTabs;
} else {
line->fFlags = SynEditStringFlag::sfHasNoTabs;
}
}
return Result;
line->fColumns = mEdit->stringColumns(line->fString);
return line->fColumns;
}
void SynEditStringList::InsertLines(int Index, int NumLines)
@ -619,15 +592,22 @@ void SynEditStringList::setFileEndingType(const FileEndingType &fileEndingType)
mFileEndingType = fileEndingType;
}
void SynEditStringList::invalidAllLineColumns()
{
mIndexOfLongestLine = -1;
for (PSynEditStringRec& line:mList) {
line->fColumns = -1;
}
}
SynEditStringRec::SynEditStringRec():
fString(),
fObject(nullptr),
fRange{0,0},
fExpandedLength(-1),
fColumns(-1),
fParenthesisLevel(0),
fBracketLevel(0),
fBraceLevel(0),
fFlags(SynEditStringFlag::sfExpandedLengthUnknown)
fBraceLevel(0)
{
}

View File

@ -21,8 +21,7 @@ struct SynEditStringRec {
QString fString;
void * fObject;
SynRangeState fRange;
int fExpandedLength;
SynEditStringFlags fFlags;
int fColumns; //
int fParenthesisLevel;
int fBracketLevel;
int fBraceLevel;
@ -44,17 +43,18 @@ typedef std::shared_ptr<SynEditStringList> PSynEditStringList;
using StringListChangeCallback = std::function<void(PSynEditStringList* object, int index, int count)>;
class QFile;
class SynEdit;
class SynEditStringList : public QObject
{
Q_OBJECT
public:
explicit SynEditStringList(QObject* parent=nullptr);
explicit SynEditStringList(SynEdit* pEdit,QObject* parent=nullptr);
int parenthesisLevels(int Index);
int bracketLevels(int Index);
int braceLevels(int Index);
QString expandedStrings(int Index);
int expandedStringLength(int Index);
int lineColumns(int Index);
int lengthOfLongestLine();
SynRangeState ranges(int Index);
void setRange(int Index, SynRangeState ARange);
@ -73,8 +73,6 @@ public:
void beginUpdate();
void endUpdate();
int tabWidth();
void setTabWidth(int value);
int add(const QString& s);
int addStrings(const QStringList& Strings);
@ -97,6 +95,8 @@ public:
FileEndingType getFileEndingType() const;
void setFileEndingType(const FileEndingType &fileEndingType);
public slots:
void invalidAllLineColumns();
signals:
void changed();
@ -114,16 +114,16 @@ protected:
private:
SynEditStringRecList mList;
SynEdit* mEdit;
//int mCount;
//int mCapacity;
FileEndingType mFileEndingType;
bool mAppendNewLineAtEOF;
ConvertTabsProcEx mConvertTabsProc;
int mIndexOfLongestLine;
int mTabWidth;
int mUpdateCount;
QString ExpandString(int Index);
int calculateLineColumns(int Index);
};
enum class SynChangeReason {crInsert, crPaste, crDragDropInsert,

View File

@ -302,7 +302,8 @@ bool SynEditTextPainter::TokenIsSpaces(bool &bSpacesTest, const QString& Token,
// Store the token chars with the attributes in the TokenAccu
// record. This will paint any chars already stored if there is
// a (visible) change in the attributes.
void SynEditTextPainter::AddHighlightToken(const QString &Token, int ColumnsBefore, int TokenColumns, int cLine, PSynHighlighterAttribute p_Attri)
void SynEditTextPainter::AddHighlightToken(const QString &Token, int ColumnsBefore,
int TokenColumns, int cLine, PSynHighlighterAttribute p_Attri)
{
bool bCanAppend;
QColor Foreground, Background;
@ -463,240 +464,213 @@ void SynEditTextPainter::PaintLines()
// inside the loop. Get only the starting point for this.
rcLine = AClip;
rcLine.setBottom((aFirstRow - edit->mTopLine) * edit->mTextHeight);
// Make sure the token accumulator string doesn't get reassigned too often.
TokenAccu.Columns = 0;
TokenAccu.ColumnsBefore = 0;
if (fHighlighter) then begin
TokenAccu.MaxLen := Max(128, fCharsInWindow);
SetLength(TokenAccu.s, TokenAccu.MaxLen);
end;
// Now loop through all the lines. The indices are valid for Lines.
for cRow := aFirstRow to aLastRow do begin
vLine := RowToLine(cRow);
if (vLine > Lines.Count) and not (Lines.Count = 0) then
break;
for (cRow = aFirstRow; cRow<=aLastRow; cRow++) {
vLine = edit->rowToLine(cRow);
if (vLine > edit->mLines->count() && edit->mLines->count() != 0)
break;
// Get the expanded line.
sLine := Lines.ExpandedStrings[vLine - 1];
// determine whether will be painted with ActiveLineColor
bCurrentLine := CaretY = vLine;
// Initialize the text and background colors, maybe the line should
// use special values for them.
colFG := Font.Color;
colBG := colEditorBG;
bSpecialLine := DoOnSpecialLineColors(vLine, colFG, colBG);
if bSpecialLine then begin
// The selection colors are just swapped, like seen in Delphi.
colSelFG := colBG;
colSelBG := colFG;
end else begin
colSelFG := fSelectedColor.Foreground;
colSelBG := fSelectedColor.Background;
DoOnEditAreas(vLine, areaList,colBorder,areaType);
end;
// Removed word wrap support
vFirstChar := FirstCol;
vLastChar := LastCol;
// Get the information about the line selection. Three different parts
// are possible (unselected before, selected, unselected after), only
// unselected or only selected means bComplexLine will be FALSE. Start
// with no selection, compute based on the visible columns.
bComplexLine := FALSE;
nLineSelStart := 0;
nLineSelEnd := 0;
// Does the selection intersect the visible area?
if bAnySelection and (cRow >= vSelStart.Row) and (cRow <= vSelEnd.Row) then begin
// Default to a fully selected line. This is correct for the smLine
// selection mode and a good start for the smNormal mode.
nLineSelStart := FirstCol;
nLineSelEnd := LastCol + 1;
if (fActiveSelectionMode = smColumn) or
((fActiveSelectionMode = smNormal) and (cRow = vSelStart.Row)) then
if (vSelStart.Column > LastCol) then begin
nLineSelStart := 0;
nLineSelEnd := 0;
end else if (vSelStart.Column > FirstCol) then begin
nLineSelStart := vSelStart.Column;
bComplexLine := TRUE;
end;
if (fActiveSelectionMode = smColumn) or
((fActiveSelectionMode = smNormal) and (cRow = vSelEnd.Row)) then
if (vSelEnd.Column < FirstCol) then begin
nLineSelStart := 0;
nLineSelEnd := 0;
end else if (vSelEnd.Column < LastCol) then begin
nLineSelEnd := vSelEnd.Column;
bComplexLine := TRUE;
end;
{$IFDEF SYN_MBCSSUPPORT}
//todo: nLineSelStart & nLineSelEnd must be buffer coordinates
if (fActiveSelectionMode = smColumn) then
MBCSGetSelRangeInLineWhenColumnSelectionMode(sLine, nLineSelStart,
nLineSelEnd);
{$ENDIF}
end; //endif bAnySelection
// Update the rcLine rect to this line.
rcLine.Top := rcLine.Bottom;
Inc(rcLine.Bottom, fTextHeight);
bLineSelected := (not bComplexLine) and (nLineSelStart > 0);
rcToken := rcLine;
if not Assigned(fHighlighter) or (not fHighlighter.Enabled) then begin
// Remove text already displayed (in previous rows)
if (vFirstChar <> FirstCol) or (vLastChar <> LastCol) then
sToken := Copy(sLine, vFirstChar, vLastChar - vFirstChar)
else
sToken := sLine;
if fShowSpecChar and (not bLineSelected) and (not bSpecialLine) and (Length(sLine) < vLastChar) then
sToken := sToken + SynLineBreakGlyph;
nTokenLen := Length(sToken);
if bComplexLine then begin
SetDrawingColors(FALSE);
rcToken.Left := Max(rcLine.Left, ColumnToXValue(FirstCol));
rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelStart));
PaintToken(sToken, nTokenLen, 0, FirstCol, nLineSelStart,False);
rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelEnd));
rcToken.Right := Min(rcLine.Right, ColumnToXValue(LastCol));
PaintToken(sToken, nTokenLen, 0, nLineSelEnd, LastCol,True);
SetDrawingColors(TRUE);
rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelStart));
rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelEnd));
PaintToken(sToken, nTokenLen, 0, nLineSelStart, nLineSelEnd - 1,False);
end else begin
SetDrawingColors(bLineSelected);
PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol,bLineSelected);
end;
end else begin
// Initialize highlighter with line text and range info. It is
// necessary because we probably did not scan to the end of the last
// line - the internal highlighter range might be wrong.
if vLine = 1 then begin
fHighlighter.ResetRange;
fHighlighter.ResetParenthesisLevel;
fHighlighter.ResetBracketLevel;
fHighlighter.ResetBraceLevel;
end else begin
fHighlighter.SetRange(Lines.Ranges[vLine - 2]);
fHighlighter.SetParenthesisLevel(Lines.ParenthesisLevels[vLine - 2]);
fHighlighter.SetBracketLevel(Lines.BracketLevels[vLine - 2]);
fHighlighter.SetBraceLevel(Lines.BraceLevels[vLine - 2]);
end;
fHighlighter.SetLine(sLine, vLine - 1);
// Try to concatenate as many tokens as possible to minimize the count
// of ExtTextOut calls necessary. This depends on the selection state
// or the line having special colors. For spaces the foreground color
// is ignored as well.
TokenAccu.Len := 0;
nTokenPos := 0;
// Test first whether anything of this token is visible.
while not fHighlighter.GetEol do begin
sToken := fHighlighter.GetToken;
// Work-around buggy highlighters which return empty tokens.
if sToken = '' then begin
fHighlighter.Next;
if fHighlighter.GetEol then
break;
sToken := fHighlighter.GetToken;
// Maybe should also test whether GetTokenPos changed...
if sToken = '' then
raise Exception.Create('The highlighter seems to be in an infinite loop');
end;
nTokenPos := fHighlighter.GetTokenPos;
nTokenLen := Length(sToken);
if nTokenPos + nTokenLen >= vFirstChar then begin
if nTokenPos + nTokenLen >= vLastChar then begin
if nTokenPos >= vLastChar then
break; //*** BREAK ***
nTokenLen := vLastChar - nTokenPos - 1;
end;
// It's at least partially visible. Get the token attributes now.
attr := fHighlighter.GetTokenAttribute;
{
if (nTokenPos = 0) and (attr = fHighlighter.WhitespaceAttribute) then begin
sToken := StringOfChar('.',nTokenLen);
end;
// Get the line.
sLine = edit->mLines->getString(vLine - 1);
// determine whether will be painted with ActiveLineColor
bCurrentLine = (edit->mCaretY == vLine);
// Initialize the text and background colors, maybe the line should
// use special values for them.
colFG = edit->palette().color(QPalette::Text);
colBG = colEditorBG();
bSpecialLine = edit->DoOnSpecialLineColors(vLine, colFG, colBG);
if (bSpecialLine) {
// The selection colors are just swapped, like seen in Delphi.
colSelFG = colBG;
colSelBG = colFG;
} else {
colSelFG = edit->mSelectedForeground;
colSelBG = edit->mSelectedBackground;
}
edit->DoOnEditAreas(vLine, areaList);
// Removed word wrap support
vFirstChar = FirstCol;
vLastChar = LastCol;
// Get the information about the line selection. Three different parts
// are possible (unselected before, selected, unselected after), only
// unselected or only selected means bComplexLine will be FALSE. Start
// with no selection, compute based on the visible columns.
bComplexLine = false;
nLineSelStart = 0;
nLineSelEnd = 0;
// Does the selection intersect the visible area?
if (bAnySelection && (cRow >= vSelStart.Row) && (cRow <= vSelEnd.Row)) {
// Default to a fully selected line. This is correct for the smLine
// selection mode and a good start for the smNormal mode.
nLineSelStart = FirstCol;
nLineSelEnd = LastCol + 1;
if ((edit->mActiveSelectionMode == SynSelectionMode::smColumn) ||
((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelStart.Row)) ) {
if (vSelStart.Column > LastCol) {
nLineSelStart = 0;
nLineSelEnd = 0;
} else if (vSelStart.Column > FirstCol) {
nLineSelStart = vSelStart.Column;
bComplexLine = true;
}
}
if sToken = '[' then begin
GetBraceColorAttr(fHighlighter.GetBracketLevel,attr);
end else if sToken = ']' then begin
GetBraceColorAttr(fHighlighter.GetBracketLevel+1,attr);
end else if sToken = '(' then begin
GetBraceColorAttr(fHighlighter.GetParenthesisLevel,attr);
end else if sToken = ')' then begin
GetBraceColorAttr(fHighlighter.GetParenthesisLevel+1,attr);
end else if sToken = '{' then begin
GetBraceColorAttr(fHighlighter.GetBraceLevel,attr);
end else if sToken = '}' then begin
GetBraceColorAttr(fHighlighter.GetBraceLevel+1,attr);
end;
AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol),
nTokenLen, cRow,attr);
end;
// Let the highlighter scan the next token.
fHighlighter.Next;
end;
// Don't assume HL.GetTokenPos is valid after HL.GetEOL = True.
Inc(nTokenPos, Length(sToken));
if fHighlighter.GetEol and (nTokenPos < vLastChar) then begin
// Draw text that couldn't be parsed by the highlighter, if any.
if nTokenPos < Length(sLine) then begin
if nTokenPos + 1 < vFirstChar then
nTokenPos := vFirstChar - 1;
nTokenLen := Min(Length(sLine), vLastChar) - (nTokenPos + 1);
if nTokenLen > 0 then begin
sToken := Copy(sLine, nTokenPos + 1, nTokenLen);
AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol),
nTokenLen, cRow, nil);
end;
end;
// Draw LineBreak glyph.
if (eoShowSpecialChars in fOptions) and (not bLineSelected)
and (not bSpecialLine) and (Length(sLine) < vLastChar) then begin
AddHighlightToken(SynLineBreakGlyph,
Length(sLine) - (vFirstChar - FirstCol),
Length(SynLineBreakGlyph),cRow, fHighLighter.WhitespaceAttribute);
end;
end;
if ( (edit->mActiveSelectionMode == SynSelectionMode::smColumn) ||
((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelEnd.Row)) ) {
if (vSelEnd.Column < FirstCol) {
nLineSelStart = 0;
nLineSelEnd = 0;
} else if (vSelEnd.Column < LastCol) {
nLineSelEnd = vSelEnd.Column;
bComplexLine = true;
}
}
} //endif bAnySelection
// Paint folding
foldRange := FoldStartAtLine(vLine);
if assigned(foldRange) and foldRange.Collapsed then begin
sFold := ' ... }';
nFold := Length(sFold);
Attr := fHighlighter.SymbolAttribute;
GetBraceColorAttr(fHighlighter.GetBraceLevel,attr);
AddHighlightToken(sFold,Length(sLine)+1 - (vFirstChar - FirstCol)
, nFold, cRow, attr);
// Compute some helper variables.
//nC1 := Max(FirstCol, Length(sLine)+1);
//nC2 := Min(LastCol, Length(sLine) +1 + nFold + 1);
//SetDrawingColors(FALSE);
//PaintToken(sFold,nFold, Length(sLine)+1,nC1, nC2);
end;
// Update the rcLine rect to this line.
rcLine.setTop(rcLine.bottom());
rcLine.setBottom(rcLine.bottom()+edit->mTextHeight);
// Draw anything that's left in the TokenAccu record. Fill to the end
// of the invalid area with the correct colors.
PaintHighlightToken(TRUE);
bLineSelected = (!bComplexLine) && (nLineSelStart > 0);
rcToken = rcLine;
if (!edit->mHighlighter || !edit->mHighlighter->enabled()) {
sToken = sLine;
nTokenLen = edit->mLines->lineColumns(vLine-1);
if (edit->mShowSpecChar && (!bLineSelected) && (!bSpecialLine) && (nTokenLen < vLastChar)) {
sToken = sToken + SynLineBreakGlyph;
nTokenLen = sToken + edit->charColumns(SynLineBreakGlyph);
}
if (bComplexLine) {
setDrawingColors(false);
rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(FirstCol)));
rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(nLineSelStart)));
PaintToken(sToken, nTokenLen, 0, FirstCol, nLineSelStart,false);
rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(nLineSelEnd)));
rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(LastCol)));
PaintToken(sToken, nTokenLen, 0, nLineSelEnd, LastCol,true);
setDrawingColors(false);
rcToken.setLeft(std::max(rcLine.left(), ColumnToXValue(nLineSelStart)));
rcToken.setRight(std::min(rcLine.right(), ColumnToXValue(nLineSelEnd)));
PaintToken(sToken, nTokenLen, 0, nLineSelStart, nLineSelEnd - 1,false);
} else {
setDrawingColors(bLineSelected);
PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol,bLineSelected);
}
} else {
// Initialize highlighter with line text and range info. It is
// necessary because we probably did not scan to the end of the last
// line - the internal highlighter range might be wrong.
if (vLine == 1) {
edit->mHighlighter->resetState();
} else {
edit->mHighlighter->setState(
edit->mLines->ranges(vLine-2),
edit->mLines->braceLevels(vLine-2),
edit->mLines->bracketLevels(vLine-2),
edit->mLines->parenthesisLevels(vLine-2)
);
edit->mHighlighter->setLine(sLine, vLine - 1);
}
// Try to concatenate as many tokens as possible to minimize the count
// of ExtTextOut calls necessary. This depends on the selection state
// or the line having special colors. For spaces the foreground color
// is ignored as well.
TokenAccu.Columns = 0;
nTokenPos = 0;
// Test first whether anything of this token is visible.
while (edit->mHighlighter->eol()) {
sToken = edit->mHighlighter->getToken();
// Work-around buggy highlighters which return empty tokens.
if (sToken.isEmpty()) {
edit->mHighlighter->next();
if (edit->mHighlighter->eol())
break;
sToken = edit->mHighlighter->getToken();
// Maybe should also test whether GetTokenPos changed...
if (sToken.isEmpty())
throw BaseError(SynEdit::tr("The highlighter seems to be in an infinite loop"));
}
nTokenPos = edit->charToColumn(vLine,edit->mHighlighter->getTokenPos());
nTokenLen = edit->stringColumns(sToken);
if (nTokenPos + nTokenLen >= vFirstChar) {
if (nTokenPos + nTokenLen >= vLastChar) {
if (nTokenPos >= vLastChar)
break; //*** BREAK ***
nTokenLen = vLastChar - nTokenPos - 1;
}
// It's at least partially visible. Get the token attributes now.
attr = edit->mHighlighter->getTokenAttribute();
if (sToken == "[") {
GetBraceColorAttr(edit->mHighlighter->getBracketLevel(),attr);
} else if (sToken == "]") {
GetBraceColorAttr(edit->mHighlighter->getBracketLevel()+1,attr);
} else if (sToken == "(") {
GetBraceColorAttr(edit->mHighlighter->getParenthesisLevel(),attr);
} else if (sToken == ")") {
GetBraceColorAttr(edit->mHighlighter->getParenthesisLevel()+1,attr);
} else if (sToken == "{") {
GetBraceColorAttr(edit->mHighlighter->getBraceLevel(),attr);
} else if (sToken == "}") {
GetBraceColorAttr(edit->mHighlighter->getBraceLevel()+1,attr);
}
AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol),
nTokenLen, vLine,attr);
}
// Let the highlighter scan the next token.
edit->mHighlighter->next();
}
// Don't assume HL.GetTokenPos is valid after HL.GetEOL == True.
nTokenPos += edit->stringColumns(sToken);
if (edit->mHighlighter->eol() && (nTokenPos < vLastChar)) {
int lineColumns = edit->mLines->lineColumns(vLine-1);
// Draw text that couldn't be parsed by the highlighter, if any.
if (nTokenPos < lineColumns) {
if (nTokenPos + 1 < vFirstChar)
nTokenPos = vFirstChar - 1;
nTokenLen = std::min(lineColumns, vLastChar) - (nTokenPos + 1);
if (nTokenLen > 0) {
sToken = edit->subStringByColumns(sLine,nTokenPos+1,nTokenLen);
AddHighlightToken(sToken, nTokenPos - (vFirstChar - FirstCol),
edit->stringColumns(sToken), vLine, PSynHighlighterAttribute());
}
}
// Draw LineBreak glyph.
if (edit->mShowSpecChar && (!bLineSelected) &&
(!bSpecialLine) && (edit->mLines->lineColumns(vLine-1) < vLastChar)) {
AddHighlightToken(SynLineBreakGlyph,
edit->mLines->lineColumns(vLine-1) - (vFirstChar - FirstCol),
edit->charColumns(SynLineBreakGlyph),vLine, edit->mHighlighter->whitespaceAttribute());
}
}
//Paint editingAreaBorders
PaintEditAreas(areaList,colBorder,areaType);
// Paint folding
foldRange = edit->foldStartAtLine(vLine);
if ((foldRange) && foldRange->collapsed) {
sFold = " ... } ";
nFold = edit->stringColumns(sFold);
attr = edit->mHighlighter->symbolAttribute();
GetBraceColorAttr(edit->mHighlighter->getBraceLevel(),attr);
AddHighlightToken(sFold,edit->mLines->lineColumns(vLine-1)+1 - (vFirstChar - FirstCol)
, nFold, vLine, attr);
}
end;
// Draw anything that's left in the TokenAccu record. Fill to the end
// of the invalid area with the correct colors.
PaintHighlightToken(true);
// Now paint the right edge if necessary. We do it line by line to reduce
// the flicker. Should not cost very much anyway, compared to the many
// calls to ExtTextOut.
if bDoRightEdge then begin
Canvas.MoveTo(nRightEdge, rcLine.Top);
Canvas.LineTo(nRightEdge, rcLine.Bottom + 1);
end;
bCurrentLine := False;
end; //endfor cRow
//Paint editingAreaBorders
PaintEditAreas(areaList);
}
// Now paint the right edge if necessary. We do it line by line to reduce
// the flicker. Should not cost very much anyway, compared to the many
// calls to ExtTextOut.
if (bDoRightEdge) {
painter->paintEngine(nRightEdge, rcLine.top(),nRightEdge,rcLine.bottom()+1);
}
bCurrentLine = false;
}
}

View File

@ -6,6 +6,7 @@
#include <QString>
#include "Types.h"
#include "highlighter/base.h"
#include "../utils.h"
class SynEdit;
class SynEditTextPainter
@ -35,7 +36,7 @@ public:
int cLine, PSynHighlighterAttribute p_Attri);
void PaintFoldAttributes();
void GetBraceColorAttr(int level, const PSynHighlighterAttribute& attr);
void GetBraceColorAttr(int level, PSynHighlighterAttribute &attr);
void PaintLines();
private:
SynEdit* edit;

View File

@ -161,6 +161,19 @@ PSynHighlighterAttribute SynHighlighter::getAttribute(const QString &name) const
return PSynHighlighterAttribute();
}
bool SynHighlighter::enabled() const
{
return mEnabled;
}
void SynHighlighter::setEnabled(bool value)
{
if (value != mEnabled) {
mEnabled = value;
setAttributesChanged();
}
}
void SynHighlighterAttribute::setChanged()
{
emit changed();

View File

@ -112,6 +112,9 @@ public:
virtual QString languageName();
static bool isSpaceChar(const QChar& ch);
bool enabled() const;
void setEnabled(bool value);
signals:
void attributesChanged();

View File

@ -1,5 +1,5 @@
TEMPLATE = subdirs
SUBDIRS += \
../QScintilla/src/qscintilla.pro \
# ../QScintilla/src/qscintilla.pro \
RedPandaIDE