SynEdit: Starting on Ifdef Markup

git-svn-id: trunk@41090 -
This commit is contained in:
martin 2013-05-09 12:02:57 +00:00
parent 8ddfe52d9b
commit f5dd5b7aa8
3 changed files with 330 additions and 84 deletions

View File

@ -45,11 +45,12 @@ type
function GetPoint(const Index : Integer) : TPoint;
function GetPointCount : Integer;
function GetStartPoint(const Index : Integer) : TPoint;
procedure SetCount(const AValue : Integer); override;
function GetMatch(const Index : Integer) : TSynMarkupHighAllMatch;
procedure SetEndPoint(const Index : Integer; const AValue : TPoint);
procedure SetMatch(const Index : Integer; const AValue : TSynMarkupHighAllMatch);
procedure SetStartPoint(const Index : Integer; const AValue : TPoint);
protected
procedure SetCount(const AValue : Integer); override;
public
constructor Create;
Function MaybeReduceCapacity : Boolean;

View File

@ -23,7 +23,7 @@ unit SynEditMarkupIfDef;
interface
uses
SysUtils, types, SynEditMarkup, SynEditMiscClasses, SynHighlighterPas,
SysUtils, types, SynEditMiscClasses, SynHighlighterPas,
SynEditMarkupHighAll, SynEditHighlighterFoldBase, SynEditFoldedView, LazSynEditText,
SynEditMiscProcs, LazClasses, LazLoggerBase, Graphics, LCLProc;
@ -81,6 +81,7 @@ type
FNodeState, FOpeningPeerNodeState: TSynMarkupIfdefNodeStateEx;
FNodeFlags: SynMarkupIfDefNodeFlags;
FPeer1, FPeer2: TSynMarkupHighIfDefEntry;
FRelativeNestDepth: Integer;
FStartColumn, FEndColumn: Integer;
function GetIsDisabled: Boolean;
function GetIsEnabled: Boolean;
@ -97,6 +98,7 @@ type
procedure SetPeer(APeerType: TSynMarkupIfdefNodeType; ANewPeer: TSynMarkupHighIfDefEntry);
procedure ClearPeerField(APeer: PSynMarkupHighIfDefEntry);
procedure RemoveForwardPeers;
procedure MaybeClearOtherPeerField(APeerField: PSynMarkupHighIfDefEntry);
function GetPeerField(APeerType: TSynMarkupIfdefNodeType): PSynMarkupHighIfDefEntry;
function GetOtherPeerField(APeer: PSynMarkupHighIfDefEntry): PSynMarkupHighIfDefEntry;
@ -125,6 +127,8 @@ type
property Line: TSynMarkupHighIfDefLinesNode read FLine write SetLine;
property StartColumn: Integer read FStartColumn write FStartColumn;
property EndColumn: Integer read FEndColumn write FEndColumn;
// RelativeNestDepth (opening depth)) First node is always 0 // nodes in line can be negative
property RelativeNestDepth: Integer read FRelativeNestDepth;
function ClosingPeer: TSynMarkupHighIfDefEntry;
// COMMENT BEFORE AUTO COMPLETE !!!!!
property IfDefPeer: TSynMarkupHighIfDefEntry index idnIfdef read GetPeer write SetPeer;
@ -573,7 +577,7 @@ end;
function TSynRefCountedDict.GetMatchAtChar(AText: PChar; ATextLen: Integer): Integer;
begin
FDict.GetMatchAtChar(AText, ATextLen, @CheckWordEnd);
Result := FDict.GetMatchAtChar(AText, ATextLen, @CheckWordEnd);
end;
{ TSynMarkupHighIfDefEntry }
@ -762,7 +766,7 @@ end;
procedure TSynMarkupHighIfDefEntry.SetPeer(APeerType: TSynMarkupIfdefNodeType;
ANewPeer: TSynMarkupHighIfDefEntry);
var
OwnPeerField, OwnOtherPeerField, OthersPeerField: PSynMarkupHighIfDefEntry;
OwnPeerField, OthersPeerField: PSynMarkupHighIfDefEntry;
begin
//assert((ANewPeer=nil) or (APeerType = ANewPeer.NodeType), 'APeerType = ANewPeer.NodeType'); // elseif can be set as ifdef
OwnPeerField := GetPeerField(APeerType);
@ -772,43 +776,32 @@ begin
exit;
end;
if OwnPeerField^ <> nil then begin
// The PeerField in the old peer
assert(OwnPeerField^.GetPeerField(NodeType)^ = self, 'Peer does not point back to self');
ClearPeerField(OwnPeerField);
end;
ClearPeerField(OwnPeerField);
if ANewPeer <> nil then begin
// If new peer is part of another pair, disolve that pair. This may set OwnPeerField = nil, if new pair points to this node
ANewPeer.SetPeer(NodeType, nil);
if ANewPeer = nil then begin
OwnPeerField^ := ANewPeer;
if (NodeType in [idnIfdef, idnEndIf]) and (ANewPeer <> nil) then begin
// idnIfdef, idnEndIf are only allowed either ONE peer
OwnOtherPeerField := GetOtherPeerField(OwnPeerField);
if OwnOtherPeerField^ <> nil then begin
debugln(['Setting other peer to nil while setting ',dbgs(APeerType),' to ',dbgs(NodeType)]);
OwnOtherPeerField^.SetPeer(NodeType, nil);
assert(OwnOtherPeerField^ = nil, 'OwnOtherPeerField was emptied, by setting the peers backpointer to nil')
end;
end;
end;
OwnPeerField^ := ANewPeer;
if OwnPeerField^ = nil then begin
if not IsForwardPeerField(OwnPeerField) then
SetOpeningPeerNodeState(idnUnknown, idnUnknown);
end
else begin
OthersPeerField := OwnPeerField^.GetPeerField(NodeType);
assert(OthersPeerField^ = nil, 'Peer is not empty');
OthersPeerField^ := self;
// If new peer is part of another pair, disolve that pair. This may set OwnPeerField = nil, if new pair points to this node
assert(ANewPeer.GetPeer(NodeType) <> self, 'New peer points to this, but was not known by this / link is not bidirectional');
if (NodeType = idnElseIf) and (APeerType = idnElse) then // APeerType never is idnElseIf;
OthersPeerField := ANewPeer.GetPeerField(idnIfdef) // act as ifdef
else
OthersPeerField := ANewPeer.GetPeerField(NodeType);
ANewPeer.ClearPeerField(OthersPeerField);
MaybeClearOtherPeerField(OwnPeerField);
ANewPeer.MaybeClearOtherPeerField(OthersPeerField);
OthersPeerField^ := Self;
OwnPeerField^ := ANewPeer;
if IsForwardPeerField(OwnPeerField) then
OwnPeerField^.SetOpeningPeerNodeState(NodeState, NodeStateForPeer(OwnPeerField^.NodeType))
else
SetOpeningPeerNodeState(OwnPeerField^.NodeState, OwnPeerField^.NodeStateForPeer(NodeType));
end;
end;
@ -816,6 +809,8 @@ end;
procedure TSynMarkupHighIfDefEntry.ClearPeerField(APeer: PSynMarkupHighIfDefEntry);
begin
if APeer^ = nil then exit;
// assert(APeer^.GetPeerField(NodeType)^ = self, 'ClearPeerField: Peer does not point back to self');
if IsForwardPeerField(APeer) then
APeer^.SetOpeningPeerNodeState(idnUnknown, idnUnknown)
else
@ -827,7 +822,7 @@ begin
if APeer^.FPeer2 = self then
APeer^.FPeer2 := nil
else
assert(false, 'ClearPeerField did not find back reference');
assert(false, 'ClearPeerField: did not find back reference');
APeer^ := nil;
end;
@ -846,6 +841,22 @@ begin
end;
end;
procedure TSynMarkupHighIfDefEntry.MaybeClearOtherPeerField(APeerField: PSynMarkupHighIfDefEntry);
var
OwnOtherPeerField: PSynMarkupHighIfDefEntry;
begin
if not (NodeType in [idnIfdef, idnEndIf]) then
exit;
// idnIfdef, idnEndIf are only allowed either ONE peer
OwnOtherPeerField := GetOtherPeerField(APeerField);
if OwnOtherPeerField^ <> nil then begin
debugln(['Setting other peer to nil while setting (p1=True / P2=false)', dbgs(APeerField=@FPeer1)]);
ClearPeerField(OwnOtherPeerField);
assert(OwnOtherPeerField^ = nil, 'OwnOtherPeerField was emptied, by setting the peers backpointer to nil')
end;
end;
procedure TSynMarkupHighIfDefEntry.ApplyNodeStateToLine(ARemove: Boolean = False);
var
i: Integer;
@ -1006,7 +1017,7 @@ end;
procedure TSynMarkupHighIfDefLinesNode.MakeDisposed;
begin
FLineFlags := [idlDisposed];
FLineFlags := [idlDisposed] + FLineFlags * [idlInGlobalClear];
while EntryCount > 0 do
DeletEntry(EntryCount-1, True);
assert((FDisabledEntryOpenCount =0) and (FDisabledEntryCloseCount = 0), 'no close count left over');
@ -1430,55 +1441,104 @@ end;
procedure TSynMarkupHighIfDefLinesTree.ConnectPeers(var ANode: TSynMarkupHighIfDefLinesNodeInfo;
var ANestList: TSynMarkupHighIfDefLinesNodeInfoList; AOuterLines: TLazSynEditNestedFoldsList);
var
PeerList: array of TSynMarkupHighIfDefEntry;
NestDepth, LowerNestDepth: Integer;
PeerList: array of TSynMarkupHighIfDefEntry; // List of Else/Endif in the current line, that where opened in a previous line
OpenList: array of TSynMarkupHighIfDefEntry; // List of IfDef/Else in the current line
CurDepth, MaxListIdx, MinOpenDepth, MaxOpenDepth, MaxPeerDepth, MinPeerDepth: Integer;
i, j, OtherDepth: Integer;
OtherLine: TSynMarkupHighIfDefLinesNodeInfo;
function OpenIdx(AIdx: Integer): Integer; // correct negative idx
begin
Result := AIdx;
if Result >= 0 then exit;
Result := MaxListIdx + (-AIdx);
end;
begin
NestDepth := ANode.NestDepthAtNodeEnd;
LowerNestDepth := MaxInt;
SetLength(PeerList, NestDepth + ANode.EntryCount + 1);
OtherLine.ClearInfo;
for i := ANode.EntryCount - 1 downto 0 do begin
/// Scan for onel line blocks
CurDepth := ANode.NestDepthAtNodeStart;
MinOpenDepth := MaxInt;
MaxOpenDepth := -1;
MinPeerDepth := MaxInt;
MaxPeerDepth := -1;
MaxListIdx := CurDepth + ANode.EntryCount + 1;
SetLength(OpenList, MaxListIdx + ANode.EntryCount);
SetLength(PeerList, MaxListIdx);
for i := 0 to ANode.EntryCount - 1 do begin
case ANode.Entry[i].NodeType of
idnIfdef: begin
if (LowerNestDepth <= NestDepth) and (PeerList[NestDepth].IfDefPeer <> ANode.Entry[i])
then begin
Debugln(['New Peer for ',dbgs(PeerList[NestDepth].NodeType), ' to ifdef same line']);
PeerList[NestDepth].IfDefPeer := ANode.Entry[i]; // update closing node
end;
dec(NestDepth);
inc(CurDepth);
OpenList[OpenIdx(CurDepth)] := ANode.Entry[i]; // Store IfDef, with Index at end of IfDef (inside block)
if CurDepth < MinOpenDepth then MinOpenDepth := CurDepth;
if CurDepth > MaxOpenDepth then MaxOpenDepth := CurDepth;
end;
idnElse, idnElseIf: begin
if (LowerNestDepth <= NestDepth)
then begin
if PeerList[NestDepth].NodeType = idnEndIf then begin
if PeerList[NestDepth].ElsePeer <> ANode.Entry[i] then begin
Debugln(['New Peer for ',dbgs(PeerList[NestDepth].NodeType), ' to else same line']);
PeerList[NestDepth].ElsePeer := ANode.Entry[i]; // update closing node
end;
end
else begin
DebugLn('Ignoring invalid double else');
end;
If CurDepth <= 0 then begin
debugln(['Ignoring node with has no opening at all in line ', ANode.StartLine]);
end;
PeerList[NestDepth] := ANode.Entry[i];
if LowerNestDepth > NestDepth then
LowerNestDepth := NestDepth;
if (CurDepth >= MinOpenDepth) and (CurDepth <= MaxOpenDepth) then begin
// Opening Node on this line
assert(CurDepth = MaxOpenDepth, 'ConnectPeers: Same line peer skips opening node(s)');
case OpenList[OpenIdx(CurDepth)].NodeType of
idnIfdef, idnElseIf:
if OpenList[OpenIdx(CurDepth)].ElsePeer <> ANode.Entry[i] then begin
Debugln(['New Peer for ',dbgs(OpenList[OpenIdx(CurDepth)].NodeType), ' to else same line']);
OpenList[OpenIdx(CurDepth)].ElsePeer := ANode.Entry[i];
//dec(MaxOpenDepth); // Will be set with the current entry
end;
idnElse: DebugLn('Ignoring invalid double else (on same line)');
end;
end
else
If CurDepth >= 0 then begin
// Opening Node in previous line
PeerList[CurDepth] := ANode.Entry[i];
assert((MaxPeerDepth=-1) or ((MinPeerDepth <= MaxPeerDepth) and (CurDepth = MinPeerDepth-1)), 'ConnectPeers: skipped noeds during line scan');
if CurDepth < MinPeerDepth then MinPeerDepth := CurDepth;
if CurDepth > MaxPeerDepth then MaxPeerDepth := CurDepth;
end;
OpenList[OpenIdx(CurDepth)] := ANode.Entry[i]; // Store IfDef, with Index at end of IfDef (inside block)
if CurDepth < MinOpenDepth then MinOpenDepth := CurDepth;
if CurDepth > MaxOpenDepth then MaxOpenDepth := CurDepth;
end;
idnEndIf: begin
inc(NestDepth);
PeerList[NestDepth] := ANode.Entry[i];
if LowerNestDepth > NestDepth then
LowerNestDepth := NestDepth;
If CurDepth <= 0 then begin
debugln(['Ignoring node with has no opening at all in line', ANode.StartLine]);
dec(CurDepth);
continue; // This node has no opening node
end;
if (CurDepth >= MinOpenDepth) and (CurDepth <= MaxOpenDepth) then begin
// Opening Node on this line
assert(CurDepth = MaxOpenDepth, 'ConnectPeers: Same line peer skips opening node(s)');
if OpenList[OpenIdx(CurDepth)].EndIfPeer <> ANode.Entry[i] then begin
Debugln(['New Peer for ',dbgs(OpenList[OpenIdx(CurDepth)].NodeType), ' to endif same line']);
OpenList[OpenIdx(CurDepth)].EndIfPeer := ANode.Entry[i];
dec(MaxOpenDepth);
end;
end
else begin
// Opening Node in previous line
PeerList[CurDepth] := ANode.Entry[i];
assert((MaxPeerDepth=-1) or ((MinPeerDepth <= MaxPeerDepth) and (CurDepth = MinPeerDepth-1)), 'ConnectPeers: skipped noeds during line scan');
if CurDepth < MinPeerDepth then MinPeerDepth := CurDepth;
if CurDepth > MaxPeerDepth then MaxPeerDepth := CurDepth;
end;
dec(CurDepth);
end;
end;
end;
// Find peers in previous lines.
// Find peers in previous lines. MinPeerDepth <= 0 have no opening
// Opening (IfDef) nodes will be connected when there closing node is found.
for i := NestDepth downto LowerNestDepth do begin
for i := MaxPeerDepth downto Max(MinPeerDepth, 1) do begin
// Todo: MAybe optimize, if it can be known that an existing peer link is correct
//case PeerList[i].NodeType of
// idnElse: if PeerList[i].IfDefPeer <> nil then continue;
@ -1507,8 +1567,20 @@ begin
idnIfdef: begin
assert(PeerList[i].NodeType in [idnElse, idnElseIf, idnEndIf], 'PeerList[i].NodeType in [idnElse, idnEndIf] for other ifdef');
if PeerList[i].IfDefPeer <> OtherLine.Entry[j] then begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to ifdef other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
if OtherLine.Entry[j].GetPeer(PeerList[i].NodeType) <> nil then begin
debugln(['COMPARING MaxPeerdepth for ',dbgs(PeerList[i].NodeType), ' to ifdef other line']);
if (OtherLine.NestDepthAtNodeStart + OtherLine.Entry[j].RelativeNestDepth + 1 = i
// ANode.NestDepthAtNodeStart + PeerList[i].RelativeNestDepth
)
then begin
Debugln(['New Peer (REPLACE) for ',dbgs(PeerList[i].NodeType), ' to ifdef other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
end;
end
else begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to ifdef other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
end;
end;
j := -1;
break;
@ -1517,8 +1589,20 @@ begin
assert(PeerList[i].NodeType in [idnElse, idnElseIf, idnEndIf], 'PeerList[i].NodeType in [idnElse, idnEndIf] for other else');
if (PeerList[i].NodeType = idnEndIf) then begin
if PeerList[i].ElsePeer <> OtherLine.Entry[j] then begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].ElsePeer := OtherLine.Entry[j];
if OtherLine.Entry[j].GetPeer(PeerList[i].NodeType) <> nil then begin
debugln(['COMPARING MaxPeerdepth for ',dbgs(PeerList[i].NodeType), ' to else other line']);
if OtherLine.NestDepthAtNodeStart + OtherLine.Entry[j].RelativeNestDepth = i
// ANode.NestDepthAtNodeStart + PeerList[i].RelativeNestDepth
then begin
Debugln(['New Peer (REPLACE) for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].ElsePeer := OtherLine.Entry[j];
end;
end
else begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].ElsePeer := OtherLine.Entry[j];
end;
end;
j := -1;
end
@ -1526,8 +1610,19 @@ begin
if (PeerList[i].NodeType in [idnElseIf, idnElse]) and (OtherLine.Entry[j].NodeType = idnElseIf)
then begin
if PeerList[i].IfDefPeer <> OtherLine.Entry[j] then begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
if OtherLine.Entry[j].GetPeer(PeerList[i].NodeType) <> nil then begin
debugln(['COMPARING MaxPeerdepth for ',dbgs(PeerList[i].NodeType), ' to else other line']);
if OtherLine.NestDepthAtNodeStart + OtherLine.Entry[j].RelativeNestDepth = i
// ANode.NestDepthAtNodeStart + PeerList[i].RelativeNestDepth
then begin
Debugln(['New Peer (REPLACE) for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
end;
end
else begin
Debugln(['New Peer for ',dbgs(PeerList[i].NodeType), ' to else other line']);
PeerList[i].IfDefPeer := OtherLine.Entry[j];
end;
end;
j := -1;
end
@ -1825,6 +1920,10 @@ DebugLn(['change startline ', WorkNode.StartLine ,' to ', aLinePos]);
end;
assert(WorkNode.StartLine < aLinePos);
WorkLine := WorkNode.StartLine + WorkNode.ScanEndOffs;
if (WorkLine >= aLinePos) then
WorkNode.ScanEndOffs := aLinePos - 1 - WorkNode.StartLine;
WorkLine := WorkNode.StartLine + WorkNode.LastEntryEndLineOffs;
i := WorkNode.EntryCount - 1;
if (WorkLine >= aLinePos) and (i >= 0) then begin
@ -2068,7 +2167,7 @@ var
fn, fn2: TSynFoldNodeInfo;
LogStartX, LogEndX, LineLen, LineOffs: Integer;
Entry: TSynMarkupHighIfDefEntry;
i, c: Integer;
i, c, RelNestDepth, RelNestDepthNext: Integer;
NType: TSynMarkupIfdefNodeType;
begin
DebugLnEnter(['>> ScanLine ', ALine, ' ', dbgs(ANodeForLine), ' ', dbgs(ACheckOverlapOnCreateLine)]);
@ -2081,6 +2180,7 @@ begin
if (ANodeForLine <> nil) and (ANodeForLine.EntryCapacity < FoldNodeInfoList.Count) then
ANodeForLine.EntryCapacity := FoldNodeInfoList.Count;
NodesAddedCnt := 0;
RelNestDepthNext := 0;
LineTextLower := LowerCase(Lines[ToIdx(ALine)]);
LineLen := Length(LineTextLower);
@ -2102,11 +2202,13 @@ begin
// assert(LogStartX >= LogEndX, 'ifdef xpos found before end of previous ifdef');
LogEndX := FindCloseCurlyBracket(LogStartX+1, LineOffs) + 1;
RelNestDepth := RelNestDepthNext;
case TheDict.GetMatchAtChar(@LineTextLower[LogStartX], LineLen + 1 - LogStartX) of
1: // ifdef
begin
assert(sfaOpen in fn.FoldAction, 'sfaOpen in fn.FoldAction');
NType := idnIfdef;
inc(RelNestDepthNext);
end;
2: // else
begin
@ -2122,6 +2224,7 @@ begin
begin
assert(sfaClose in fn.FoldAction, 'sfaOpen in fn.FoldAction');
NType := idnEndIf;
dec(RelNestDepthNext);
end;
4: // ElseIf
begin
@ -2141,6 +2244,7 @@ begin
end;
Entry := GetEntry(LogStartX, LogEndX, LineOffs, NType);
Entry.FRelativeNestDepth := RelNestDepth;
if LineOffs > 0 then begin
if ANodeForLine.LastEntryEndLineOffs <> LineOffs then begin

View File

@ -46,6 +46,7 @@ type
function TestText3: TStringArray;
function TestText4: TStringArray;
function TestText5: TStringArray;
function TestText6: TStringArray;
procedure CheckNodes(AName: String; ALine: Integer;
AExp: array of TNodeExpect);
@ -422,6 +423,15 @@ begin
AddLine('{$Endif}' );
AddLine('' );
AddLine('' );
AddLine('' );
// 20
AddLine('{$IFDEF a}' );
AddLine('' );
// 1 - 9 11 - 21 22 - 29 30 - 37 38 - 46 48 - 56 58 - 68 69 - 77
AddLine('{$EndIf} {$IFDEF a} {$ELSE} {$ELSE} {$ENDIF} {$endif} {$IFDEF a} {$ENDIF} ');
AddLine('' );
AddLine('' );
AddLine('' );
end;
function TTestMarkupIfDef.TestText3: TStringArray;
@ -482,6 +492,42 @@ begin
AddLine('' );
end;
function TTestMarkupIfDef.TestText6: TStringArray;
procedure AddLine(s: String);
begin
SetLength(Result, Length(Result)+1);
Result[Length(Result)-1] := s;
end;
begin
// 1
AddLine('//' );
AddLine('{$IFDEF a}' );
AddLine('' );
AddLine('' );
// 5
AddLine('' );
AddLine(' {$IFDEF b}' );
AddLine('' );
AddLine('' );
AddLine('' );
// 10
AddLine(' {$IFDEF c}' );
AddLine('' );
AddLine('' );
AddLine('' );
AddLine(' {$Endif}' );
// 15
AddLine('' );
AddLine('' );
AddLine('' );
AddLine(' {$Endif}' );
AddLine('' );
// 20
AddLine('' );
end;
function TTestMarkupIfDef.CreateTheHighLighter: TSynCustomFoldHighlighter;
begin
Result := TSynPasSyn.Create(nil);
@ -927,6 +973,15 @@ FTestTree.DebugPrint(true);DebugLn;
CheckNodesXY('', 6, [3, 14], 0);
// Insert IFDEF into empty text
ReCreateEditForTreeTest(TestTextNoIfDef);
FTestTree.ValidateRange(1, 5, FOpenings);
SynEdit.TextBetweenPoints[point(1, 3),point(1, 3)] := '{$IFDEF a}';
FTestTree.ValidateRange(1, 5, FOpenings);
FTestTree.DebugPrint(true);DebugLn;
CheckNodesXY('Insert IFDEF into empty text', 3, [1,11], 0);
FTestTree.DiscardOpeningList(FOpenings);
FOpenings := nil;;
FTestTree.Free;
@ -1128,16 +1183,9 @@ DebugLn('--------');FTestTree.DebugPrint(true);
FTestTree.ValidateRange(1, 18, FOpenings);
DebugLn('--------');FTestTree.DebugPrint(true);
// ONe and only one of the 2 ends should have a peer
nd := FTestTree.FindNodeAtPosition(33, afmNil);
if nd.HasNode and (nd.EntryCount > 0) and (nd.Entry[0].EndIfPeer.Line.GetPosition = 4) then begin
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef, EpEnd(4, 1)) ]);
CheckNodes(n, 4, [ ExpN( 1, 9, idnEndIf, EpIf(2, 1)) ]);
CheckNodes(n, 6, [ ExpN( 1, 9, idnEndIf, EpIf(-1, -1)) ]); // must not have a peer
end else begin
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef, EpEnd(6, 1)) ]);
CheckNodes(n, 4, [ ExpN( 1, 9, idnEndIf, EpIf(-1, -1)) ]); // must not have a peer
CheckNodes(n, 6, [ ExpN( 1, 9, idnEndIf, EpIf(2, 1)) ]);
end;
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef, EpEnd(4, 1)) ]);
CheckNodes(n, 4, [ ExpN( 1, 9, idnEndIf, EpIf(2, 1)) ]);
CheckNodes(n, 6, [ ExpN( 1, 9, idnEndIf, EpIf(-1, -1)) ]); // must not have a peer
// One and only one else may be connected to if and one (but maybe the other) to endif
CheckNodes(n,10, [ ExpN( 1,11, idnIfdef) ]); // EpElse(12, 1) // or 14
CheckNodes(n,12, [ ExpN( 1, 8, idnElse) ]);
@ -1354,6 +1402,78 @@ DebugLn('--------');FTestTree.DebugPrint(true);
{%region Insert If/end to create invalid peering, that must be resolved }
n := 'Peers, TestText6: Resolve left-over binding: ' +
'Insert Ifdef in visible part, with node inbetween';
ReCreateEditForTreeTest(TestText6);
FTestTree.ValidateRange(1, 20, FOpenings);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef ) ]);
CheckNodes(n, 6, [ ExpN( 2,12, idnIfdef, EpEnd(18, 2)) ]);
CheckNodes(n,10, [ ExpN( 3,13, idnIfdef, EpEnd(14, 3)) ]);
CheckNodes(n,14, [ ExpN( 3,11, idnEndIf, EpIf(10, 3)) ]);
CheckNodes(n,18, [ ExpN( 2,10, idnEndIf, EpIf( 6, 2)) ]);
SynEdit.TextBetweenPoints[point(1, 8),point(1, 8)] := ' {$IfDef X}';
FTestTree.ValidateRange(1, 20, FOpenings);
DebugLn('--------');FTestTree.DebugPrint(true);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef ) ]);
CheckNodes(n, 6, [ ExpN( 2,12, idnIfdef ) ]);
CheckNodes(n, 8, [ ExpN( 4,14, idnIfdef, EpEnd(18, 2)) ]);
CheckNodes(n,10, [ ExpN( 3,13, idnIfdef, EpEnd(14, 3)) ]);
CheckNodes(n,14, [ ExpN( 3,11, idnEndIf, EpIf(10, 3)) ]);
CheckNodes(n,18, [ ExpN( 2,10, idnEndIf, EpIf( 8, 4)) ]);
n := n + ' Remove again';
SynEdit.TextBetweenPoints[point(1, 8),point(14, 8)] := '';
FTestTree.ValidateRange(1, 20, FOpenings);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef ) ]);
CheckNodes(n, 6, [ ExpN( 2,12, idnIfdef, EpEnd(18, 2)) ]);
CheckNodes(n,10, [ ExpN( 3,13, idnIfdef, EpEnd(14, 3)) ]);
CheckNodes(n,14, [ ExpN( 3,11, idnEndIf, EpIf(10, 3)) ]);
CheckNodes(n,18, [ ExpN( 2,10, idnEndIf, EpIf( 6, 2)) ]);
{%endregion Insert If/end to create invalid peering, that must be resolved }
{%region Insert If/end to create invalid peering, that must be resolved }
n := 'Peers, TestText6: Relosve left-over binding: ' +
'Insert Ifdef in visible part, with node inbetween AT end of outer ifdef';
ReCreateEditForTreeTest(TestText6);
FTestTree.ValidateRange(1, 20, FOpenings);
SynEdit.TextBetweenPoints[point(12, 6),point(12, 6)] := ' {$IfDef X}';
FTestTree.ValidateRange(1, 20, FOpenings);
DebugLn('--------');FTestTree.DebugPrint(true);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef ) ]);
CheckNodes(n, 6, [ ExpN( 2,12, idnIfdef ),
ExpN(15,25, idnIfdef, EpEnd(18, 2))
]);
CheckNodes(n,10, [ ExpN( 3,13, idnIfdef, EpEnd(14, 3)) ]);
CheckNodes(n,14, [ ExpN( 3,11, idnEndIf, EpIf(10, 3)) ]);
CheckNodes(n,18, [ ExpN( 2,10, idnEndIf, EpIf( 6, 15)) ]);
n := n + ' Remove again';
SynEdit.TextBetweenPoints[point(12, 6),point(25, 6)] := '';
FTestTree.ValidateRange(1, 20, FOpenings);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef ) ]);
CheckNodes(n, 6, [ ExpN( 2,12, idnIfdef, EpEnd(18, 2)) ]);
CheckNodes(n,10, [ ExpN( 3,13, idnIfdef, EpEnd(14, 3)) ]);
CheckNodes(n,14, [ ExpN( 3,11, idnEndIf, EpIf(10, 3)) ]);
CheckNodes(n,18, [ ExpN( 2,10, idnEndIf, EpIf( 6, 2)) ]);
{%endregion Insert If/end to create invalid peering, that must be resolved }
{%region }
n := 'P';
ReCreateEditForTreeTest(TestText2);
FTestTree.ValidateRange(1, 24, FOpenings);
FTestTree.ValidateRange(1, 24, FOpenings);
{%endregion }
{%endregion peers}
@ -1430,6 +1550,7 @@ DebugLn('--------');FTestTree.DebugPrint(true);
FTestTree.ValidateRange(1, 6, FOpenings);
DebugLn('--------');FTestTree.DebugPrint(true);
AssertEquals(n + '2 requests ' , 2, FNodeStateRequests.Count);
AssertEquals(n + 'Got reqest for 2/1' , '1', FNodeStateRequests.Values['2/1']);
AssertEquals(n + 'Got reqest for 4/1' , '1', FNodeStateRequests.Values['4/1']);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef, idnEnabled), ExpN(13,21, idnEndIf, idnEnabled ) ]);
@ -1440,12 +1561,32 @@ DebugLn('--------');FTestTree.DebugPrint(true);
FNodeStateRequests.Clear;
FTestTree.SetNodeState(2,1, idnNotInCode);
DebugLn('--------');FTestTree.DebugPrint(true);
AssertEquals(n + 'Got NO reqest for 2/1' , '', FNodeStateRequests.Values['2/1']);
AssertEquals(n + 'Got NO reqest for 4/1' , '', FNodeStateRequests.Values['4/1']);
AssertEquals(n + 'NO requests ' , 0, FNodeStateRequests.Count);
//AssertEquals(n + 'Got NO reqest for 2/1' , '', FNodeStateRequests.Values['2/1']);
//AssertEquals(n + 'Got NO reqest for 4/1' , '', FNodeStateRequests.Values['4/1']);
CheckNodes(n, 2, [ ExpN( 1,11, idnIfdef, idnNotInCode), ExpN(13,21, idnEndIf ) ]);
CheckNodes(n, 4, [ ExpN( 1,11, idnIfdef, idnDisabled), ExpN(13,21, idnEndIf, idnDisabled ) ]);
{%region Insert IFDEF into empty text }
FNodeStateResponses.Clear;
FNodeStateRequests.Clear;
ReCreateEditForTreeTest(TestTextNoIfDef);
FTestTree.OnNodeStateRequest := @TesTNodeStateHandler;
FTestTree.ValidateRange(1, 5, FOpenings);
FTestTree.DebugPrint(true);DebugLn;
AssertEquals(n + 'NO requests ' , 0, FNodeStateRequests.Count);
SynEdit.TextBetweenPoints[point(1, 3),point(1, 3)] := '{$IFDEF a}';
FTestTree.DebugPrint(true);DebugLn;
FTestTree.ValidateRange(1, 5, FOpenings);
FTestTree.DebugPrint(true);DebugLn;
AssertEquals(n + 'one requests ' , 1, FNodeStateRequests.Count);
AssertEquals(n + 'Got reqest for 3/1' , '1', FNodeStateRequests.Values['3/1']);
CheckNodesXY('Insert IFDEF into empty text', 3, [1,11], 0);
{%endregion Insert IFDEF into empty text }
FTestTree.DiscardOpeningList(FOpenings);
FOpenings := nil;