mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-26 14:53:50 +02:00
SynEdit: Optimized/Extended TLazSynEditNestedFoldsList / added OpeningLineEndIndex
git-svn-id: trunk@37905 -
This commit is contained in:
parent
8c1c285384
commit
2eff3271c7
components/synedit
@ -320,6 +320,7 @@ type
|
||||
FGroupCount: Integer;
|
||||
FGroupEndLevelsAtEval: Array of integer;
|
||||
FCount, FOpeningOnLineCount: Integer;
|
||||
FOpeningLineEndIndex: Integer;
|
||||
FIncludeOpeningOnLine: Boolean;
|
||||
FNestInfo: Array of TLazSynEditNestedFoldsListEntry;
|
||||
FEvaluationIndex: Integer;
|
||||
@ -329,13 +330,14 @@ type
|
||||
function GetHLNode(Index: Integer): TSynFoldNodeInfo;
|
||||
function GetNodeFoldGroup(Index: Integer): Integer;
|
||||
function GetNodeFoldType(Index: Integer): Pointer;
|
||||
procedure InitSubGroupEndLevels;
|
||||
procedure InitSubGroupEndLevels(const AHighlighter: TSynCustomFoldHighlighter);
|
||||
procedure InitNestInfoForIndex(AnIndex: Integer);
|
||||
procedure InitOpeningOnLine(const AHighlighter: TSynCustomFoldHighlighter);
|
||||
procedure SetFoldFlags(AValue: TSynFoldBlockFilterFlags);
|
||||
procedure SetIncludeOpeningOnLine(AValue: Boolean);
|
||||
function GetOpeningOnLineCount(const AHighlighter: TSynCustomFoldHighlighter; AFoldGroup: Integer): Integer; // ignores FFoldFlags
|
||||
procedure AquireFoldNodeInfoList(const AHighlighter: TSynCustomFoldHighlighter; const ALine: Integer = -1);
|
||||
procedure ReleaseFoldNodeInfoList;
|
||||
procedure SetOpeningLineEndIndex(AValue: Integer);
|
||||
public
|
||||
constructor Create(aFoldProvider: TSynEditFoldProvider);
|
||||
procedure Clear;
|
||||
@ -347,7 +349,10 @@ type
|
||||
property FoldGroup: Integer read FFoldGroup write SetFoldGroup;
|
||||
property FoldFlags: TSynFoldBlockFilterFlags read FFoldFlags write SetFoldFlags;
|
||||
property IncludeOpeningOnLine: Boolean read FIncludeOpeningOnLine write SetIncludeOpeningOnLine;
|
||||
//property OpeningLineLogicalPos: Integer read FOpeningLineLogicalPos write SetOpeningLineLogicalPos;
|
||||
// OpeningLineEnd... can only be used with sfbIncludeDisabled
|
||||
// Highest included index (unfiltered index)
|
||||
property OpeningLineEndIndex: Integer read FOpeningLineEndIndex write SetOpeningLineEndIndex;
|
||||
//property OpeningLineEndLogicalPos: Integer read FOpeningLineEndLogicalPos write SetOpeningLineEndLogicalPos;
|
||||
public
|
||||
property HLNode[Index: Integer]: TSynFoldNodeInfo read GetHLNode;
|
||||
property NodeFoldType[Index: Integer]: Pointer read GetNodeFoldType; // e.g.cfbtBeginEnd, cfbtcfbtProcedure ...
|
||||
@ -2854,9 +2859,11 @@ end;
|
||||
procedure TLazSynEditNestedFoldsList.Clear;
|
||||
begin
|
||||
FGroupCount := -1;
|
||||
SetLength(FGroupEndLevelsAtEval, 0);
|
||||
FCount := -1;
|
||||
FOpeningOnLineCount := -1;
|
||||
FEvaluationIndex := -1;
|
||||
FOpeningLineEndIndex := -1;
|
||||
SetLength(FNestInfo, 0);
|
||||
end;
|
||||
|
||||
@ -2868,40 +2875,25 @@ begin
|
||||
Clear;
|
||||
end;
|
||||
|
||||
procedure TLazSynEditNestedFoldsList.InitSubGroupEndLevels;
|
||||
procedure TLazSynEditNestedFoldsList.InitSubGroupEndLevels(const AHighlighter: TSynCustomFoldHighlighter);
|
||||
var
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
i: integer;
|
||||
begin
|
||||
if FGroupCount > 0 then
|
||||
if Length(FGroupEndLevelsAtEval) > 0 then
|
||||
exit;
|
||||
|
||||
hl := FFoldProvider.HighLighterWithLines;
|
||||
if hl = nil then exit;
|
||||
|
||||
if FFoldGroup = 0 then begin
|
||||
// special, join other groups (or some other...)
|
||||
FGroupCount := hl.FoldTypeCount;
|
||||
// special, join other groups
|
||||
FGroupCount := AHighlighter.FoldTypeCount;
|
||||
// start at 1, so FoldGroup can be used as index
|
||||
SetLength(FGroupEndLevelsAtEval, FGroupCount + 1);
|
||||
if FIncludeOpeningOnLine then
|
||||
AquireFoldNodeInfoList(hl, FLine);
|
||||
try
|
||||
for i := 1 to FGroupCount do begin
|
||||
FGroupEndLevelsAtEval[i] := hl.FoldBlockEndLevel(FLine - 1, i, FFoldFlags);
|
||||
// TODO: adjust flags, if include disabled
|
||||
if FIncludeOpeningOnLine then
|
||||
FGroupEndLevelsAtEval[i] := FGroupEndLevelsAtEval[i] + GetOpeningOnLineCount(hl, i);
|
||||
end;
|
||||
finally
|
||||
if FIncludeOpeningOnLine then
|
||||
ReleaseFoldNodeInfoList;
|
||||
end;
|
||||
for i := 1 to FGroupCount do
|
||||
FGroupEndLevelsAtEval[i] := AHighlighter.FoldBlockEndLevel(FLine - 1, i, FFoldFlags);
|
||||
end
|
||||
else begin
|
||||
FGroupCount := 1;
|
||||
SetLength(FGroupEndLevelsAtEval, 1);
|
||||
FGroupEndLevelsAtEval[0] := Count; // includes OpeningOnLineCount
|
||||
FGroupEndLevelsAtEval[0] := Count - OpeningOnLineCount;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2952,7 +2944,7 @@ begin
|
||||
try
|
||||
if (AnIndex >= Count) or (AnIndex >= FEvaluationIndex) then exit;
|
||||
|
||||
InitSubGroupEndLevels;
|
||||
InitSubGroupEndLevels(hl);
|
||||
if (FEvaluationIndex = Count) then begin
|
||||
if (OpeningOnLineCount > 0) then
|
||||
CurLine := Line
|
||||
@ -3020,6 +3012,107 @@ begin
|
||||
assert(AnIndex >= FEvaluationIndex, 'TLazSynEditNestedFoldsList.InitNestInfoForIndex Index not found');
|
||||
end;
|
||||
|
||||
procedure TLazSynEditNestedFoldsList.InitOpeningOnLine(const AHighlighter: TSynCustomFoldHighlighter);
|
||||
var
|
||||
nd: TSynFoldNodeInfo;
|
||||
OpenIdx: Array of Array of Integer; // List of open-node-index, for each FoldCroup
|
||||
OpenCnt: Array of Integer; // List of open-node-index, for each FoldCroup
|
||||
Grp, c, i, j, GrpLow, GrpHigh: Integer;
|
||||
oc: LongInt;
|
||||
begin
|
||||
Assert((FOpeningLineEndIndex < 0) or (sfbIncludeDisabled in FoldFlags), 'OpeningLineEndIndex only implemented for sfbIncludeDisabled');
|
||||
|
||||
FCount := AHighlighter.FoldBlockEndLevel(FLine - 1, FFoldGroup, FFoldFlags);
|
||||
FEvaluationIndex := FCount;
|
||||
|
||||
if not FIncludeOpeningOnLine then begin
|
||||
SetLength(FNestInfo, FCount); // Capacity for max opening nodes
|
||||
exit;
|
||||
end;
|
||||
|
||||
AquireFoldNodeInfoList(AHighlighter, FLine);
|
||||
try
|
||||
if (sfbIncludeDisabled in FFoldFlags) then
|
||||
FFoldNodeInfoList.ActionFilter := []
|
||||
else
|
||||
FFoldNodeInfoList.ActionFilter := [sfaFold];
|
||||
FFoldNodeInfoList.GroupFilter := 0;
|
||||
|
||||
if FFoldGroup = 0 then begin
|
||||
FGroupCount := AHighlighter.FoldTypeCount;
|
||||
GrpLow := 1;
|
||||
GrpHigh := FGroupCount;
|
||||
end
|
||||
else begin
|
||||
FGroupCount := 1;
|
||||
GrpLow := FFoldGroup;
|
||||
GrpHigh := FFoldGroup;
|
||||
end;
|
||||
SetLength(OpenIdx, FGroupCount, FFoldNodeInfoList.Count);
|
||||
SetLength(OpenCnt, FGroupCount);
|
||||
FOpeningOnLineCount := 0;
|
||||
for Grp := 0 to FGroupCount - 1 do
|
||||
OpenCnt[Grp] := 0;
|
||||
|
||||
for Grp := GrpLow to GrpHigh do begin
|
||||
(* Filtering group in the loop instead of the list only works, if 0 is the only special group
|
||||
See use of NodeIndex below, if changing this *)
|
||||
//FFoldNodeInfoList.GroupFilter := Grp;
|
||||
for i := 0 to FFoldNodeInfoList.Count - 1 do begin
|
||||
nd := FFoldNodeInfoList[i];
|
||||
if (sfaInvalid in nd.FoldAction) or (nd.FoldGroup <> Grp) then
|
||||
Continue;
|
||||
if (FOpeningLineEndIndex >= 0) and (nd.AllNodeIndex > FOpeningLineEndIndex) then
|
||||
break;
|
||||
|
||||
if sfaOpen in nd.FoldAction then begin
|
||||
inc(FOpeningOnLineCount);
|
||||
OpenIdx[Grp - GrpLow, OpenCnt[Grp - GrpLow]] := nd.NodeIndex; // Using NodeIndex only works, because we do NOT change the filter
|
||||
inc(OpenCnt[Grp - GrpLow]);
|
||||
end
|
||||
else
|
||||
if (nd.FoldAction * [sfaClose, sfaFold, sfaSingleLine] = [sfaClose, sfaSingleLine]) then begin
|
||||
dec(FOpeningOnLineCount);
|
||||
dec(OpenCnt[Grp - GrpLow]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
SetLength(FNestInfo, FCount + FOpeningOnLineCount);
|
||||
|
||||
// TODO: skip if FOpeningOnLineCount = 0
|
||||
|
||||
//FFoldNodeInfoList.ActionFilter := [];
|
||||
//FFoldNodeInfoList.GroupFilter := 0;
|
||||
c := FFoldNodeInfoList.Count - 1;
|
||||
if (FOpeningLineEndIndex >= 0) and (c > FOpeningLineEndIndex) then
|
||||
c := FOpeningLineEndIndex;
|
||||
j := FOpeningOnLineCount;
|
||||
|
||||
For i := c downto 0 do begin
|
||||
if j = 0 then break;
|
||||
nd := FFoldNodeInfoList[i];
|
||||
Grp := nd.FoldGroup;
|
||||
if (Grp < GrpLow) or (Grp > GrpHigh) then Continue;
|
||||
oc := OpenCnt[Grp - GrpLow];
|
||||
Assert(oc >= 0, 'TLazSynEditNestedFoldsList.InitOpeningOnLine bad count for '+IntToStr(Grp));
|
||||
Assert((oc=0) or (OpenIdx[Grp - GrpLow, oc-1] <= i), 'TLazSynEditNestedFoldsList.InitOpeningOnLine bad index for '+IntToStr(i)+' G='+IntToStr(Grp));
|
||||
if (oc > 0) and (OpenIdx[Grp - GrpLow, oc-1] = i) then begin
|
||||
dec(OpenCnt[Grp - GrpLow]);
|
||||
dec(j);
|
||||
FNestInfo[FCount + j].LineIdx := FLine;
|
||||
FNestInfo[FCount + j].HNode := nd;
|
||||
FNestInfo[FCount + j].HNode.NodeIndex := j;
|
||||
end;
|
||||
end;
|
||||
|
||||
FCount := FCount + FOpeningOnLineCount;
|
||||
Assert(j=0, 'TLazSynEditNestedFoldsList.InitOpeningOnLine did not fill all nodes '+IntToStr(j));
|
||||
finally
|
||||
ReleaseFoldNodeInfoList;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLazSynEditNestedFoldsList.SetFoldFlags(AValue: TSynFoldBlockFilterFlags);
|
||||
begin
|
||||
if FFoldFlags = AValue then Exit;
|
||||
@ -3052,6 +3145,13 @@ begin
|
||||
ReleaseRefAndNil(FFoldNodeInfoList);
|
||||
end;
|
||||
|
||||
procedure TLazSynEditNestedFoldsList.SetOpeningLineEndIndex(AValue: Integer);
|
||||
begin
|
||||
if FOpeningLineEndIndex = AValue then Exit;
|
||||
FOpeningLineEndIndex := AValue;
|
||||
Clear; // TODO only clear current line, the rest will still be valid
|
||||
end;
|
||||
|
||||
procedure TLazSynEditNestedFoldsList.SetFoldGroup(AValue: Integer);
|
||||
begin
|
||||
if FFoldGroup = AValue then Exit;
|
||||
@ -3077,31 +3177,10 @@ begin
|
||||
hl := FFoldProvider.HighLighterWithLines;
|
||||
if hl = nil then exit(-1);
|
||||
|
||||
FCount := hl.FoldBlockEndLevel(FLine - 1, FFoldGroup, FFoldFlags) + OpeningOnLineCount;
|
||||
FEvaluationIndex := FCount;
|
||||
SetLength(FNestInfo, FCount);
|
||||
InitOpeningOnLine(hl);
|
||||
Result := FCount;
|
||||
end;
|
||||
|
||||
function TLazSynEditNestedFoldsList.GetOpeningOnLineCount(const AHighlighter: TSynCustomFoldHighlighter;
|
||||
AFoldGroup: Integer): Integer;
|
||||
begin
|
||||
AquireFoldNodeInfoList(AHighlighter, FLine);
|
||||
try
|
||||
// TODO: adjust flags, if include disabled
|
||||
//NFilter := [sfaOpenFold];
|
||||
//if not(sfbIncludeDisabled in FFoldFlags) then Include(NFilter, sfaFold);
|
||||
FFoldNodeInfoList.ActionFilter := [sfaOpenFold, sfaFold];
|
||||
FFoldNodeInfoList.GroupFilter := AFoldGroup;
|
||||
|
||||
// Need to check alll nodes with FoldNodeInfoCount
|
||||
// Hide-able nodes can open and close on the same line "(* comment *)"
|
||||
Result := FFoldNodeInfoList.Count;
|
||||
finally
|
||||
ReleaseFoldNodeInfoList;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TLazSynEditNestedFoldsList.OpeningOnLineCount: Integer;
|
||||
var
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
@ -3115,7 +3194,7 @@ begin
|
||||
Result := FOpeningOnLineCount;
|
||||
if Result >= 0 then exit;
|
||||
|
||||
FOpeningOnLineCount := GetOpeningOnLineCount(hl, FFoldGroup);
|
||||
InitOpeningOnLine(hl);
|
||||
Result := FOpeningOnLineCount;
|
||||
end;
|
||||
|
||||
|
@ -1815,6 +1815,7 @@ procedure TTestFoldedView.TestNestedFoldsList;
|
||||
end;
|
||||
var
|
||||
TheList: TLazSynEditNestedFoldsList;
|
||||
i1, i2, i3, i: Integer;
|
||||
begin
|
||||
// L= *(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+).*?A=(.*)
|
||||
// CheckNode(TheList.HLNode[2], $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
|
||||
@ -1990,6 +1991,58 @@ begin
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, -1,-1, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[0], 0, 0, 0, 7, -1,-1, 0, 1, 10, 10, 1, [sfaOpen, sfaOpenFold,sfaMarkup, sfaMultiLine]);
|
||||
|
||||
PopPushBaseName('group 0 - line 4 (with "end"');
|
||||
for i1 := 0 to 1 do begin // IncludeOpeningOnLine
|
||||
if i1 = 0
|
||||
then PushBaseName('IncludeOpeningOnLine')
|
||||
else PushBaseName('NOT IncludeOpeningOnLine');
|
||||
for i2 := 0 to 1 do begin // sfbIncludeDisabled
|
||||
if i2 = 0
|
||||
then PushBaseName('sfbIncludeDisabled')
|
||||
else PushBaseName('NOT sfbIncludeDisabled');
|
||||
for i3 := 0 to 2 do begin // EnableFolds
|
||||
case i3 of
|
||||
0: begin
|
||||
EnableFolds([cfbtBeginEnd..cfbtNone]);
|
||||
PushBaseName('all enabled');
|
||||
i := 3;
|
||||
end;
|
||||
1: begin
|
||||
EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtTopBeginEnd]);
|
||||
PushBaseName('all enabled');
|
||||
i := 2;
|
||||
end;
|
||||
2: begin
|
||||
EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtTopBeginEnd, cfbtProcedure]);
|
||||
PushBaseName('all enabled');
|
||||
i := 1;
|
||||
end;
|
||||
end;
|
||||
if i2 = 0 then i := 3;
|
||||
|
||||
TheList.ResetFilter;
|
||||
TheList.Line := 4;
|
||||
TheList.FoldGroup := 0;
|
||||
if i2 = 0
|
||||
then TheList.FoldFlags := [sfbIncludeDisabled]
|
||||
else TheList.FoldFlags := [];
|
||||
TheList.IncludeOpeningOnLine := i1 = 0;
|
||||
AssertEquals(BaseTestName + 'Cnt', i, TheList.Count);
|
||||
if i3 in [0] then
|
||||
CheckNode(TheList.HLNode[2], 2, 0, 0, 5, 2, 3, 2, 3, 1, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine])
|
||||
else if i2 = 0 then
|
||||
CheckNode(TheList.HLNode[2], 2, 0, 0, 5, -1, -1, 2, 3, 1, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup, sfaMultiLine]);
|
||||
if i3 in [0,1] then
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, 1, 2, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine])
|
||||
else if i2 = 0 then
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, -1, -1, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[0], 0, 0, 0, 7, 0, 1, 0, 1, 10, 10, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
PopBaseName;
|
||||
end;
|
||||
PopBaseName;
|
||||
end;
|
||||
PopBaseName;
|
||||
end;
|
||||
|
||||
PopBaseName;
|
||||
{%endregion TestText1}
|
||||
@ -2066,6 +2119,31 @@ begin
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, 1, 2, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[0], 0, 0, 0, 7, 0, 1, 0, 1, 10, 10, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
|
||||
PopPushBaseName('All Enabled - group 0 - line 7 mixed');
|
||||
TheList.ResetFilter;
|
||||
TheList.Line := 7;
|
||||
TheList.FoldGroup := 0;
|
||||
TheList.FoldFlags := [];
|
||||
TheList.IncludeOpeningOnLine := True;
|
||||
AssertEquals(BaseTestName + 'Cnt', 5, TheList.Count);
|
||||
CheckNode(TheList.HLNode[4], 7, 0, 11, 16, 3, 4, 3, 4, 0, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[3], 5, 0, 12, 17, 3, 4, 3, 4, 0, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[2], 4, 0, 23, 28, 2, 3, 2, 3, 1, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, 1, 2, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[0], 0, 0, 0, 7, 0, 1, 0, 1, 10, 10, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
|
||||
PopPushBaseName('All Enabled - group 0 - line 7 mixed // NOT IncludeOpeningOnLine');
|
||||
TheList.ResetFilter;
|
||||
TheList.Line := 7;
|
||||
TheList.FoldGroup := 0;
|
||||
TheList.FoldFlags := [];
|
||||
TheList.IncludeOpeningOnLine := False;
|
||||
AssertEquals(BaseTestName + 'Cnt', 4, TheList.Count);
|
||||
CheckNode(TheList.HLNode[3], 5, 0, 12, 17, 3, 4, 3, 4, 0, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[2], 4, 0, 23, 28, 2, 3, 2, 3, 1, 0, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[1], 1, 0, 0, 9, 1, 2, 1, 2, 3, 3, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
CheckNode(TheList.HLNode[0], 0, 0, 0, 7, 0, 1, 0, 1, 10, 10, 1, [sfaOpen, sfaOpenFold,sfaMarkup,sfaFold,sfaFoldFold, sfaMultiLine]);
|
||||
|
||||
PopBaseName;
|
||||
{%endregion TestText2}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user