SynEdit: Fold at %Region and $IfDef (Issue #12718)

git-svn-id: trunk@19409 -
This commit is contained in:
martin 2009-04-13 15:36:53 +00:00
parent 1c8d3ab9b0
commit 71fb77ec40
5 changed files with 539 additions and 192 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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}

View File

@ -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

View File

@ -1262,6 +1262,8 @@ resourcestring
dlgFoldPasRepeat = 'Repeat';
dlgFoldPasCase = 'Case';
dlgFoldPasAsm = 'Asm';
dlgFoldPasIfDef = '{$IfDef}';
dlgFoldPasUserRegion = '{%Region}';
// CodeTools dialog
dlgCodeToolsOpts = 'CodeTools Options';