SynEdit: MarkupFoldColor, improve performance

git-svn-id: trunk@58578 -
This commit is contained in:
martin 2018-07-19 15:27:31 +00:00
parent de1e87aabd
commit 381de68567

View File

@ -50,10 +50,10 @@ interface
uses
Classes, SysUtils, Graphics, SynEditMarkup, SynEditMiscClasses, Controls,
LCLProc, LCLType, SynEditFoldedView, SynEditHighlighter,
SynEditHighlighterFoldBase, LazSynEditText
LCLProc, LCLType, SynEditHighlighter,
SynEditHighlighterFoldBase, LazSynEditText, SynEditTextBase
{$IFDEF WithSynMarkupFoldColorDebugGutter}, SynGutterBase, SynTextDrawer{$ENDIF}
;
;
type
@ -79,12 +79,33 @@ type
Border : Boolean;
Ignore : Boolean; //no color no line
SrcNode : TSynFoldNodeInfo;
LevelBefore, Level, LevelAfter : integer; //needed by non nest nodes
Level, LevelAfter : integer; //needed by non nest nodes
end;
TMarkupFoldColorInfos = array of TMarkupFoldColorInfo;
TSynFoldNodeInfos = array of TSynFoldNodeInfo; //for quick compare detection
TColumnCacheEntry = Integer;
PColumnCacheEntry = ^TColumnCacheEntry;
{ TSynEditMarkupFoldColorsColumnCache }
TSynEditMarkupFoldColorsColumnCache = class(TSynManagedStorageMem)
private
function GetColumnData(Index: Integer): TColumnCacheEntry;
function GetIsValidForLine(Index: Integer): Boolean;
procedure SetColumnData(Index: Integer; AValue: TColumnCacheEntry);
protected
procedure LineTextChanged(AIndex: Integer; ACount: Integer = 1); override;
procedure InsertedLines(AIndex, ACount: Integer); override;
//procedure DeletedLines(AIndex, ACount: Integer); override;
procedure Invalidate;
public
constructor Create;
property ColumnData[Index: Integer]: TColumnCacheEntry read GetColumnData write SetColumnData; default;
property IsValidForLine[Index: Integer]: Boolean read GetIsValidForLine;
end;
{ TSynEditMarkupFoldColors }
TSynEditMarkupFoldColors = class(TSynEditMarkup)
@ -93,17 +114,15 @@ type
FDebugGutter: TIDESynMarkupFoldColorDebugGutter;
{$ENDIF}
fUpdateColors: Boolean;
function GetFirstCharacterColumn(pIndex: Integer): Byte;
function GetFirstCharacterColumn(pIndex: Integer): TColumnCacheEntry;
procedure TextBufferChanged(pSender: TObject);
private
fHighlighter: TSynCustomFoldHighlighter;
fMarkupColors: array of TSynSelectedColor;
fNestList: TLazSynEditNestedFoldsList;
fNestList, fNestList2: TLazSynEditNestedFoldsList;
// cache
fFirstCharacterPhysColCache: Array of Byte;
fCacheCount,
fCacheCapacity,
FColumnCache: TSynEditMarkupFoldColorsColumnCache;
fFoldColorInfosCount,
fFoldColorInfosCapacity: Integer;
@ -112,32 +131,23 @@ type
fColors : array of TColor;
fPreparedRow: integer;
fLastNode,
fLastOpenNode: TSynFoldNodeInfo;
fLastIndex,
fLastOpenIndex: Integer;
fLastEnabled: Boolean;
fFirstInvalidCacheLine, fLastInvalidCacheLine: integer;
fUpdateCache: Boolean;
procedure DoMarkupParentFoldAtRow(pRow: Integer);
procedure DoMarkupParentCloseFoldAtRow(pRow: Integer);
function GetColor(pIndex: Integer): TSynSelectedColor;
procedure SetDefaultGroup(pValue: integer);
procedure SetCacheCount(pNewCount: Integer);
procedure SetFoldColorInfosCount(pNewCount: Integer);
procedure InitCache;
procedure ClearCache;
procedure UpdateCache;
procedure UpdateCacheRange(pFrom, pTo: Integer);
procedure InitNestList;
procedure UpdateColors;
property FirstCharacterColumn[pIindex: Integer]: Byte read GetFirstCharacterColumn;
property FirstCharacterColumn[pIindex: Integer]: TColumnCacheEntry read GetFirstCharacterColumn;
protected
// Notifications about Changes to the text
procedure DoTextChanged({%H-}pStartLine, pEndLine, {%H-}pCountDiff: Integer); override; // 1 based
procedure SetLines(const pValue: TSynEditStrings); override;
procedure LinesChanged(pSender: TSynEditStrings; pIndex, pCount: Integer);
procedure HighlightChanged(pSender: TSynEditStrings; pIndex, pCount: Integer);
procedure DoEnabledChanged(pSender: TObject); override;
procedure ColorChanged(pMarkup: TObject);
@ -169,6 +179,58 @@ uses
{$endif}
Dialogs;
{ TSynEditMarkupFoldColorsColumnCache }
function TSynEditMarkupFoldColorsColumnCache.GetColumnData(Index: Integer
): TColumnCacheEntry;
begin
Result := PColumnCacheEntry(ItemPointer[Index])^;
end;
function TSynEditMarkupFoldColorsColumnCache.GetIsValidForLine(Index: Integer
): Boolean;
begin
Result := PColumnCacheEntry(ItemPointer[Index])^ > 0;
end;
procedure TSynEditMarkupFoldColorsColumnCache.SetColumnData(Index: Integer;
AValue: TColumnCacheEntry);
begin
PColumnCacheEntry(ItemPointer[Index])^ := AValue;
end;
procedure TSynEditMarkupFoldColorsColumnCache.LineTextChanged(AIndex: Integer;
ACount: Integer);
var
i: Integer;
begin
for i := AIndex to AIndex + ACount - 1 do
ColumnData[i] := 0;
end;
procedure TSynEditMarkupFoldColorsColumnCache.InsertedLines(AIndex,
ACount: Integer);
var
i: Integer;
begin
for i := AIndex to AIndex + ACount - 1 do
ColumnData[i] := 0;
end;
procedure TSynEditMarkupFoldColorsColumnCache.Invalidate;
var
i: Integer;
begin
for i := 0 to Count - 1 do
ColumnData[i] := 0;
end;
constructor TSynEditMarkupFoldColorsColumnCache.Create;
begin
inherited;
ItemSize := SizeOf(TColumnCacheEntry);
end;
{$IFDEF WithSynMarkupFoldColorDebugGutter}
{ TIDESynMarkupFoldColorDebugGutter }
@ -217,13 +279,13 @@ begin
+ IntToStr(PhysX) + ',' + IntToStr(PhysX2) + ',' + IntToStr(PhysCol) + '/'
+ IntToStr(ColorIdx) + '/'
+ BoolToStr(Border, True)[1] + BoolToStr(Ignore, True)[1] + '/'
+ IntToStr(Level) + ',' + IntToStr(LevelBefore) + ',' + IntToStr(LevelAfter)
+ IntToStr(Level) + ',' + IntToStr(LevelAfter)
+ ') ';
while length(s) < 21 * (j+1) do s := s + ' ';
end;
s := IntToStr(FOwner.fFoldColorInfosCount) + s;
if iLine < length(FOwner.fFirstCharacterPhysColCache) then
s := s + ', '+IntToStr(FOwner.fFirstCharacterPhysColCache[ToIdx(iLine)]);
if iLine < FOwner.FColumnCache.Count then
s := s + ', '+IntToStr(FOwner.FColumnCache[ToIdx(iLine)]);
TextDrawer.ExtTextOut(rcLine.Left, rcLine.Top, ETO_OPAQUE or ETO_CLIPPED, rcLine,
PChar(Pointer(S)),Length(S));
@ -258,10 +320,7 @@ begin
FDebugGutter.FOwner := Self;
{$ENDIF}
fCacheCapacity := 0;
SetCacheCount(100);
fFirstInvalidCacheLine := -1;
fLastInvalidCacheLine := -1;
FColumnCache := TSynEditMarkupFoldColorsColumnCache.Create;
fHighlighter := TSynCustomFoldHighlighter(TCustomSynEdit(SynEdit).Highlighter);
if Assigned(fHighlighter)
@ -279,6 +338,13 @@ begin
fNestList.FoldFlags := [sfbIncludeDisabled];
fNestList.IncludeOpeningOnLine := True;
// for scanning the "if" of a "then" to find the indent
fNestList2 := TLazSynEditNestedFoldsList.Create(Lines, fHighlighter);
fNestList2.ResetFilter;
fNestList2.FoldGroup := fDefaultGroup;
fNestList2.FoldFlags := [sfbIncludeDisabled];
fNestList2.IncludeOpeningOnLine := False;
SetLength(fMarkupColors, 10);
for i := 0 to length(fMarkupColors) - 1 do begin
fMarkupColors[i] := TSynSelectedColor.Create;
@ -309,14 +375,18 @@ destructor TSynEditMarkupFoldColors.Destroy;
var
i: Integer;
begin
if Lines <> nil then
Lines.Ranges[Self] := nil;
FColumnCache.Free;
for i := 0 to Length(fMarkupColors) - 1 do
fMarkupColors[i].Free;
if Assigned(Lines) then begin
Lines.RemoveChangeHandler(senrLineCount, @LinesChanged);
Lines.RemoveChangeHandler(senrHighlightChanged, @HighlightChanged);
Lines.RemoveNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
end;
FreeAndNil(fNestList);
FreeAndNil(fNestList2);
inherited Destroy;
end;
@ -329,6 +399,7 @@ begin
if not Assigned(fHighlighter) then
exit;
fNestList.Clear; // for next markup start
fNestList2.Clear;
if fUpdateColors then
UpdateColors;
end;
@ -403,7 +474,8 @@ begin
end;
end;
function TSynEditMarkupFoldColors.GetFirstCharacterColumn(pIndex: Integer): Byte;
function TSynEditMarkupFoldColors.GetFirstCharacterColumn(pIndex: Integer
): TColumnCacheEntry;
var
l: String;
s, p: Integer;
@ -414,29 +486,35 @@ begin
while (p <= s)
//and (l[p] in [#9, #32, '/']) do inc(p);
and (l[p] in [#9, #32]) do inc(p);
if (p > 255) or (p > s) then p := 255;
Result := Min(TCustomSynEdit(SynEdit).LogicalToPhysicalPos(Point(p, toPos(pIndex))).x, 255);
if p > s then
exit(high(Result));
Result := TCustomSynEdit(SynEdit).LogicalToPhysicalPos(Point(p, toPos(pIndex))).x;
end;
procedure TSynEditMarkupFoldColors.TextBufferChanged(pSender: TObject);
begin
if not Enabled then
exit;
InitCache;
InitNestList;
if pSender <> nil then
TSynEditStrings(pSender).Ranges[Self] := nil;
FColumnCache.Capacity := SynEdit.Lines.Capacity;
FColumnCache.Count := SynEdit.Lines.Count;
Lines.Ranges[Self] := FColumnCache;
FColumnCache.Invalidate;
end;
procedure TSynEditMarkupFoldColors.DoMarkupParentFoldAtRow(pRow: Integer);
var
lNodeCol: Byte;
lNodeCol: TColumnCacheEntry;
i, lLvl, lLineIdx, lCurIndex: Integer;
lCurNode: TSynFoldNodeInfo;
procedure AddVerticalLine;
begin
if fFirstCharacterPhysColCache[lCurNode.LineIndex] = 0 then
fFirstCharacterPhysColCache[lCurNode.LineIndex] := FirstCharacterColumn[lCurNode.LineIndex];
lNodeCol := fFirstCharacterPhysColCache[lCurNode.LineIndex];
with fFoldColorInfos[lCurIndex] do begin
SrcNode:= lCurNode; //needed by close node
PhysCol := lNodeCol;
@ -455,25 +533,55 @@ var
end;
end;
var
lvlB, lvlA: Integer;
lKeepLevel: Boolean;
procedure InitColumnForKeepLvl(LineIdx, FoldGroup: Integer);
var
LevelOpenNode: TSynFoldNodeInfo;
i, ONodeFirstCol: integer;
begin
ONodeFirstCol := FirstCharacterColumn[LineIdx];
FColumnCache[LineIdx] := ONodeFirstCol;
if ONodeFirstCol = 1 then
exit;
fNestList2.Line := LineIdx;
fNestList2.FoldGroup := FoldGroup;
if fNestList2.Count = 0 then
exit;
LevelOpenNode := fNestList2.HLNode[fNestList2.Count-1];
if sfaInvalid in LevelOpenNode.FoldAction then
exit; // try node before ??
if not (sfaOutlineKeepLevel in LevelOpenNode.FoldAction) then
exit;
if not FColumnCache.IsValidForLine[LevelOpenNode.LineIndex] then begin
InitColumnForKeepLvl(LevelOpenNode.LineIndex, FoldGroup);
if not FColumnCache.IsValidForLine[LevelOpenNode.LineIndex] then begin
exit;
end;
end;
i := FColumnCache[LevelOpenNode.LineIndex];
FColumnCache[LineIdx] := min(i, ONodeFirstCol);
end;
var
lKeepLevel: Boolean;
LastNode: TSynFoldNodeInfo;
begin
lLineIdx := ToIdx(pRow);
fNestList.Line := lLineIdx;
fHighlighter.CurrentLines := Lines;
LastNode.LineIndex := -1;
// get first character for current line
if fFirstCharacterPhysColCache[lLineIdx] = 0 then
fFirstCharacterPhysColCache[lLineIdx] := FirstCharacterColumn[lLineIdx];
if not FColumnCache.IsValidForLine[lLineIdx] then
FColumnCache[lLineIdx] := FirstCharacterColumn[lLineIdx];
lLvl := 0;
i := 0;
i := 0; // starting at the node with the lowest line number
while i < fNestList.Count do begin
lCurNode := fNestList.HLNode[i];
// sanity check
Assert(fCacheCapacity > lCurNode.LineIndex, 'TSynEditMarkupFoldColors.DoMarkupParentFoldAtRow: cache arrays too small');
Assert(sfaOpen in lCurNode.FoldAction, 'no sfaOpen in lCurNode.FoldAction');
{$IFDEF SynEditMarkupFoldColoringDebug}
//DebugLn(' O: %s %s %s', [IfThen(sfaOutline in lCurNode.FoldAction, 'X', '-'), IfThen(sfaClose in lCurNode.FoldAction, 'C ', IfThen(sfaOpen in lCurNode.FoldAction, 'O ', '??')),FoldTypeToStr(lCurNode.FoldType)]);
@ -481,17 +589,12 @@ begin
if (sfaOutline in lCurNode.FoldAction)
and not (sfaInvalid in lCurNode.FoldAction)
and (lCurNode.LineIndex <> lLineIdx) then begin
lvlB := lLvl;
if ( sfaOutlineForceIndent in lCurNode.FoldAction) then
inc(lLvl)
else if ( sfaOutlineMergeParent in lCurNode.FoldAction) then
dec(lLvl);
if fFirstCharacterPhysColCache[lCurNode.LineIndex] = 0 then
fFirstCharacterPhysColCache[lCurNode.LineIndex] := FirstCharacterColumn[lCurNode.LineIndex];
lNodeCol := fFirstCharacterPhysColCache[lCurNode.LineIndex];
// new FoldColorInfo
SetFoldColorInfosCount(fFoldColorInfosCount + 1);
lCurIndex := fFoldColorInfosCount - 1;
@ -501,17 +604,28 @@ begin
// DebugLn(' %s %s - %s %s', [FoldTypeToStr(fLastOpenNode.FoldType), IfThen(sfaOutlineKeepLevel in fLastOpenNode.FoldAction, '(Keep)', ''), FoldTypeToStr(lCurNode.FoldType), IfThen(sfaOutlineKeepLevel in lCurNode.FoldAction, '(Keep)', '')]);
{$ENDIF}
// find lastnode // first opening node on this line, that is = hl.line[-1].endnestlevel (-1)
if (lCurNode.NestLvlStart < fHighlighter.FoldBlockEndLevel(lCurNode.LineIndex-1, lCurNode.FoldGroup, [sfbIncludeDisabled])) and
(i < fNestList.Count - fNestList.OpeningOnLineCount) and
(not FColumnCache.IsValidForLine[lCurNode.LineIndex])
then
InitColumnForKeepLvl(lCurNode.LineIndex, lCurNode.FoldGroup);
if not FColumnCache.IsValidForLine[lCurNode.LineIndex] then
FColumnCache[lCurNode.LineIndex] := FirstCharacterColumn[lCurNode.LineIndex];
lNodeCol := FColumnCache[lCurNode.LineIndex];
{ do not keep level if two consecutive sfaOutlineKeepLevel nodes are
on different lines and start on different columns }
if (fLastNode.LineIndex >= 0)
and (sfaOutlineKeepLevel in fLastNode.FoldAction) then begin
if (LastNode.LineIndex >= 0)
and (sfaOutlineKeepLevel in LastNode.FoldAction) then begin
{$IFDEF SynEditMarkupFoldColoringDebug}
//DebugLn(' %.5d/%.5d %.2d/%.2d', [fLastNode.LineIndex+1,lCurNode.LineIndex+1, FFoldColorInfos[fLastIndex].PhysCol, lNodeCol]);
//DebugLn(' %.5d/%.5d %.2d/%.2d', [LastNode.LineIndex+1,lCurNode.LineIndex+1, FFoldColorInfos[fLastIndex].PhysCol, lNodeCol]);
//DbgOut(' keep');
{$ENDIF}
lKeepLevel := True;
if (sfaOutlineKeepLevel in lCurNode.FoldAction)
and not (fLastNode.LineIndex = lCurNode.LineIndex)
and not (LastNode.LineIndex = lCurNode.LineIndex)
and not (fFoldColorInfos[fLastIndex].PhysCol = lNodeCol) then begin
{$IFDEF SynEditMarkupFoldColoringDebug}
//DbgOut(' not');
@ -535,8 +649,8 @@ begin
fFoldColorInfos[lCurIndex].Level := lLvl;
fFoldColorInfos[lCurIndex].ColorIdx := Max(0, lLvl) mod (length(fColors));
// overwrite first character column with new value
if fFoldColorInfos[fLastIndex].PhysX < fFirstCharacterPhysColCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] then
fFirstCharacterPhysColCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] := fFoldColorInfos[fLastIndex].PhysX;
if fFoldColorInfos[fLastIndex].PhysX < FColumnCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] then
FColumnCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] := fFoldColorInfos[fLastIndex].PhysX;
{$IFDEF SynEditMarkupFoldColoringDebug}
//with FFoldColorInfos[lCurIndex] do
// DebugLn(' > > > %.2d %.2d-%.2d: %d - %s %.5d:%s', [PhysCol, PhysX, PhysX2, Level, IfThen(sfaClose in SrcNode.FoldAction, 'C ', IfThen(sfaOpen in SrcNode.FoldAction, 'O ', '??')),ToPos(SrcNode.LineIndex),FoldTypeToStr(SrcNode.FoldType)]);
@ -546,16 +660,13 @@ begin
if not (sfaOutlineKeepLevel in lCurNode.FoldAction) then
inc(lLvl);
fLastNode := lCurNode;
LastNode := lCurNode;
fLastIndex := lCurIndex;
fLastOpenNode := lCurNode;
fLastOpenIndex := lCurIndex;
lvlA := lLvl;
with fFoldColorInfos[fFoldColorInfosCount - 1] do begin
LevelBefore := lvlB;
LevelAfter := lvlA;
LevelAfter := lLvl; // used in DoMarkupParentCloseFoldAtRow
end;
end;
inc(i);
@ -567,7 +678,7 @@ var
lMaxLevel, lvl, lCurIndex: Integer;
lCurNode: TSynFoldNodeInfo;
lKeepLevel: Boolean;
lNodeCol: Byte;
lNodeCol: TColumnCacheEntry;
function AddHighlight: Boolean;
var
@ -605,9 +716,9 @@ var
SrcNode:= lCurNode; //needed by close node
Row := pRow; //ToPos(lCurNode.LineIndex);
PhysX := lPhysX;
//if fFirstCharacterPhysColCache[lCurNode.LineIndex] = 0 then
// fFirstCharacterPhysColCache[lCurNode.LineIndex] := FirstCharacterColumn[lCurNode.LineIndex];
PhysCol := lNodeCol; //fFirstCharacterPhysColCache[lCurNode.LineIndex];
//if not FColumnCache.IsValidForLine[lCurNode.LineIndex] then
// FColumnCache[lCurNode.LineIndex] := FirstCharacterColumn[lCurNode.LineIndex];
PhysCol := lNodeCol; //FColumnCache[lCurNode.LineIndex];
PhysX2 := lPhysX2;
Level := lvl;
lMaxLevel := Max(lMaxLevel, lvl);
@ -624,16 +735,16 @@ var
end;
var
lLineIdx,i,j,lvlB,lvlA , k: integer;
lLineIdx,i,j,lvlA , k: integer;
lNodeList: TLazSynFoldNodeInfoList;
begin
lLineIdx := ToIdx(pRow);
// as all nodes will be on pRow we can set lNodeCol here already
if fFirstCharacterPhysColCache[lLineIdx] = 0 then
fFirstCharacterPhysColCache[lLineIdx] := FirstCharacterColumn[lLineIdx];
lNodeCol := fFirstCharacterPhysColCache[lLineIdx];
if not FColumnCache.IsValidForLine[lLineIdx] then
FColumnCache[lLineIdx] := FirstCharacterColumn[lLineIdx];
lNodeCol := FColumnCache[lLineIdx];
fHighlighter.CurrentLines := Lines;
@ -653,7 +764,6 @@ begin
lCurIndex := fFoldColorInfosCount - 1;
// sanity check
Assert(lCurNode.LineIndex = lLineIdx, 'Node not on aRow');
Assert(fCacheCapacity > lCurNode.LineIndex, 'TSynEditMarkupFoldColors.DoMarkupParentFoldAtRow: cache arrays too small');
{$IFDEF SynEditMarkupFoldColoringDebug}
//if not (sfaInvalid in lCurNode.FoldAction) then
@ -663,7 +773,6 @@ begin
if not (sfaInvalid in lCurNode.FoldAction)
and (sfaOutline in lCurNode.FoldAction) then begin
if sfaOpen in lCurNode.FoldAction then begin
lvlB := lvl;
if ( sfaOutlineForceIndent in lCurNode.FoldAction) then
inc(lvl)
@ -696,10 +805,10 @@ begin
if AddHighlight then begin
if lKeepLevel then begin
// overwrite first character column with new value
if fFoldColorInfos[fLastOpenIndex].PhysX < fFirstCharacterPhysColCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] then begin
fFirstCharacterPhysColCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] := fFoldColorInfos[fLastOpenIndex].PhysX;
if fFoldColorInfos[fLastOpenIndex].PhysX < FColumnCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] then begin
FColumnCache[fFoldColorInfos[lCurIndex].SrcNode.LineIndex] := fFoldColorInfos[fLastOpenIndex].PhysX;
Assert(fFoldColorInfos[lCurIndex].SrcNode.LineIndex = lLineIdx, 'fFoldColorInfos[lCurIndex].SrcNode.LineIndex <> lLineIdx');
lNodeCol := fFirstCharacterPhysColCache[lLineIdx]
lNodeCol := FColumnCache[lLineIdx]
end;
{$IFDEF SynEditMarkupFoldColoringDebug}
//with FFoldColorInfos[lCurIndex] do
@ -711,13 +820,11 @@ begin
inc(lvl);
lvlA := lvl;
fLastNode := lCurNode;
fLastIndex := lCurIndex;
fLastOpenNode := lCurNode;
fLastOpenIndex := lCurIndex;
with fFoldColorInfos[fFoldColorInfosCount - 1] do begin
LevelBefore := lvlB;
LevelAfter := lvlA;
end;
end;
@ -729,15 +836,12 @@ begin
and (FoldGroup = lCurNode.FoldGroup)
and (sfaOpen in FoldAction)
and (NestLvlEnd = lCurNode.NestLvlStart) then begin
lvlB := lvl;
lvl := fFoldColorInfos[j].Level;
lvlA := fFoldColorInfos[j].LevelAfter;
if AddHighlight then begin
fLastNode := lCurNode;
fLastIndex := lCurIndex;
with fFoldColorInfos[fFoldColorInfosCount - 1] do begin
LevelBefore := lvlB;
LevelAfter := lvlA;
end;
// if found opening position is behind closing position:
@ -781,14 +885,10 @@ begin
//DebugLn(#10'PrepareMarkupForRow %d', [aRow]);
{$ENDIF}
if fUpdateCache then
UpdateCache;
fPreparedRow := pRow;
fFoldColorInfosCount := 0; //reset needed to prevent using of invalid area
// invalidate fLastNode
fLastNode.LineIndex := -1;
// invalidate LastNode
fLastIndex := -1;
fLastOpenNode.LineIndex := -1;
fLastOpenIndex := -1;
@ -814,7 +914,7 @@ begin
and (fFoldColorInfos[i-1].PhysX2 = fFoldColorInfos[i].PhysX2)
and (fFoldColorInfos[i-1].Row = pRow)
and (fFoldColorInfos[i].Row = pRow) then begin
fFirstCharacterPhysColCache[ToIdx(pRow)] := fFoldColorInfos[i-2].PhysCol;
FColumnCache[ToIdx(pRow)] := fFoldColorInfos[i-2].PhysCol;
end;
end;
@ -845,23 +945,6 @@ begin
fNestList.FoldGroup := fDefaultGroup;
end;
procedure TSynEditMarkupFoldColors.SetCacheCount(pNewCount: Integer);
var
i: Integer;
begin
if pNewCount > fCacheCapacity then begin
// expand array
fCacheCapacity := pNewCount + 900;
SetLength(fFirstCharacterPhysColCache, fCacheCapacity);
end;
if pNewCount > fCacheCount then begin
// clear new section
for i := fCacheCount to pNewCount - 1 do
fFirstCharacterPhysColCache[i] := 0;
end;
fCacheCount := pNewCount;
end;
procedure TSynEditMarkupFoldColors.SetFoldColorInfosCount(pNewCount: Integer);
begin
if pNewCount > fFoldColorInfosCapacity then begin
@ -872,67 +955,12 @@ begin
fFoldColorInfosCount := pNewCount;
end;
procedure TSynEditMarkupFoldColors.InitCache;
procedure TSynEditMarkupFoldColors.InitNestList;
begin
if Assigned(fNestList) then
fNestList.Lines := Lines;
// set cache size
SetCacheCount(Lines.Count);
end;
procedure TSynEditMarkupFoldColors.ClearCache;
var
i: Integer;
begin
for i := 0 to fCacheCount - 1 do
fFirstCharacterPhysColCache[i] := 0;
//DebugLn('*** ClearCache');
UpdateCacheRange(0, fCacheCount - 1);
end;
procedure TSynEditMarkupFoldColors.UpdateCache;
var
i, max, lTopLineIdx: Integer;
lFrom, lTo, j: Integer;
begin
// force calculating of fFirstCharacterPhysColCache only for lines
// in front of TopLine
fUpdateCache := False;
lTopLineIdx := ToIdx(TCustomSynEdit(SynEdit).TopLine);
max := Min(SynEdit.Lines.Count, length(fFirstCharacterPhysColCache)) - 1;
if (fFirstInvalidCacheLine >= 0) and (fFirstInvalidCacheLine < lTopLineIdx) then
for j := fFirstInvalidCacheLine to min(fLastInvalidCacheLine, lTopLineIdx) do begin
if fFirstCharacterPhysColCache[j] = 0 then
PrepareMarkupForRow(ToPos(j));
end;
fNestList.Clear;
fFirstInvalidCacheLine := -1;
fLastInvalidCacheLine := -1;
//DebugLn(' Cache updated');
end;
procedure TSynEditMarkupFoldColors.UpdateCacheRange(pFrom, pTo: Integer);
var
i: Integer;
begin
if (fFirstInvalidCacheLine >= 0) then begin
for i := pFrom to fFirstInvalidCacheLine - 1 do
fFirstCharacterPhysColCache[i] := 0;
for i := fLastInvalidCacheLine + 1 to pTo do
fFirstCharacterPhysColCache[i] := 0;
end
else begin
for i := pFrom to pTo do
fFirstCharacterPhysColCache[i] := 0;
end;
if (fFirstInvalidCacheLine < 0) or (pFrom < fFirstInvalidCacheLine) then
fFirstInvalidCacheLine := pFrom;
if pTo > fLastInvalidCacheLine then
fLastInvalidCacheLine := pTo;
fUpdateCache := True;
if Assigned(fNestList2) then
fNestList2.Lines := Lines;
end;
procedure TSynEditMarkupFoldColors.UpdateColors;
@ -964,7 +992,7 @@ var
lNode: TSynFoldNodeInfo;
lNodeIdx, lEndLine, lLineIdx, lBottomLine, lDecreaseCount, lOuterNodeIdx: Integer;
nl: LongInt;
x: Byte;
x: TColumnCacheEntry;
{$IFDEF SynEditMarkupFoldColoringDebug}
t: QWord;
{$ENDIF}
@ -1003,11 +1031,12 @@ begin
// pEndLine seems to be the first line after the change
pEndLine := pEndLine - 1;
lEndLine := pEndLine;
fFirstCharacterPhysColCache[ToIdx(lEndLine)] := FirstCharacterColumn[ToIdx(lEndLine)];
x := fFirstCharacterPhysColCache[ToIdx(lEndLine)];
FColumnCache[ToIdx(lEndLine)] := FirstCharacterColumn[ToIdx(lEndLine)];
x := FColumnCache[ToIdx(lEndLine)];
lBottomLine := TCustomSynEdit(SynEdit).TopLine + TCustomSynEdit(SynEdit).LinesInWindow;
fNestList.Clear;
fNestList2.Clear;
lLineIdx := ToIdx(pStartLine);
fNestList.Line := lLineIdx;
lNodeIdx := fNestList.Count - 1;
@ -1059,9 +1088,6 @@ begin
lEndLine := Max(lEndLine, lLineIdx);
end;
// invalidate cache
UpdateCacheRange(ToIdx(pStartLine), ToIdx(Max(pEndLine, lEndLine)));
if lEndLine > pEndLine then begin
{$IFDEF SynEditMarkupFoldColoringDebug}
//DebugLn(' InvalidateSynLines(%d, %d)', [EndLine + 1, lEndLine]);
@ -1079,16 +1105,17 @@ procedure TSynEditMarkupFoldColors.SetLines(const pValue: TSynEditStrings);
var
old: TSynEditStrings;
begin
if Lines <> nil then
Lines.Ranges[Self] := nil;
if Enabled then begin
old := Lines;
if Assigned(old)
and (pValue <> old) then begin
// change:
// remove Changehandler
old.RemoveChangeHandler(senrLineCount, @LinesChanged);
old.RemoveChangeHandler(senrHighlightChanged, @HighlightChanged);
old.RemoveNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
ClearCache;
FColumnCache.Invalidate;
end;
end;
inherited SetLines(pValue);
@ -1097,56 +1124,24 @@ begin
// change:
if Assigned(pValue) then begin
// add Changehandler
pValue.AddChangeHandler(senrLineCount, @LinesChanged);
pValue.AddChangeHandler(senrHighlightChanged, @HighlightChanged);
pValue.AddNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
InitCache;
InitNestList;
end else begin
// clear cache
SetCacheCount(0);
if Assigned(fNestList) then
fNestList.Lines := nil;
if Assigned(fNestList2) then
fNestList2.Lines := nil;
//DebugLn('*** SetLines');
end;
end;
end;
end;
procedure TSynEditMarkupFoldColors.LinesChanged(pSender: TSynEditStrings;
pIndex, pCount: Integer);
var
absCount,
idx, i, lCount: Integer;
begin
if not Enabled then
exit;
{$IFDEF SynEditMarkupFoldColoringDebug}
//DebugLn(' LinesChanged: aIndex=%d aCount=%d', [aIndex, aCount]);
{$ENDIF}
lCount := Min(Length(fFirstCharacterPhysColCache) - 1, pSender.Count);
idx := ToIdx(pIndex);
if (pCount < 0)
and (idx >= 0) then begin
// lines deleted
absCount := Abs(pCount);
for i := idx to lCount - absCount do
fFirstCharacterPhysColCache[i] := fFirstCharacterPhysColCache[i + absCount];
end;
SetCacheCount(pSender.Count);
if (pCount > 0) then begin
if idx >= 0 then begin
// lines added
for i := lCount - pCount downto idx do
fFirstCharacterPhysColCache[i + pCount] := fFirstCharacterPhysColCache[i];
UpdateCacheRange(idx, Min(idx + pCount, Length(fFirstCharacterPhysColCache) - 1));
end else begin
// first lines will be inserted
UpdateCacheRange(0, Length(fFirstCharacterPhysColCache) - 1);
end;
//DebugLn('*** LinesChanged');
if Lines <> nil then begin
FColumnCache.Capacity := Lines.Capacity;
FColumnCache.Count := Lines.Count;
Lines.Ranges[Self] := FColumnCache;
end;
FColumnCache.Invalidate;
end;
procedure TSynEditMarkupFoldColors.HighlightChanged(pSender: TSynEditStrings;
@ -1173,11 +1168,12 @@ begin
fHighlighter := TSynCustomFoldHighlighter(newHighlighter);
fNestList.HighLighter := fHighlighter;
fNestList2.HighLighter := fHighlighter;
if not Enabled then
exit;
ClearCache;
FColumnCache.Invalidate;
end;
procedure TSynEditMarkupFoldColors.DoEnabledChanged(pSender: TObject);
@ -1191,10 +1187,9 @@ begin
{$ENDIF}
if Assigned(Lines) then begin
// add Changehandler
Lines.AddChangeHandler(senrLineCount, @LinesChanged);
Lines.AddChangeHandler(senrHighlightChanged, @HighlightChanged);
Lines.AddNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
InitCache;
InitNestList;
end;
end else begin
{$IFDEF SynEditMarkupFoldColoringDebug}
@ -1202,10 +1197,9 @@ begin
{$ENDIF}
if Assigned(Lines) then begin
// remove Changehandler
Lines.RemoveChangeHandler(senrLineCount, @LinesChanged);
Lines.RemoveChangeHandler(senrHighlightChanged, @HighlightChanged);
Lines.RemoveNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
ClearCache;
FColumnCache.Invalidate;
end;
end;
if Assigned(Lines) then