mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-22 23:45:57 +02:00
SynEdit: Fold at %Region and $IfDef (Issue #12718)
git-svn-id: trunk@19409 -
This commit is contained in:
parent
1c8d3ab9b0
commit
71fb77ec40
@ -51,7 +51,9 @@ type
|
||||
LineOffset : Integer; (* Line-Number Offset to parent node
|
||||
All line numbers are stored as offsets, for faster updates if lines are inserted/deleted *)
|
||||
LeftCount : Integer; (* Lines folded in left tree. Used to calculate how many lines are folded up to a specified line *)
|
||||
LineCount : Integer; (* Amount of lines covered by this fold only *)
|
||||
FullCount : Integer; (* Amount of lines in source for this fold *)
|
||||
LineCount : Integer; (* Amount of lines folded away by this fold,
|
||||
FullCount + Lines covered by overlaps *)
|
||||
|
||||
function TreeDepth: integer; (* longest WAY down. Only one node => 1! *)
|
||||
function RecursiveFoldCount : Integer; (* Amount of lines covered by this and all child nodes *)
|
||||
@ -80,6 +82,7 @@ type
|
||||
TSynTextFoldAVLNode = object
|
||||
private
|
||||
function GetLineCount : Integer;
|
||||
function GetFullCount : Integer;
|
||||
protected
|
||||
fData : TSynTextFoldAVLNodeData; // nil if unfolded
|
||||
fStartLine : Integer; // start of folded
|
||||
@ -89,6 +92,7 @@ type
|
||||
function Next : TSynTextFoldAVLNode;
|
||||
function Prev : TSynTextFoldAVLNode;
|
||||
property LineCount : Integer read GetLineCount; // Zero, if Not in a fold
|
||||
property FullCount : Integer read GetFullCount; // Zero, if Not in a fold
|
||||
property StartLine : Integer read fStartLine; // 1st Line of Current Fold
|
||||
property FoldedBefore : Integer read fFoldedBefore; // Count of Lines folded before Startline
|
||||
end;
|
||||
@ -139,6 +143,7 @@ type
|
||||
Procedure AdjustForLinesDeleted(AStartLine, ALineCount : Integer);
|
||||
Function FindLastFold : TSynTextFoldAVLNode;
|
||||
Function FindFirstFold : TSynTextFoldAVLNode;
|
||||
Function LastFoldedLine : integer; // The actual line; LastNode.StartLine + LastNode.LineCount - 1
|
||||
procedure debug;
|
||||
end;
|
||||
|
||||
@ -461,6 +466,13 @@ begin
|
||||
else Result := fData.LineCount;
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLNode.GetFullCount: Integer;
|
||||
begin
|
||||
if fData = nil
|
||||
then Result := -1
|
||||
else Result := fData.FullCount;
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLNode.IsInFold : Boolean;
|
||||
begin
|
||||
Result := fData <> nil;
|
||||
@ -546,7 +558,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLTree.FindFoldForLine(ALine : Integer; FindNextNode : Boolean = False) : TSynTextFoldAVLNode;
|
||||
(* Find Fold by Line in Real Text *)
|
||||
function TSynTextFoldAVLTree.FindFoldForLine(ALine : Integer;
|
||||
FindNextNode : Boolean = False) : TSynTextFoldAVLNode;
|
||||
var
|
||||
r : TSynTextFoldAVLNodeData;
|
||||
rStartLine : Integer;
|
||||
@ -557,7 +571,7 @@ begin
|
||||
rFoldedBefore := 0;
|
||||
while (r <> nil) do begin
|
||||
rStartLine := rStartLine + r.LineOffset;
|
||||
|
||||
|
||||
if ALine < rStartLine then begin
|
||||
if FindNextNode and (r.Left = nil) then break;
|
||||
r := r.Left; // rStartLine points to r, so if r.Left is nil then it is pointing to the next fold;
|
||||
@ -582,7 +596,9 @@ begin
|
||||
Result.fFoldedBefore := rFoldedBefore; // always ok
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLTree.FindFoldForFoldedLine(ALine : Integer; FindNextNode : Boolean) : TSynTextFoldAVLNode;
|
||||
(* Find Fold by Line in Folded Text // always returns unfolded, unless next=true *)
|
||||
function TSynTextFoldAVLTree.FindFoldForFoldedLine(ALine : Integer;
|
||||
FindNextNode : Boolean) : TSynTextFoldAVLNode;
|
||||
var
|
||||
r : TSynTextFoldAVLNodeData;
|
||||
rStartLine : Integer;
|
||||
@ -594,6 +610,7 @@ begin
|
||||
while (r <> nil) do begin
|
||||
rStartLine := rStartLine + r.LineOffset;
|
||||
|
||||
// r.LeftCount => "FoldedBefore"
|
||||
if ALine + r.LeftCount < rStartLine then begin
|
||||
if FindNextNode and (r.Left = nil) then break;
|
||||
r := r.Left; // rStartLine points to r, so if r.Left is nil then it is pointing to the next fold;
|
||||
@ -618,74 +635,79 @@ begin
|
||||
end;
|
||||
|
||||
procedure TSynTextFoldAVLTree.AdjustForLinesInserted(AStartLine, ALineCount : Integer);
|
||||
var
|
||||
Current : TSynTextFoldAVLNodeData;
|
||||
CurrentLine : Integer;
|
||||
begin
|
||||
Current := fRoot;
|
||||
CurrentLine := fRootOffset;
|
||||
|
||||
while (Current <> nil) do begin
|
||||
CurrentLine := CurrentLine + Current.LineOffset;
|
||||
Procedure DoAdjustForLinesInserted(Current : TSynTextFoldAVLNodeData;
|
||||
CurrentLine : Integer);
|
||||
var
|
||||
t: LongInt;
|
||||
begin
|
||||
while (Current <> nil) do begin
|
||||
CurrentLine := CurrentLine + Current.LineOffset;
|
||||
|
||||
if AStartLine < CurrentLine then begin
|
||||
// move current node
|
||||
Current.LineOffset := Current.LineOffset + ALineCount;
|
||||
CurrentLine := CurrentLine + ALineCount;
|
||||
if Current.Left <> nil then
|
||||
Current.Left.LineOffset := Current.Left.LineOffset - ALineCount;
|
||||
Current := Current.Left;
|
||||
end
|
||||
else if AStartLine > CurrentLine + Current.LineCount - 1 then begin
|
||||
// The new lines are entirly behind the current node
|
||||
Current := Current.Right;
|
||||
end
|
||||
else begin
|
||||
// grow current node
|
||||
Current.LineCount := Current.LineCount + ALineCount;
|
||||
Current.AdjustParentLeftCount(ALineCount);
|
||||
TreeForNestedNode(Current, CurrentLine).AdjustForLinesInserted(AStartLine, ALineCount);
|
||||
if Current.Right <> nil then // and move entire right
|
||||
Current.Right.LineOffset := Current.Right.LineOffset + ALineCount;
|
||||
break;
|
||||
if AStartLine < CurrentLine then begin
|
||||
// move current node
|
||||
Current.LineOffset := Current.LineOffset + ALineCount;
|
||||
CurrentLine := CurrentLine + ALineCount;
|
||||
if Current.Left <> nil then
|
||||
Current.Left.LineOffset := Current.Left.LineOffset - ALineCount;
|
||||
Current := Current.Left;
|
||||
end
|
||||
else if AStartLine > CurrentLine + Current.LineCount - 1 then begin
|
||||
// The new lines are entirly behind the current node
|
||||
Current := Current.Right;
|
||||
end
|
||||
else begin
|
||||
// grow current node
|
||||
// CurrentLine <= AStartLine <= CurrentLine + Current.FullCount - 1
|
||||
t := Current.FullCount;
|
||||
if AStartLine <= CurrentLine + t - 1 then
|
||||
Current.FullCount := t + ALineCount;
|
||||
Current.LineCount := Current.LineCount + ALineCount;
|
||||
Current.AdjustParentLeftCount(ALineCount);
|
||||
TreeForNestedNode(Current, CurrentLine).AdjustForLinesInserted(AStartLine, ALineCount);
|
||||
|
||||
if Current.Right <> nil then // and move entire right
|
||||
Current.Right.LineOffset := Current.Right.LineOffset + ALineCount;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
DoAdjustForLinesInserted(fRoot, fRootOffset);
|
||||
end;
|
||||
|
||||
procedure TSynTextFoldAVLTree.AdjustForLinesDeleted(AStartLine, ALineCount : Integer);
|
||||
Procedure UnfoldForRange(Current : TSynTextFoldAVLNodeData; CurrentLine, StartLine, LineCount : Integer);
|
||||
begin
|
||||
// unfold any node, that has either start or end line in the range
|
||||
end;
|
||||
|
||||
Procedure AdjustNodeForLinesDeleted(Current : TSynTextFoldAVLNodeData; CurrentLine, StartLine, LineCount : Integer);
|
||||
procedure TSynTextFoldAVLTree.AdjustForLinesDeleted(AStartLine,
|
||||
ALineCount : Integer);
|
||||
Procedure AdjustNodeForLinesDeleted(Current : TSynTextFoldAVLNodeData;
|
||||
CurrentLine, FirstLineToDelete, CountLinesToDelete : Integer);
|
||||
var
|
||||
EndLine, LinesBefore, LinesInside, LinesAfter, t : Integer;
|
||||
LastLineToDelete, LinesBefore, LinesInside, LinesAfter, t : Integer;
|
||||
begin
|
||||
EndLine := StartLine + LineCount - 1; // only valid for delete; LineCount < 0
|
||||
LastLineToDelete := FirstLineToDelete + CountLinesToDelete - 1; // only valid for delete; CountLinesToDelete < 0
|
||||
|
||||
while (Current <> nil) do begin
|
||||
CurrentLine := CurrentLine + Current.LineOffset;
|
||||
|
||||
if StartLine < CurrentLine then begin
|
||||
if FirstLineToDelete < CurrentLine then begin
|
||||
// move current node
|
||||
if EndLine >= CurrentLine then begin
|
||||
if LastLineToDelete >= CurrentLine then begin
|
||||
// overlap => shrink
|
||||
LinesBefore := CurrentLine - StartLine;
|
||||
LinesInside := LineCount - LinesBefore;
|
||||
LinesBefore := CurrentLine - FirstLineToDelete;
|
||||
LinesInside := CountLinesToDelete - LinesBefore;
|
||||
// shrink
|
||||
t := Current.LineCount;
|
||||
Current.LineCount := Max(Current.LineCount - LinesInside, -1);
|
||||
Current.FullCount := Max(Current.FullCount - LinesInside, -1);
|
||||
Current.LineCount := Max(Current.LineCount - LinesInside, 0);
|
||||
Current.AdjustParentLeftCount(Current.LineCount - t); // If LineCount = -1; LeftCount will be correctd on delete node
|
||||
TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(CurrentLine, LinesInside);
|
||||
|
||||
if (Current.Right <> nil) and (LinesInside > 0) then begin
|
||||
if (Current.Right <> nil) then begin
|
||||
// move right // Calculate from the new curent.LineOffset, as below
|
||||
AdjustNodeForLinesDeleted(Current.Right, CurrentLine - LinesBefore,
|
||||
StartLine, LinesInside);
|
||||
FirstLineToDelete, LinesInside);
|
||||
end;
|
||||
end
|
||||
else LinesBefore := LineCount;
|
||||
else LinesBefore := CountLinesToDelete;
|
||||
|
||||
// move current node (includes right subtree / left subtree needs eval)
|
||||
Current.LineOffset := Current.LineOffset - LinesBefore;
|
||||
@ -694,20 +716,24 @@ procedure TSynTextFoldAVLTree.AdjustForLinesDeleted(AStartLine, ALineCount : Int
|
||||
Current.Left.LineOffset := Current.Left.LineOffset + LinesBefore;
|
||||
Current := Current.Left;
|
||||
end
|
||||
else if StartLine > CurrentLine + Current.LineCount - 1 then begin
|
||||
else if FirstLineToDelete > CurrentLine + Current.LineCount - 1 then begin
|
||||
// The deleted lines are entirly behind the current node
|
||||
Current := Current.Right;
|
||||
end
|
||||
else begin // (StartLine >= CurrentLine) AND (StartLine < CurrentLine - Current.LineCount);
|
||||
LinesAfter := EndLine - (CurrentLine + Current.LineCount - 1);
|
||||
else begin
|
||||
// (FirstLineToDelete >= CurrentLine) AND (FirstLineToDelete < CurrentLine + Current.LineCount);
|
||||
LinesAfter := LastLineToDelete - (CurrentLine + Current.LineCount - 1);
|
||||
if LinesAfter < 0 then LinesAfter := 0;
|
||||
LinesInside := LineCount - LinesAfter;
|
||||
LinesInside := CountLinesToDelete - LinesAfter;
|
||||
|
||||
// shrink current node
|
||||
t := Current.LineCount;
|
||||
Current.LineCount := Current.LineCount - LinesInside;
|
||||
Current.AdjustParentLeftCount(Current.LineCount - t);
|
||||
TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(StartLine, LinesInside);
|
||||
if Current.FullCount > Current.LineCount then
|
||||
Current.FullCount := Current.LineCount;
|
||||
Current.AdjustParentLeftCount(Current.LineCount - t); // If LineCount = -1; LeftCount will be correctd on delete node
|
||||
|
||||
TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(FirstLineToDelete, LinesInside);
|
||||
Current := Current.Right;
|
||||
end;
|
||||
|
||||
@ -757,13 +783,25 @@ begin
|
||||
Result.fFoldedBefore := 0; // first fold
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLTree.LastFoldedLine: integer;
|
||||
var
|
||||
n: TSynTextFoldAVLNode;
|
||||
begin
|
||||
n := FindFirstFold;
|
||||
if not n.IsInFold then exit(0);
|
||||
Result := n.StartLine + n.LineCount - 1;
|
||||
end;
|
||||
|
||||
procedure TSynTextFoldAVLTree.debug;
|
||||
function debug2(ind, typ : String; ANode, AParent : TSynTextFoldAVLNodeData; offset : integer) :integer;
|
||||
begin
|
||||
result := 0;
|
||||
if ANode = nil then exit;
|
||||
with ANode do
|
||||
DebugLn([ind,typ,' LineOffset: ',LineOffset,', LineCount: ', LineCount,', LeftCount: ',LeftCount,', Balance: ',Balance,' ##Line=', offset+LineOffset]);
|
||||
DebugLn([Format('L=%3d -%3d: %2d / %2d', [offset + ANode.LineOffset,
|
||||
offset + ANode.LineOffset + ANode.LineCount -1, LineCount,
|
||||
FullCount]), ind, typ, ' (',LineOffset, ') LeftCount: ',
|
||||
LeftCount, ' Balance: ',Balance]);
|
||||
if ANode.Parent <> AParent then DebugLn([ind,'* Bad parent']);
|
||||
Result := debug2(ind+' ', 'L', ANode.Left, ANode, offset+ANode.LineOffset);
|
||||
If Result <> ANode.LeftCount then debugln([ind,' ***** Leftcount was ',Result, ' but should be ', ANode.LeftCount]);
|
||||
@ -782,6 +820,7 @@ begin
|
||||
r := NewNode;
|
||||
r.LineOffset := ALine;
|
||||
r.LineCount := ACount;
|
||||
r.FullCount := ACount;
|
||||
r.LeftCount := 0;
|
||||
Result.fData := r;
|
||||
Result.fStartLine := ALine;
|
||||
@ -807,53 +846,65 @@ function TSynTextFoldAVLTree.RemoveFoldForNodeAtLine(ANode : TSynTextFoldAVLNode
|
||||
var
|
||||
NestedNode, MergeNode : TSynTextFoldAVLNodeData;
|
||||
NestedLine : LongInt;
|
||||
OnlyNested: Boolean;
|
||||
begin
|
||||
OnlyNested := ALine >= ANode.StartLine + ANode.FullCount;
|
||||
// The cfCollapsed line is one line before the fold
|
||||
Result := ANode.StartLine-1; // Return the cfcollapsed that was unfolded
|
||||
RemoveNode(ANode.fData);
|
||||
if not OnlyNested then
|
||||
RemoveNode(ANode.fData);
|
||||
|
||||
If ANode.fData.Nested <> nil then
|
||||
begin
|
||||
(*Todo: should we mark the tree as NO balancing needed ???*)
|
||||
TreeForNestedNode(ANode.fData, ANode.StartLine).RemoveFoldForLine(ALine, IgnoreFirst);
|
||||
|
||||
// merge the remaining nested into current
|
||||
NestedNode := ANode.fData.Nested;
|
||||
if NestedNode <> nil
|
||||
then NestedLine := ANode.fStartLine + NestedNode.LineOffset;
|
||||
|
||||
while NestedNode <> nil do begin
|
||||
while NestedNode.Left <> nil do begin
|
||||
NestedNode := NestedNode.Left;
|
||||
NestedLine := NestedLine + NestedNode.LineOffset;
|
||||
if not OnlyNested then begin
|
||||
// merge the remaining nested into current
|
||||
NestedNode := ANode.fData.Nested;
|
||||
if NestedNode <> nil
|
||||
then NestedLine := ANode.fStartLine + NestedNode.LineOffset;
|
||||
|
||||
while NestedNode <> nil do begin
|
||||
while NestedNode.Left <> nil do begin
|
||||
NestedNode := NestedNode.Left;
|
||||
NestedLine := NestedLine + NestedNode.LineOffset;
|
||||
end;
|
||||
|
||||
if NestedNode.Right <> nil then begin
|
||||
NestedNode := NestedNode.Right;
|
||||
NestedLine := NestedLine + NestedNode.LineOffset;
|
||||
continue;
|
||||
end;
|
||||
|
||||
// leaf node
|
||||
// Anything that is still nested (MergeNode.Nested), will stay nested
|
||||
MergeNode := NestedNode;
|
||||
|
||||
NestedLine := NestedLine - NestedNode.LineOffset;
|
||||
NestedNode := NestedNode.Parent;
|
||||
|
||||
MergeNode.LineOffset := MergeNode.LineOffset + NestedLine;
|
||||
if NestedNode <> nil then begin
|
||||
NestedNode.ReplaceChild(MergeNode, nil);
|
||||
MergeNode.Parent := nil;
|
||||
end;
|
||||
MergeNode.LeftCount := 0;
|
||||
MergeNode.Balance := 0;
|
||||
InsertNode(MergeNode);
|
||||
end;
|
||||
|
||||
if NestedNode.Right <> nil then begin
|
||||
NestedNode := NestedNode.Right;
|
||||
NestedLine := NestedLine + NestedNode.LineOffset;
|
||||
continue;
|
||||
end
|
||||
else begin
|
||||
if ANode.LineCount > ANode.FullCount then begin
|
||||
ANode.fData.LineCount := max(ANode.FullCount,
|
||||
TreeForNestedNode(ANode.fData, 0).LastFoldedLine + 1);
|
||||
end;
|
||||
|
||||
// leaf node
|
||||
// Anything that is still nested (MergeNode.Nested), will stay nested
|
||||
MergeNode := NestedNode;
|
||||
|
||||
NestedLine := NestedLine - NestedNode.LineOffset;
|
||||
NestedNode := NestedNode.Parent;
|
||||
|
||||
MergeNode.LineOffset := MergeNode.LineOffset + NestedLine;
|
||||
if NestedNode <> nil then begin
|
||||
NestedNode.ReplaceChild(MergeNode, nil);
|
||||
MergeNode.Parent := nil;
|
||||
end;
|
||||
MergeNode.LeftCount := 0;
|
||||
MergeNode.Balance := 0;
|
||||
InsertNode(MergeNode);
|
||||
end;
|
||||
|
||||
|
||||
end;
|
||||
|
||||
DisposeNode(ANode.fData);
|
||||
|
||||
if not OnlyNested then
|
||||
DisposeNode(ANode.fData);
|
||||
end;
|
||||
|
||||
function TSynTextFoldAVLTree.InsertNode(ANode : TSynTextFoldAVLNodeData) : Integer;
|
||||
@ -863,14 +914,13 @@ var
|
||||
|
||||
current, Nest : TSynTextFoldAVLNodeData;
|
||||
ALine, AEnd, ACount : Integer;
|
||||
|
||||
|
||||
(* ANode.StartLine < Current.StartLine // ANode goes into tree *)
|
||||
procedure NestCurrentIntoNewBlock; inline;
|
||||
var
|
||||
diff, start2, before2 : Integer;
|
||||
p : TSynTextFoldAVLNodeData;
|
||||
begin
|
||||
// TODO => Check if LineCount needs to be extended (part overlap/nesting)
|
||||
// include extension in below AdjustParentLeftCount
|
||||
current.AdjustParentLeftCount(ACount-current.LineCount); // -RecursiveFoldCount(current));
|
||||
rStartLine := rStartLine - current.LineOffset; // rStarteLine is now current.Parent
|
||||
p := current.Parent;
|
||||
@ -901,17 +951,46 @@ var
|
||||
start2 := ALine; before2 := rFoldedBefore;
|
||||
p := ANode.Successor(start2, before2);
|
||||
end;
|
||||
// check only after loop, if we gre, we did so by existing nodes, so no new overlaps
|
||||
start2 := TreeForNestedNode(Anode, 0).LastFoldedLine;
|
||||
if start2 > ANode.FullCount - 1 then begin
|
||||
ANode.AdjustParentLeftCount(start2 + 1 - ANode.LineCount);
|
||||
ANode.LineCount := start2 + 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure NestNewBlockIntoCurrent; inline;
|
||||
(* ANode.StartLine > Current.StartLine // Current remains in tree *)
|
||||
procedure NestNewBlockIntoCurrent; //inline;
|
||||
var
|
||||
end2, start2, before2: Integer;
|
||||
p: TSynTextFoldAVLNodeData;
|
||||
begin
|
||||
// Check if current.LineCount needs extension
|
||||
ANode.LineOffset := ALine - rStartLine;
|
||||
if current.Nested <> nil
|
||||
then TreeForNestedNode(current, 0).InsertNode(ANode)
|
||||
else current.Nested := ANode;
|
||||
// TODO => Find More Nodes (only if acount extended), that need to be nested => May include LineCount/LeftCount Adjustment
|
||||
// TODO => BalanceAfterInsert (only if more nodes)
|
||||
|
||||
end2 := TreeForNestedNode(current, 0).LastFoldedLine;
|
||||
if end2 > current.FullCount -1 then begin
|
||||
end2 := rStartLine + end2;
|
||||
|
||||
start2 := rStartLine; before2 := rFoldedBefore;
|
||||
p := current.Successor(start2, before2);
|
||||
while (p <> nil) and (start2 <= end2) do begin
|
||||
RemoveNode(p);
|
||||
p.LineOffset := start2 - rStartLine;
|
||||
TreeForNestedNode(current, 0).InsertNode(p);
|
||||
|
||||
start2 := rStartLine; before2 := rFoldedBefore;
|
||||
p := current.Successor(start2, before2);
|
||||
end;
|
||||
end2 := TreeForNestedNode(current, 0).LastFoldedLine;
|
||||
if end2 > current.FullCount -1 then begin
|
||||
current.AdjustParentLeftCount(end2 + 1 - current.LineCount);
|
||||
current.LineCount := end2 + 1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
@ -971,7 +1050,7 @@ begin
|
||||
NestCurrentIntoNewBlock
|
||||
else begin
|
||||
debugln(['Droping Foldnode / Already exists. Startline=', rStartLine,' LineCount=',ACount]);
|
||||
ANode.Free;
|
||||
FreeAndNil(ANode);
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
@ -985,7 +1064,7 @@ begin
|
||||
current := current.Right;
|
||||
continue;
|
||||
end
|
||||
else if Nest=nil then Begin // insert to the right - no nesting
|
||||
else if Nest=nil then Begin // insert to the right - no nesting
|
||||
current.AdjustParentLeftCount(ACount);
|
||||
current.SetRightChild(ANode, -rStartLine);
|
||||
BalanceAfterInsert(ANode);
|
||||
@ -1661,11 +1740,13 @@ begin
|
||||
end;
|
||||
|
||||
function TSynEditFoldedView.LengthForFoldAtTextIndex(ALine : Integer) : Integer;
|
||||
var
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
begin
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit(0);
|
||||
Result := TSynCustomFoldHighlighter(FHighLighter).FoldLineLength(ALine,
|
||||
TSynCustomFoldHighlighter(FHighLighter).FoldOpenCount(ALine) -1);
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
Result := hl.FoldLineLength(ALine, hl.FoldOpenCount(ALine) -1);
|
||||
end;
|
||||
|
||||
procedure TSynEditFoldedView.FoldAtTextIndex(AStartIndex : Integer);
|
||||
@ -1719,20 +1800,21 @@ end;
|
||||
|
||||
procedure TSynEditFoldedView.FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
|
||||
var
|
||||
i, l, top: Integer;
|
||||
i, l, top, t: Integer;
|
||||
hl: TSynCustomFoldHighlighter;
|
||||
begin
|
||||
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
|
||||
then exit;
|
||||
FHighLighter.CurrentLines := fLines;
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
t := 1; // TODO: Highlighter default type; or iterate through all types
|
||||
|
||||
top := TopTextIndex;
|
||||
fFoldTree.Clear;
|
||||
i := 0;
|
||||
while i < fLines.Count do begin
|
||||
if (hl.FoldOpenCount(i) > 0)
|
||||
and (hl.FoldNestCount(i) > StartLevel) then begin
|
||||
if (hl.FoldOpenCount(i, t) > 0)
|
||||
and (hl.FoldNestCount(i, t) > StartLevel) then begin
|
||||
l := LengthForFoldAtTextIndex(i);
|
||||
// i is 0-based
|
||||
// FoldTree is 1-based AND first line remains visble
|
||||
@ -1777,8 +1859,8 @@ begin
|
||||
FHighLighter.CurrentLines := fLines;
|
||||
hl := TSynCustomFoldHighlighter(FHighLighter);
|
||||
|
||||
// LineCount is allowed to be -1
|
||||
while node.IsInFold and (node.StartLine + node.LineCount + 1 >= AStart) do begin
|
||||
// FullCount is allowed to be -1
|
||||
while node.IsInFold and (node.StartLine + node.FullCount + 1 >= AStart) do begin
|
||||
tmpnode := node.Prev;
|
||||
if tmpnode.IsInFold then
|
||||
node := tmpnode
|
||||
@ -1790,7 +1872,7 @@ begin
|
||||
LastCount := -2;
|
||||
while node.IsInFold do begin
|
||||
line := node.StartLine - 1; // the 1-based cfCollapsed (last visible) Line
|
||||
cnt := node.LineCount;
|
||||
cnt := node.FullCount;
|
||||
if ((LastStart = line) and (LastCount = cnt)) or (cnt < 0) then begin
|
||||
// Same node as previous or fully deleted
|
||||
tmpnode := node.Prev;
|
||||
@ -1803,7 +1885,7 @@ begin
|
||||
LastCount := cnt;
|
||||
|
||||
// look at the 0-based cfCollapsed (visible) Line
|
||||
if not(hl.FoldOpenCount(line - 1) > 0) then begin
|
||||
if (hl.FoldOpenCount(line - 1) <= 0) then begin
|
||||
// the Fold-Begin of this node has gone
|
||||
tmpnode := node.Prev;
|
||||
aFoldTree.RemoveFoldForNodeAtLine(node, -1); // Don't touch any nested node
|
||||
@ -1813,7 +1895,7 @@ begin
|
||||
end;
|
||||
|
||||
a:= LengthForFoldAtTextIndex(line-1);
|
||||
if not(cnt = a) then begin
|
||||
if (cnt <> a) then begin
|
||||
// the Fold-End of this node has gone or moved
|
||||
tmpnode := node.Prev;
|
||||
aFoldTree.RemoveFoldForNodeAtLine(node, -1); // Don't touch any nested node
|
||||
@ -1823,8 +1905,14 @@ begin
|
||||
end;
|
||||
|
||||
if (node.fData.Nested <> nil)
|
||||
and (FixFolding(line, line+1+node.LineCount, aFoldTree.TreeForNestedNode(node.fData.Nested, line+1)))
|
||||
then continue;
|
||||
and (FixFolding(line, line+1+node.FullCount, aFoldTree.TreeForNestedNode(node.fData, line+1)))
|
||||
then begin
|
||||
if node.LineCount > node.FullCount then begin
|
||||
node.fData.LineCount := max(node.FullCount,
|
||||
aFoldTree.TreeForNestedNode(node.fData, 0).LastFoldedLine + 1);
|
||||
end;
|
||||
continue;
|
||||
end;
|
||||
|
||||
// the node was ok
|
||||
if node.StartLine >= AMinEnd then break;
|
||||
|
@ -144,14 +144,16 @@ type
|
||||
function CurrentCodeFoldBlockLevel: integer; virtual;
|
||||
|
||||
// requires CurrentLines;
|
||||
function MinimumFoldLevel(Index: Integer): integer; virtual; abstract;
|
||||
function EndFoldLevel(Index: Integer): integer; virtual; abstract;
|
||||
function MinimumFoldLevel(Index: Integer): integer; virtual; abstract; // TODO: Move to Fold*
|
||||
function EndFoldLevel(Index: Integer): integer; virtual; abstract; // TODO: Replace with FoldNestCount
|
||||
|
||||
// fold-nodes that can be collapsed
|
||||
// Highlighter can join several fold structures Or leave out some
|
||||
function FoldOpenCount(ALineIndex: Integer): integer; virtual;
|
||||
function FoldCloseCount(ALineIndex: Integer): integer; virtual;
|
||||
function FoldNestCount(ALineIndex: Integer): integer; virtual;
|
||||
function FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer; virtual;
|
||||
function FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer; virtual;
|
||||
function FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer; virtual;
|
||||
function FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
|
||||
UseCloseNodes: boolean = false): integer; virtual;
|
||||
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; virtual;
|
||||
|
||||
// All fold-nodes
|
||||
@ -300,17 +302,23 @@ begin
|
||||
Result:=0;
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.FoldOpenCount(ALineIndex: Integer): integer;
|
||||
function TSynCustomFoldHighlighter.FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
begin
|
||||
result := 0;
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.FoldCloseCount(ALineIndex: Integer): integer;
|
||||
function TSynCustomFoldHighlighter.FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
begin
|
||||
result := 0;
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.FoldNestCount(ALineIndex: Integer): integer;
|
||||
function TSynCustomFoldHighlighter.FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TSynCustomFoldHighlighter.FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
|
||||
UseCloseNodes: boolean): integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
@ -108,7 +108,9 @@ type
|
||||
cfbtExcept,
|
||||
cfbtRepeat,
|
||||
cfbtAsm,
|
||||
cfbtCase
|
||||
cfbtCase,
|
||||
cfbtIfDef, // {$IfDef} directive, ths is not counted in the Range-Node
|
||||
cfbtRegion // {%Region} user folds, not counted in the Range-Node
|
||||
);
|
||||
TPascalCodeFoldBlockTypes = set of TPascalCodeFoldBlockType;
|
||||
|
||||
@ -157,6 +159,26 @@ const
|
||||
|
||||
type
|
||||
|
||||
TSynPasRangeInfo = record
|
||||
EndLevelIfDef: Smallint;
|
||||
MinLevelIfDef: Smallint;
|
||||
EndLevelRegion: Smallint;
|
||||
MinLevelRegion: Smallint;
|
||||
end;
|
||||
|
||||
{ TSynHighlighterPasRangeList }
|
||||
|
||||
TSynHighlighterPasRangeList = class(TSynHighlighterRangeList)
|
||||
private
|
||||
function GetTSynPasRangeInfo(Index: Integer): TSynPasRangeInfo;
|
||||
procedure SetTSynPasRangeInfo(Index: Integer; const AValue: TSynPasRangeInfo);
|
||||
protected
|
||||
function ItemSize: Integer; override;
|
||||
public
|
||||
property PasRangeInfo[Index: Integer]: TSynPasRangeInfo
|
||||
read GetTSynPasRangeInfo write SetTSynPasRangeInfo;
|
||||
end;
|
||||
|
||||
{ TSynPasSynRange }
|
||||
|
||||
TSynPasSynRange = class(TSynCustomHighlighterRange)
|
||||
@ -203,6 +225,7 @@ type
|
||||
FStartCodeFoldBlockLevel: integer;
|
||||
FPasStartLevel: Smallint;
|
||||
fRange: TRangeStates;
|
||||
FSynPasRangeInfo: TSynPasRangeInfo;
|
||||
FAtLineStart: Boolean; // Line had only spaces or comments sofar
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
fLineStr: string;
|
||||
@ -377,35 +400,41 @@ type
|
||||
procedure DestroyDividerDrawConfig;
|
||||
procedure InitFoldConfig;
|
||||
protected
|
||||
function GetFoldConfig(Index: Integer): Boolean; override;
|
||||
function GetFoldConfigCount: Integer; override;
|
||||
procedure SetFoldConfig(Index: Integer; const AValue: Boolean); override;
|
||||
function GetIdentChars: TSynIdentChars; override;
|
||||
function IsFilterStored: boolean; override; //mh 2000-10-08
|
||||
protected
|
||||
function GetRangeClass: TSynCustomHighlighterRangeClass; override;
|
||||
procedure CreateRootCodeFoldBlock; override;
|
||||
function CreateRangeList: TSynHighlighterRangeList; override;
|
||||
function UpdateRangeInfoAtLine(Index: Integer): Boolean; override; // Returns true if range changed
|
||||
|
||||
function StartPascalCodeFoldBlock
|
||||
(ABlockType: TPascalCodeFoldBlockType): TSynCustomCodeFoldBlock;
|
||||
procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); override;
|
||||
procedure CloseBeginEndBlocks;
|
||||
procedure EndCodeFoldBlockLastLine;
|
||||
procedure StartCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
procedure EndCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
|
||||
function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; override;
|
||||
function GetFoldNodeInfoCount(Line: Integer): Integer; override;
|
||||
|
||||
function GetIdentChars: TSynIdentChars; override;
|
||||
function IsFilterStored: boolean; override; //mh 2000-10-08
|
||||
|
||||
procedure CreateRootCodeFoldBlock; override;
|
||||
function StartPascalCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType):
|
||||
TSynCustomCodeFoldBlock;
|
||||
procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); override;
|
||||
procedure CloseBeginEndBlocks;
|
||||
procedure EndCodeFoldBlockLastLine;
|
||||
function TopPascalCodeFoldBlockType(DownIndex: Integer = 0): TPascalCodeFoldBlockType;
|
||||
|
||||
function GetRangeClass: TSynCustomHighlighterRangeClass; override;
|
||||
property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange;
|
||||
function TopPascalCodeFoldBlockType
|
||||
(DownIndex: Integer = 0): TPascalCodeFoldBlockType;
|
||||
|
||||
function MinimumPasFoldLevel(Index: Integer): integer;
|
||||
function EndPasFoldLevel(Index: Integer): integer;
|
||||
function LastLinePasFoldLevelFix(Index: Integer): integer;
|
||||
function MinimumPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
|
||||
function EndPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
|
||||
function LastLinePasFoldLevelFix(Index: Integer; AType: Integer = 1): integer;
|
||||
|
||||
function LastLineFoldLevelFix(Index: Integer): integer;
|
||||
function GetDrawDivider(Index: integer): TSynDividerDrawConfigSetting; override;
|
||||
function GetDividerDrawConfig(Index: Integer): TSynDividerDrawConfig; override;
|
||||
function GetDividerDrawConfigCount: Integer; override;
|
||||
|
||||
function GetFoldConfig(Index: Integer): Boolean; override;
|
||||
function GetFoldConfigCount: Integer; override;
|
||||
procedure SetFoldConfig(Index: Integer; const AValue: Boolean); override;
|
||||
public
|
||||
{$IFNDEF SYN_CPPB_1} class {$ENDIF}
|
||||
function GetCapabilities: TSynHighlighterCapabilities; override;
|
||||
@ -433,16 +462,20 @@ type
|
||||
procedure SetLine({$IFDEF FPC}const {$ENDIF}NewValue: string;
|
||||
LineNumber: Integer); override;
|
||||
procedure SetRange(Value: Pointer); override;
|
||||
procedure StartAtLineIndex(LineNumber:Integer); override; // 0 based
|
||||
|
||||
function UseUserSettings(settingIndex: integer): boolean; override;
|
||||
procedure EnumUserSettings(settings: TStrings); override;
|
||||
|
||||
// fold-nodes that can be collapsed
|
||||
function FoldOpenCount(ALineIndex: Integer): integer; override;
|
||||
function FoldCloseCount(ALineIndex: Integer): integer; override;
|
||||
function FoldNestCount(ALineIndex: Integer): integer; override;
|
||||
function FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
|
||||
function FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
|
||||
function FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
|
||||
function FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
|
||||
UseCloseNodes: boolean = false): integer; override;
|
||||
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; override;
|
||||
|
||||
// Pascal coe only // TODO: make private
|
||||
function MinimumFoldLevel(Index: Integer): integer; override;
|
||||
function EndFoldLevel(Index: Integer): integer; override;
|
||||
published
|
||||
@ -1807,6 +1840,8 @@ begin
|
||||
PasCodeFoldRange.PasFoldMinLevel :=
|
||||
PasCodeFoldRange.PasFoldEndLevel;
|
||||
FPasStartLevel := PasCodeFoldRange.PasFoldMinLevel;
|
||||
FSynPasRangeInfo.MinLevelIfDef := FSynPasRangeInfo.EndLevelIfDef;
|
||||
FSynPasRangeInfo.MinLevelRegion := FSynPasRangeInfo.EndLevelRegion;
|
||||
FNodeInfoLine := -1;
|
||||
fLineNumber := LineNumber;
|
||||
FAtLineStart := True;
|
||||
@ -1915,21 +1950,40 @@ end;
|
||||
|
||||
procedure TSynPasSyn.BraceOpenProc;
|
||||
begin
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
if (Run=fLineLen-1) or (fLine[Run+1]<>'$') then begin
|
||||
// curly bracket open -> borland comment
|
||||
inc(Run);
|
||||
{$ENDIF}
|
||||
fRange := fRange + [rsBor];
|
||||
BorProc;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
end else begin
|
||||
if (Run < fLineLen-1) and (fLine[Run+1] = '$') then begin
|
||||
// compiler directive
|
||||
fRange := fRange + [rsDirective];
|
||||
inc(Run,2);
|
||||
fToIdent := Run;
|
||||
KeyHash;
|
||||
if KeyComp('ifdef') or KeyComp('ifndef') then
|
||||
StartCustomCodeFoldBlock(cfbtIfDef)
|
||||
else if KeyComp('endif') then
|
||||
EndCustomCodeFoldBlock(cfbtIfDef)
|
||||
else if KeyComp('else') then begin
|
||||
EndCustomCodeFoldBlock(cfbtIfDef);
|
||||
StartCustomCodeFoldBlock(cfbtIfDef);
|
||||
end
|
||||
else if KeyComp('region') then
|
||||
StartCustomCodeFoldBlock(cfbtRegion)
|
||||
else if KeyComp('endregion') then
|
||||
EndCustomCodeFoldBlock(cfbtRegion);
|
||||
DirectiveProc;
|
||||
end else begin
|
||||
// curly bracket open -> borland comment
|
||||
inc(Run);
|
||||
fRange := fRange + [rsBor];
|
||||
if (Run < fLineLen) and (fLine[Run] = '%') then begin
|
||||
inc(Run);
|
||||
fToIdent := Run;
|
||||
KeyHash;
|
||||
if KeyComp('region') then
|
||||
StartCustomCodeFoldBlock(cfbtRegion)
|
||||
else if KeyComp('endregion') then
|
||||
EndCustomCodeFoldBlock(cfbtRegion);
|
||||
end;
|
||||
BorProc;
|
||||
end;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.ColonOrGreaterProc;
|
||||
@ -2353,11 +2407,23 @@ begin
|
||||
FNodeInfoLine := -1;
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.StartAtLineIndex(LineNumber: Integer);
|
||||
begin
|
||||
FSynPasRangeInfo := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[LineNumber];
|
||||
inherited StartAtLineIndex(LineNumber);
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.ResetRange;
|
||||
begin
|
||||
fRange := [];
|
||||
FStartCodeFoldBlockLevel:=0;
|
||||
FPasStartLevel := 0;
|
||||
with FSynPasRangeInfo do begin
|
||||
EndLevelIfDef := 0;
|
||||
MinLevelIfDef := 0;
|
||||
EndLevelRegion := 0;
|
||||
MinLevelRegion := 0;
|
||||
end;
|
||||
Inherited ResetRange;
|
||||
CompilerMode:=pcmDelphi;
|
||||
end;
|
||||
@ -2396,78 +2462,168 @@ begin
|
||||
Result := TPascalCodeFoldBlockType(PtrUInt(p));
|
||||
end;
|
||||
|
||||
function TSynPasSyn.FoldOpenCount(ALineIndex: Integer): integer;
|
||||
function TSynPasSyn.FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
var
|
||||
inf: TSynPasRangeInfo;
|
||||
begin
|
||||
Result := EndPasFoldLevel(ALineIndex) - MinimumPasFoldLevel(ALineIndex);
|
||||
Result := 0;
|
||||
if (AType <> 1) then
|
||||
inf := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex];
|
||||
if (AType = 0) or (AType = 1) then
|
||||
Result := EndPasFoldLevel(ALineIndex) - MinimumPasFoldLevel(ALineIndex);
|
||||
if (AType = 0) or (AType = 2) then
|
||||
Result := Result + inf.EndLevelRegion - inf.MinLevelRegion;
|
||||
if (AType = 0) or (AType = 3) then
|
||||
Result := Result + inf.EndLevelIfDef - inf.MinLevelIfDef;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.FoldCloseCount(ALineIndex: Integer): integer;
|
||||
function TSynPasSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
var
|
||||
inf, inf2: TSynPasRangeInfo;
|
||||
begin
|
||||
Result := EndPasFoldLevel(ALineIndex - 1) - MinimumPasFoldLevel(ALineIndex);
|
||||
Result := 0;
|
||||
if (AType <> 1) then begin
|
||||
inf := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex];
|
||||
inf2 := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex - 1];
|
||||
end;
|
||||
if (AType = 0) or (AType = 1) then
|
||||
Result := EndPasFoldLevel(ALineIndex - 1) - MinimumPasFoldLevel(ALineIndex);
|
||||
if (AType = 0) or (AType = 2) then
|
||||
Result := Result + inf2.EndLevelRegion - inf.MinLevelRegion;
|
||||
if (AType = 0) or (AType = 3) then
|
||||
Result := Result + inf2.EndLevelIfDef - inf.MinLevelIfDef;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.FoldNestCount(ALineIndex: Integer): integer;
|
||||
function TSynPasSyn.FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer;
|
||||
var
|
||||
inf: TSynPasRangeInfo;
|
||||
begin
|
||||
Result := EndPasFoldLevel(ALineIndex);
|
||||
Result := 0;
|
||||
if (AType <> 1) then
|
||||
inf := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex];
|
||||
if (AType = 0) or (AType = 1) then
|
||||
Result := EndPasFoldLevel(ALineIndex);
|
||||
if (AType = 0) or (AType = 2) then
|
||||
Result := Result + inf.EndLevelRegion;
|
||||
if (AType = 0) or (AType = 3) then
|
||||
Result := Result + inf.EndLevelIfDef;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
|
||||
UseCloseNodes: boolean): integer;
|
||||
var
|
||||
i, j: LongInt;
|
||||
act: TSynFoldActions;
|
||||
begin
|
||||
j := GetFoldNodeInfoCount(ALineIndex);
|
||||
i := 0;
|
||||
while (i < j) and (FoldIndex > 0) do begin
|
||||
act := GetFoldNodeInfo(ALineIndex, i).FoldAction;
|
||||
if (UseCloseNodes and (sfaClose in act)) or
|
||||
((not UseCloseNodes) and (sfaOpen in act)) then
|
||||
dec(FoldIndex);
|
||||
inc(i);
|
||||
end;
|
||||
if i = j then
|
||||
exit(-1);
|
||||
// 0 is used for "all"
|
||||
case TPascalCodeFoldBlockType(PtrUInt(GetFoldNodeInfo(ALineIndex, i).FoldType)) of
|
||||
cfbtRegion:
|
||||
Result := 2;
|
||||
cfbtIfDef:
|
||||
Result := 3;
|
||||
else
|
||||
Result := 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.FoldLineLength(ALineIndex, FoldIndex: Integer): integer;
|
||||
var
|
||||
i, lvl, cnt : Integer;
|
||||
i, lvl, cnt, atype : Integer;
|
||||
e, m: Integer;
|
||||
begin
|
||||
atype := FoldTypeAtNodeIndex(ALineIndex, FoldIndex);
|
||||
cnt := CurrentLines.Count;
|
||||
e := EndPasFoldLevel(ALineIndex);
|
||||
m := MinimumPasFoldLevel(ALineIndex);
|
||||
e := EndPasFoldLevel(ALineIndex, atype);
|
||||
m := MinimumPasFoldLevel(ALineIndex, atype);
|
||||
lvl := Min(m+1+FoldIndex, e);
|
||||
i := ALineIndex + 1;
|
||||
while (i < cnt) and (MinimumPasFoldLevel(i) >= lvl) do inc(i);
|
||||
while (i < cnt) and (MinimumPasFoldLevel(i, atype) >= lvl) do inc(i);
|
||||
// check if fold last line of block (not mixed "end begin")
|
||||
// and not lastlinefix
|
||||
if (i = cnt) or (EndPasFoldLevel(i) > MinimumPasFoldLevel(i)) then
|
||||
if (i = cnt) or (EndPasFoldLevel(i, atype) > MinimumPasFoldLevel(i, atype)) then
|
||||
dec(i);
|
||||
// Amount of lines, that will become invisible (excludes the cfCollapsed line)
|
||||
Result := i - ALineIndex;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.MinimumPasFoldLevel(Index: Integer): integer;
|
||||
function TSynPasSyn.MinimumPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
|
||||
var
|
||||
r: TSynPasSynRange;
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := Min(r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1),
|
||||
r.PasFoldMinLevel)
|
||||
else
|
||||
Result := 0;
|
||||
case AType of
|
||||
2:
|
||||
Result := TSynHighlighterPasRangeList(CurrentRanges).
|
||||
PasRangeInfo[Index].MinLevelRegion;
|
||||
3:
|
||||
Result := TSynHighlighterPasRangeList(CurrentRanges).
|
||||
PasRangeInfo[Index].MinLevelIfDef;
|
||||
else
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := Min(r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1),
|
||||
r.PasFoldMinLevel)
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.EndPasFoldLevel(Index: Integer): integer;
|
||||
function TSynPasSyn.EndPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
|
||||
var
|
||||
r: TSynPasSynRange;
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1)
|
||||
else
|
||||
Result := 0;
|
||||
case AType of
|
||||
2:
|
||||
Result := TSynHighlighterPasRangeList(CurrentRanges).
|
||||
PasRangeInfo[Index].EndLevelRegion;
|
||||
3:
|
||||
Result := TSynHighlighterPasRangeList(CurrentRanges).
|
||||
PasRangeInfo[Index].EndLevelIfDef;
|
||||
else
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1)
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.LastLinePasFoldLevelFix(Index: Integer): integer;
|
||||
function TSynPasSyn.LastLinePasFoldLevelFix(Index: Integer; AType: Integer = 1): integer;
|
||||
var
|
||||
r: TSynPasSynRange;
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := r.PasFoldFixLevel
|
||||
else
|
||||
Result := 0;
|
||||
case AType of
|
||||
2: Result := 0;
|
||||
3: Result := 0;
|
||||
else
|
||||
begin
|
||||
if (Index < 0) or (Index >= CurrentLines.Count) then
|
||||
exit(0);
|
||||
r := TSynPasSynRange(CurrentRanges[Index]);
|
||||
if (r <> nil) and (Pointer(r) <> NullRange) then
|
||||
Result := r.PasFoldFixLevel
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -2526,6 +2682,51 @@ begin
|
||||
Node.FoldAction := [];
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.StartCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
begin
|
||||
if not FFoldConfig[ABlockType] then exit;
|
||||
if FCatchNodeInfo then begin // exclude subblocks, because they do not increase the foldlevel yet
|
||||
GrowNodeInfoList;
|
||||
InitNode(FNodeInfoList[FNodeInfoCount], +1, ABlockType);
|
||||
Include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaOpen);
|
||||
inc(FNodeInfoCount);
|
||||
end;
|
||||
case ABlockType of
|
||||
cfbtIfDef:
|
||||
inc(FSynPasRangeInfo.EndLevelIfDef);
|
||||
cfbtRegion:
|
||||
inc(FSynPasRangeInfo.EndLevelRegion);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynPasSyn.EndCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
|
||||
begin
|
||||
if not FFoldConfig[ABlockType] then exit;
|
||||
if FCatchNodeInfo then begin // exclude subblocks, because they do not increase the foldlevel yet
|
||||
GrowNodeInfoList;
|
||||
InitNode(FNodeInfoList[FNodeInfoCount], +1, ABlockType);
|
||||
Include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaClose);
|
||||
inc(FNodeInfoCount);
|
||||
end;
|
||||
case ABlockType of
|
||||
cfbtIfDef:
|
||||
begin
|
||||
if FSynPasRangeInfo.EndLevelIfDef > 0 then
|
||||
dec(FSynPasRangeInfo.EndLevelIfDef);
|
||||
if FSynPasRangeInfo.EndLevelIfDef < FSynPasRangeInfo.MinLevelIfDef then
|
||||
FSynPasRangeInfo.MinLevelIfDef := FSynPasRangeInfo.EndLevelIfDef;
|
||||
end;
|
||||
cfbtRegion:
|
||||
begin
|
||||
if FSynPasRangeInfo.EndLevelRegion > 0 then
|
||||
dec(FSynPasRangeInfo.EndLevelRegion);
|
||||
if FSynPasRangeInfo.EndLevelRegion < FSynPasRangeInfo.MinLevelRegion then
|
||||
FSynPasRangeInfo.MinLevelRegion := FSynPasRangeInfo.EndLevelRegion;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function TSynPasSyn.StartPascalCodeFoldBlock(
|
||||
ABlockType: TPascalCodeFoldBlockType): TSynCustomCodeFoldBlock;
|
||||
var
|
||||
@ -2756,7 +2957,26 @@ begin
|
||||
FFoldConfig[i] := i in [cfbtBeginEnd, cfbtTopBeginEnd, cfbtNestedComment,
|
||||
cfbtProcedure, cfbtUses, cfbtLocalVarType, cfbtClass,
|
||||
cfbtClassSection, cfbtRecord, cfbtRepeat, cfbtCase,
|
||||
cfbtAsm];
|
||||
cfbtAsm, cfbtRegion];
|
||||
end;
|
||||
|
||||
function TSynPasSyn.CreateRangeList: TSynHighlighterRangeList;
|
||||
begin
|
||||
Result := TSynHighlighterPasRangeList.Create;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.UpdateRangeInfoAtLine(Index: Integer): Boolean;
|
||||
var
|
||||
r: TSynPasRangeInfo;
|
||||
begin
|
||||
Result := inherited;
|
||||
r := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[Index];
|
||||
Result := Result
|
||||
or (FSynPasRangeInfo.EndLevelIfDef <> r.EndLevelIfDef)
|
||||
or (FSynPasRangeInfo.MinLevelIfDef <> r.MinLevelIfDef)
|
||||
or (FSynPasRangeInfo.EndLevelRegion <> r.EndLevelRegion)
|
||||
or (FSynPasRangeInfo.MinLevelRegion <> r.MinLevelRegion);
|
||||
TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[Index] := FSynPasRangeInfo;
|
||||
end;
|
||||
|
||||
function TSynPasSyn.GetFoldConfig(Index: Integer): Boolean;
|
||||
@ -3120,6 +3340,30 @@ begin
|
||||
dec(FPasFoldFixLevel);
|
||||
end;
|
||||
|
||||
{ TSynHighlighterPasRangeList }
|
||||
|
||||
function TSynHighlighterPasRangeList.GetTSynPasRangeInfo(Index: Integer): TSynPasRangeInfo;
|
||||
begin
|
||||
if Index < 0 then begin
|
||||
Result.MinLevelRegion := 0;
|
||||
Result.EndLevelRegion := 0;
|
||||
Result.MinLevelIfDef := 0;
|
||||
Result.EndLevelIfDef := 0;
|
||||
end;
|
||||
Result := TSynPasRangeInfo((ItemPointer[Index] + inherited ItemSize)^);
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterPasRangeList.SetTSynPasRangeInfo(Index: Integer;
|
||||
const AValue: TSynPasRangeInfo);
|
||||
begin
|
||||
TSynPasRangeInfo((ItemPointer[Index] + inherited ItemSize)^) := AValue;
|
||||
end;
|
||||
|
||||
function TSynHighlighterPasRangeList.ItemSize: Integer;
|
||||
begin
|
||||
Result := inherited ItemSize + SizeOf(TSynPasRangeInfo);
|
||||
end;
|
||||
|
||||
initialization
|
||||
MakeIdentTable;
|
||||
{$IFNDEF SYN_CPPB_1}
|
||||
|
@ -405,7 +405,7 @@ type
|
||||
|
||||
const
|
||||
|
||||
EditorOptionsFoldInfoPas: Array [0..17] of TEditorOptionsFoldInfo
|
||||
EditorOptionsFoldInfoPas: Array [0..19] of TEditorOptionsFoldInfo
|
||||
= (
|
||||
(Name: dlgFoldPasProcedure; Xml: 'Procedure';
|
||||
Index: ord(cfbtProcedure)-1; Enabled: True),
|
||||
@ -445,15 +445,20 @@ const
|
||||
Index: ord(cfbtRecord)-1; Enabled: True),
|
||||
|
||||
(Name: dlgFoldPasNestedComment; Xml: 'NestedComment';
|
||||
Index: ord(cfbtNestedComment)-1;Enabled: True)
|
||||
Index: ord(cfbtNestedComment)-1;Enabled: True),
|
||||
|
||||
(Name: dlgFoldPasIfDef; Xml: 'IfDef';
|
||||
Index: ord(cfbtIfDef)-1; Enabled: False),
|
||||
(Name: dlgFoldPasUserRegion; Xml: 'UserRegion';
|
||||
Index: ord(cfbtRegion)-1; Enabled: True)
|
||||
);
|
||||
|
||||
EditorOptionsFoldDefaults: array[TLazSyntaxHighlighter] of
|
||||
TEditorOptionsFoldRecord =
|
||||
( (Count: 0; Info: nil), // none
|
||||
(Count: 0; Info: nil), // text
|
||||
(Count: 18; Info: {$IFDEF FPC}@{$ENDIF}EditorOptionsFoldInfoPas[0]), // Freepas
|
||||
(Count: 18; Info: {$IFDEF FPC}@{$ENDIF}EditorOptionsFoldInfoPas[0]), // pas
|
||||
(Count: 20; Info: {$IFDEF FPC}@{$ENDIF}EditorOptionsFoldInfoPas[0]), // Freepas
|
||||
(Count: 20; Info: {$IFDEF FPC}@{$ENDIF}EditorOptionsFoldInfoPas[0]), // pas
|
||||
(Count: 0; Info: nil), // lfm
|
||||
(Count: 0; Info: nil), // xml
|
||||
(Count: 0; Info: nil), // html
|
||||
|
@ -1262,6 +1262,8 @@ resourcestring
|
||||
dlgFoldPasRepeat = 'Repeat';
|
||||
dlgFoldPasCase = 'Case';
|
||||
dlgFoldPasAsm = 'Asm';
|
||||
dlgFoldPasIfDef = '{$IfDef}';
|
||||
dlgFoldPasUserRegion = '{%Region}';
|
||||
|
||||
// CodeTools dialog
|
||||
dlgCodeToolsOpts = 'CodeTools Options';
|
||||
|
Loading…
Reference in New Issue
Block a user