mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-29 20:30:33 +02:00
SynEdit: MarkupFoldColor, improve performance
git-svn-id: trunk@58578 -
This commit is contained in:
parent
de1e87aabd
commit
381de68567
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user