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 SynEdit::bufferToDisplayPos(const BufferCoord &p)
{ {
DisplayCoord result {p.Char,p.Line}; DisplayCoord result {p.Char,p.Line};
// Account for tabs // Account for tabs and charColumns
if (p.Line-1 < mLines->count()) { result.Column = charToColumn(p.Line,p.Char);
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 code folding // Account for code folding
if (mUseCodeFolding) if (mUseCodeFolding)
result.Row = foldLineToRow(result.Row); 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) int SynEdit::rowToLine(int aRow)
{ {
return displayToBufferPos({1, aRow}).Line; return displayToBufferPos({1, aRow}).Line;
@ -1278,6 +1302,11 @@ void SynEdit::doChange()
emit Changed(); emit Changed();
} }
int SynEdit::tabWidth() const
{
return mTabWidth;
}
void SynEdit::paintEvent(QPaintEvent *event) void SynEdit::paintEvent(QPaintEvent *event)
{ {
if (mPainterLock>0) if (mPainterLock>0)

View File

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

View File

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

View File

@ -21,8 +21,7 @@ struct SynEditStringRec {
QString fString; QString fString;
void * fObject; void * fObject;
SynRangeState fRange; SynRangeState fRange;
int fExpandedLength; int fColumns; //
SynEditStringFlags fFlags;
int fParenthesisLevel; int fParenthesisLevel;
int fBracketLevel; int fBracketLevel;
int fBraceLevel; int fBraceLevel;
@ -44,17 +43,18 @@ typedef std::shared_ptr<SynEditStringList> PSynEditStringList;
using StringListChangeCallback = std::function<void(PSynEditStringList* object, int index, int count)>; using StringListChangeCallback = std::function<void(PSynEditStringList* object, int index, int count)>;
class QFile; class QFile;
class SynEdit;
class SynEditStringList : public QObject class SynEditStringList : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit SynEditStringList(QObject* parent=nullptr); explicit SynEditStringList(SynEdit* pEdit,QObject* parent=nullptr);
int parenthesisLevels(int Index); int parenthesisLevels(int Index);
int bracketLevels(int Index); int bracketLevels(int Index);
int braceLevels(int Index); int braceLevels(int Index);
QString expandedStrings(int Index); int lineColumns(int Index);
int expandedStringLength(int Index);
int lengthOfLongestLine(); int lengthOfLongestLine();
SynRangeState ranges(int Index); SynRangeState ranges(int Index);
void setRange(int Index, SynRangeState ARange); void setRange(int Index, SynRangeState ARange);
@ -73,8 +73,6 @@ public:
void beginUpdate(); void beginUpdate();
void endUpdate(); void endUpdate();
int tabWidth();
void setTabWidth(int value);
int add(const QString& s); int add(const QString& s);
int addStrings(const QStringList& Strings); int addStrings(const QStringList& Strings);
@ -97,6 +95,8 @@ public:
FileEndingType getFileEndingType() const; FileEndingType getFileEndingType() const;
void setFileEndingType(const FileEndingType &fileEndingType); void setFileEndingType(const FileEndingType &fileEndingType);
public slots:
void invalidAllLineColumns();
signals: signals:
void changed(); void changed();
@ -114,16 +114,16 @@ protected:
private: private:
SynEditStringRecList mList; SynEditStringRecList mList;
SynEdit* mEdit;
//int mCount; //int mCount;
//int mCapacity; //int mCapacity;
FileEndingType mFileEndingType; FileEndingType mFileEndingType;
bool mAppendNewLineAtEOF; bool mAppendNewLineAtEOF;
ConvertTabsProcEx mConvertTabsProc; ConvertTabsProcEx mConvertTabsProc;
int mIndexOfLongestLine; int mIndexOfLongestLine;
int mTabWidth;
int mUpdateCount; int mUpdateCount;
QString ExpandString(int Index); int calculateLineColumns(int Index);
}; };
enum class SynChangeReason {crInsert, crPaste, crDragDropInsert, 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 // Store the token chars with the attributes in the TokenAccu
// record. This will paint any chars already stored if there is // record. This will paint any chars already stored if there is
// a (visible) change in the attributes. // 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; bool bCanAppend;
QColor Foreground, Background; QColor Foreground, Background;
@ -463,240 +464,213 @@ void SynEditTextPainter::PaintLines()
// inside the loop. Get only the starting point for this. // inside the loop. Get only the starting point for this.
rcLine = AClip; rcLine = AClip;
rcLine.setBottom((aFirstRow - edit->mTopLine) * edit->mTextHeight); rcLine.setBottom((aFirstRow - edit->mTopLine) * edit->mTextHeight);
// Make sure the token accumulator string doesn't get reassigned too often.
TokenAccu.Columns = 0; TokenAccu.Columns = 0;
TokenAccu.ColumnsBefore = 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. // Now loop through all the lines. The indices are valid for Lines.
for cRow := aFirstRow to aLastRow do begin for (cRow = aFirstRow; cRow<=aLastRow; cRow++) {
vLine := RowToLine(cRow); vLine = edit->rowToLine(cRow);
if (vLine > Lines.Count) and not (Lines.Count = 0) then if (vLine > edit->mLines->count() && edit->mLines->count() != 0)
break; break;
// Get the expanded line. // Get the line.
sLine := Lines.ExpandedStrings[vLine - 1]; sLine = edit->mLines->getString(vLine - 1);
// determine whether will be painted with ActiveLineColor // determine whether will be painted with ActiveLineColor
bCurrentLine := CaretY = vLine; bCurrentLine = (edit->mCaretY == vLine);
// Initialize the text and background colors, maybe the line should // Initialize the text and background colors, maybe the line should
// use special values for them. // use special values for them.
colFG := Font.Color; colFG = edit->palette().color(QPalette::Text);
colBG := colEditorBG; colBG = colEditorBG();
bSpecialLine := DoOnSpecialLineColors(vLine, colFG, colBG); bSpecialLine = edit->DoOnSpecialLineColors(vLine, colFG, colBG);
if bSpecialLine then begin if (bSpecialLine) {
// The selection colors are just swapped, like seen in Delphi. // The selection colors are just swapped, like seen in Delphi.
colSelFG := colBG; colSelFG = colBG;
colSelBG := colFG; colSelBG = colFG;
end else begin } else {
colSelFG := fSelectedColor.Foreground; colSelFG = edit->mSelectedForeground;
colSelBG := fSelectedColor.Background; colSelBG = edit->mSelectedBackground;
DoOnEditAreas(vLine, areaList,colBorder,areaType); }
end; edit->DoOnEditAreas(vLine, areaList);
// Removed word wrap support
// Removed word wrap support vFirstChar = FirstCol;
vFirstChar := FirstCol; vLastChar = LastCol;
vLastChar := LastCol; // Get the information about the line selection. Three different parts
// are possible (unselected before, selected, unselected after), only
// Get the information about the line selection. Three different parts // unselected or only selected means bComplexLine will be FALSE. Start
// are possible (unselected before, selected, unselected after), only // with no selection, compute based on the visible columns.
// unselected or only selected means bComplexLine will be FALSE. Start bComplexLine = false;
// with no selection, compute based on the visible columns. nLineSelStart = 0;
bComplexLine := FALSE; nLineSelEnd = 0;
nLineSelStart := 0; // Does the selection intersect the visible area?
nLineSelEnd := 0; if (bAnySelection && (cRow >= vSelStart.Row) && (cRow <= vSelEnd.Row)) {
// Does the selection intersect the visible area? // Default to a fully selected line. This is correct for the smLine
if bAnySelection and (cRow >= vSelStart.Row) and (cRow <= vSelEnd.Row) then begin // selection mode and a good start for the smNormal mode.
// Default to a fully selected line. This is correct for the smLine nLineSelStart = FirstCol;
// selection mode and a good start for the smNormal mode. nLineSelEnd = LastCol + 1;
nLineSelStart := FirstCol; if ((edit->mActiveSelectionMode == SynSelectionMode::smColumn) ||
nLineSelEnd := LastCol + 1; ((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelStart.Row)) ) {
if (fActiveSelectionMode = smColumn) or if (vSelStart.Column > LastCol) {
((fActiveSelectionMode = smNormal) and (cRow = vSelStart.Row)) then nLineSelStart = 0;
if (vSelStart.Column > LastCol) then begin nLineSelEnd = 0;
nLineSelStart := 0; } else if (vSelStart.Column > FirstCol) {
nLineSelEnd := 0; nLineSelStart = vSelStart.Column;
end else if (vSelStart.Column > FirstCol) then begin bComplexLine = true;
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;
} }
if sToken = '[' then begin if ( (edit->mActiveSelectionMode == SynSelectionMode::smColumn) ||
GetBraceColorAttr(fHighlighter.GetBracketLevel,attr); ((edit->mActiveSelectionMode == SynSelectionMode::smNormal) && (cRow == vSelEnd.Row)) ) {
end else if sToken = ']' then begin if (vSelEnd.Column < FirstCol) {
GetBraceColorAttr(fHighlighter.GetBracketLevel+1,attr); nLineSelStart = 0;
end else if sToken = '(' then begin nLineSelEnd = 0;
GetBraceColorAttr(fHighlighter.GetParenthesisLevel,attr); } else if (vSelEnd.Column < LastCol) {
end else if sToken = ')' then begin nLineSelEnd = vSelEnd.Column;
GetBraceColorAttr(fHighlighter.GetParenthesisLevel+1,attr); bComplexLine = true;
end else if sToken = '{' then begin }
GetBraceColorAttr(fHighlighter.GetBraceLevel,attr); }
end else if sToken = '}' then begin } //endif bAnySelection
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;
// Paint folding // Update the rcLine rect to this line.
foldRange := FoldStartAtLine(vLine); rcLine.setTop(rcLine.bottom());
if assigned(foldRange) and foldRange.Collapsed then begin rcLine.setBottom(rcLine.bottom()+edit->mTextHeight);
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;
// Draw anything that's left in the TokenAccu record. Fill to the end bLineSelected = (!bComplexLine) && (nLineSelStart > 0);
// of the invalid area with the correct colors. rcToken = rcLine;
PaintHighlightToken(TRUE); 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 // Paint folding
PaintEditAreas(areaList,colBorder,areaType); 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 //Paint editingAreaBorders
// the flicker. Should not cost very much anyway, compared to the many PaintEditAreas(areaList);
// calls to ExtTextOut. }
if bDoRightEdge then begin
Canvas.MoveTo(nRightEdge, rcLine.Top); // Now paint the right edge if necessary. We do it line by line to reduce
Canvas.LineTo(nRightEdge, rcLine.Bottom + 1); // the flicker. Should not cost very much anyway, compared to the many
end; // calls to ExtTextOut.
bCurrentLine := False; if (bDoRightEdge) {
end; //endfor cRow painter->paintEngine(nRightEdge, rcLine.top(),nRightEdge,rcLine.bottom()+1);
}
bCurrentLine = false;
}
} }

View File

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

View File

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

View File

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

View File

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