SynEdit: Refactor/Cleanup Highlighter and Current-Word-Markup

git-svn-id: trunk@19079 -
This commit is contained in:
martin 2009-03-23 21:48:43 +00:00
parent 941ebd42a6
commit 4fb2ec2495
4 changed files with 322 additions and 227 deletions

View File

@ -153,6 +153,7 @@ type
fAttrChangeHooks: TSynNotifyEventChain;
{$IFDEF SYN_LAZARUS}
FCapabilities: TSynHighlighterCapabilities;
FCurrentLines: TSynEditStrings;
{$ENDIF}
fUpdateCount: integer; //mh 2001-09-13
fEnabled: Boolean;
@ -176,7 +177,6 @@ type
procedure SetDefaultFilter(Value: string); virtual;
procedure SetSampleSource(Value: string); virtual;
// code fold - only valid if hcCodeFolding in Capabilities
function GetLastLineCodeFoldLevelFix: integer; virtual;
public
procedure DefHighlightChange(Sender: TObject);
{$IFNDEF SYN_CPPB_1} class {$ENDIF}
@ -220,14 +220,12 @@ type
property IdentChars: TSynIdentChars read GetIdentChars;
property WordBreakChars: TSynIdentChars read fWordBreakChars write SetWordBreakChars;
property LanguageName: string read GetLanguageName;
property CurrentLines: TSynEditStrings read FCurrentLines write FCurrentLines;
// folding
Function GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings;
out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean; virtual;
(* Methds for folding *)
function MinimumCodeFoldBlockLevel: integer; virtual;
function CurrentCodeFoldBlockLevel: integer; virtual;
property LastLineCodeFoldLevelFix: integer read GetLastLineCodeFoldLevelFix;
function LastLineCodeFoldLevelFix: integer; virtual;
public
property AttrCount: integer read GetAttribCount;
property Attribute[idx: integer]: TSynHighlighterAttributes
@ -1087,13 +1085,6 @@ begin
fAttrChangeHooks.Remove(ANotifyEvent);
end;
function TSynCustomHighlighter.GetWordTriplet(LogicalCaret: TPoint;
Lines: TSynEditStrings; out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer
): Boolean;
begin
Result := False;
end;
function TSynCustomHighlighter.MinimumCodeFoldBlockLevel: integer;
begin
Result := 0;
@ -1111,7 +1102,7 @@ begin
end;
end;
function TSynCustomHighlighter.GetLastLineCodeFoldLevelFix: integer;
function TSynCustomHighlighter.LastLineCodeFoldLevelFix: integer;
begin
Result := 0;
end;

View File

@ -94,6 +94,20 @@ type
TSynCustomHighlighterRanges = class;
TSynFoldAction = (sfaOpen, // At this node a new Fold can start
sfaClose, // At this node a fold ends
sfaMarkup, // This node can be highlighted, by the matching Word-Pair Markup
sfaInvalid // Wrong Index
);
TSynFoldActions = set of TSynFoldAction;
TSynFoldNodeInfo = record
LogXStart, LogXEnd: Integer; // -1 previous line
FoldLvlStart, FoldLvlEnd: Integer;
FoldAction: TSynFoldActions;
FoldType: Pointer;
end;
{ TSynCustomFoldHighlighter }
TSynCustomFoldHighlighter = class(TSynCustomHighlighter)
@ -104,6 +118,8 @@ type
protected
FMinimumCodeFoldBlockLevel: integer;
protected
function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; virtual;
function GetFoldNodeInfoCount(Line: Integer): Integer; virtual;
property CodeFoldRange: TSynCustomHighlighterRange read FCodeFoldRange;
function GetRangeClass: TSynCustomHighlighterRangeClass; virtual;
function TopCodeFoldBlockType: Pointer;
@ -125,6 +141,14 @@ type
function MinimumCodeFoldBlockLevel: integer; override;
function CurrentCodeFoldBlockLevel: integer; override;
// requires CurrentLines;
function MinimumFoldLevel(Index: Integer): integer; virtual; abstract;
function EndFoldLevel(Index: Integer): integer; virtual; abstract;
function LastLineFoldLevelFix(Index: Integer): integer; virtual; abstract;
property FoldNodeInfo[Line, Index: Integer]: TSynFoldNodeInfo read GetFoldNodeInfo;
property FoldNodeInfoCount[Line: Integer]: Integer read GetFoldNodeInfoCount;
end;
TSynCustomHighlighterClass = class of TSynCustomFoldHighlighter;
@ -260,6 +284,16 @@ begin
Result:=0;
end;
function TSynCustomFoldHighlighter.GetFoldNodeInfoCount(Line: Integer): Integer;
begin
Result := 0;
end;
function TSynCustomFoldHighlighter.GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo;
begin
Result.FoldAction := [sfaInvalid];
end;
function TSynCustomFoldHighlighter.GetRangeClass: TSynCustomHighlighterRangeClass;
begin
Result:=TSynCustomHighlighterRange;

View File

@ -27,7 +27,7 @@ interface
uses
Classes, SysUtils, Graphics, SynEditMarkup, SynEditMiscClasses, Controls,
LCLProc, SynEditHighlighter;
LCLProc, SynEditHighlighter, SynEditHighlighterFoldBase;
type
@ -108,8 +108,92 @@ end;
procedure TSynEditMarkupWordGroup.FindMatchingWords(PhysCaret: TPoint;
out Word1, Word2, Word3: TWordPoint);
var
LCnt: Integer;
HL: TSynCustomFoldHighlighter;
function FindEndNode(StartNode: TSynFoldNodeInfo;
var YIndex, NIndex: Integer): TSynFoldNodeInfo;
begin
repeat
inc(NIndex);
Result := HL.FoldNodeInfo[YIndex, NIndex];
until (sfaInvalid in Result.FoldAction) or
(Result.FoldLvlEnd <= StartNode.FoldLvlStart);
if not (sfaInvalid in Result.FoldAction) then
exit;
inc(YIndex);
while (YIndex < LCnt) and
(HL.MinimumFoldLevel(YIndex) > StartNode.FoldLvlStart) do
inc(YIndex);
if YIndex = LCnt then
exit;
NIndex := -1;
repeat
inc(NIndex);
Result:= HL.FoldNodeInfo[YIndex, NIndex];
until (sfaInvalid in Result.FoldAction) or
(Result.FoldLvlEnd <= StartNode.FoldLvlStart);
if (Result.LogXEnd = 0) then
Result.FoldAction := [sfaInvalid]; // LastLine closed Node(maybe force-closed?)
end;
function FindStartNode(EndNode: TSynFoldNodeInfo;
var YIndex, NIndex: Integer): TSynFoldNodeInfo;
begin
repeat
dec(NIndex);
Result := HL.FoldNodeInfo[YIndex, NIndex];
until (sfaInvalid in Result.FoldAction) or
(Result.FoldLvlStart <= EndNode.FoldLvlEnd);
if not(sfaInvalid in Result.FoldAction) then
exit;
dec(YIndex);
while (YIndex >= 0) and (HL.MinimumFoldLevel(YIndex) > EndNode.FoldLvlEnd) do
dec(YIndex);
if YIndex < 0 then
exit;
NIndex := HL.FoldNodeInfoCount[YIndex];
repeat
dec(NIndex);
Result:= HL.FoldNodeInfo[YIndex, NIndex];
until (sfaInvalid in Result.FoldAction) or
(Result.FoldLvlStart <= EndNode.FoldLvlEnd);
end;
function FindMultiNode(OrigNode: TSynFoldNodeInfo;
var YIndex, NIndex: Integer): TSynFoldNodeInfo;
var
i: LongInt;
begin
i := NIndex;
repeat
dec(NIndex);
Result := HL.FoldNodeInfo[YIndex, NIndex];
if (sfaMarkup in Result.FoldAction) and
(Result.LogXStart = OrigNode.LogXStart) and (Result.LogXEnd > 0)
then
exit;
until (sfaInvalid in Result.FoldAction) or (Result.LogXStart <> OrigNode.LogXStart);
NIndex := i;
repeat
inc(NIndex);
Result := HL.FoldNodeInfo[YIndex, NIndex];
if (sfaMarkup in Result.FoldAction) and
(Result.LogXStart = OrigNode.LogXStart) and (Result.LogXEnd > 0)
then
exit;
until (sfaInvalid in Result.FoldAction) or (Result.LogXStart <> OrigNode.LogXStart);
Result.FoldAction := [sfaInvalid];
end;
var
LogCaretXY: TPoint;
i, i2, i3, y, y1, y2: integer;
Node1, Node2, Node3: TSynFoldNodeInfo;
begin
Word1.Y := -1;
Word2.Y := -1;
@ -119,34 +203,86 @@ begin
then
Exit;
// Check for Begin-End like pairs
if not assigned(FHighlighter) then Exit;
LogCaretXY := TSynEdit(SynEdit).PhysicalToLogicalPos(PhysCaret);
if FHighlighter.GetWordTriplet(LogCaretXY, Lines,
Word1.Y, Word1.X, Word1.X2,
Word3.Y, Word3.X, Word3. X2,
Word2.Y, Word2.X, Word2. X2
) then
begin
if Word1.Y > 0 then begin
Word1.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word1.X, Word1.Y)).X;
Word1.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word1.X2, Word1.Y)).X;
end;
if Word2.Y > 0 then begin
Word2.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word2.X, Word2.Y)).X;
Word2.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word2.X2, Word2.Y)).X;
end;
if Word3.Y > 0 then begin
Word3.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word3.X, Word3.Y)).X;
Word3.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word3.X2, Word3.Y)).X;
end;
if not (FHighlighter is TSynCustomFoldHighlighter) then
exit;
hl := TSynCustomFoldHighlighter(FHighlighter);
LogCaretXY := TSynEdit(SynEdit).PhysicalToLogicalPos(PhysCaret);
y := LogCaretXY.Y - 1;
LCnt := Lines.Count;
HL.CurrentLines := Lines;
i := 0;
repeat
Node1 := HL.FoldNodeInfo[y, i];
inc(i);
until (sfaInvalid in Node1.FoldAction) or
((Node1.LogXEnd >= LogCaretXY.X - 1) and (Node1.LogXEnd > 0));
while not(Node1.FoldAction * [sfaInvalid, sfaMarkup] <> [])
and (Node1.LogXStart <= LogCaretXY.X - 1) do
begin
Node1 := HL.FoldNodeInfo[y, i];
inc(i);
end;
if (Node1.LogXStart > LogCaretXY.X - 1) or not(sfaMarkup in Node1.FoldAction) then
exit;
dec(i);
if sfaOpen in Node1.FoldAction then begin
y1 := y;
Node2 := FindEndNode(Node1, y, i);
if (sfaInvalid in Node2.FoldAction) then
exit;
y2 := y;
i2 := i;
i3 := i;
Node3 := FindMultiNode(Node2, y, i3);
end else begin
Node2 := Node1;
i3 := i;
Node3 := FindMultiNode(Node2, y, i3);
y2 := y;
i2 := i;
Node1 := FindStartNode(Node2, y, i);
if (sfaInvalid in Node1.FoldAction) then
exit;
y1 := y;
end;
// In Case GetWordTriplet did set them
Word1.Y := -1;
Word2.Y := -1;
Word3.Y := -1;
y := y2;
if not(sfaInvalid in Node3.FoldAction) then
Node3 := FindStartNode(Node3, y, i);
Word1.Y := y1 + 1;
Word1.X := Node1.LogXStart + 1;
Word1.X2 := Node1.LogXEnd + 1;
Word2.Y := y2 + 1;
Word2.X := Node2.LogXStart + 1;
Word2.X2 := Node2.LogXEnd + 1;
if not(sfaInvalid in Node3.FoldAction) then begin
Word3 := Word2;
if i3 > i2 then begin
Word2 := Word1;
Word1.Y := y + 1;
Word1.X := Node3.LogXStart + 1;
Word1.X2 := Node3.LogXEnd + 1;
end else begin
Word2.Y := y + 1;
Word2.X := Node3.LogXStart + 1;
Word2.X2 := Node3.LogXEnd + 1;
end;
end;
if Word1.Y > 0 then begin
Word1.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word1.X, Word1.Y)).X;
Word1.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word1.X2, Word1.Y)).X;
end;
if Word2.Y > 0 then begin
Word2.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word2.X, Word2.Y)).X;
Word2.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word2.X2, Word2.Y)).X;
end;
if Word3.Y > 0 then begin
Word3.X := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word3.X, Word3.Y)).X;
Word3.X2 := TSynEdit(SynEdit).LogicalToPhysicalPos(Point(Word3.X2, Word3.Y)).X;
end;
end;
procedure TSynEditMarkupWordGroup.DoCaretChanged(OldCaret: TPoint);

View File

@ -57,7 +57,7 @@ uses
{$ELSE}
Windows, Messages,
{$ENDIF}
Classes, Registry, Controls, SynEditHighlighterFoldBase,
Classes, Registry, Controls, SynEditHighlighterFoldBase, SynEditMiscProcs,
SynEditTypes, SynEditHighlighter, SynEditTextBuffer, SynEditTextBase;
type
@ -195,6 +195,10 @@ type
{$ENDIF}
fD4syntax: boolean;
{$IFDEF SYN_LAZARUS}
FCatchNodeInfo: Boolean;
FNodeInfoLine, FNodeInfoCount: Integer;
FNodeInfoList: Array of TSynFoldNodeInfo;
procedure GrowNodeInfoList;
function GetPasCodeFoldRange: TSynPasSynRange;
procedure SetCompilerMode(const AValue: TPascalCompilerMode);
function TextComp(aText: PChar): Boolean;
@ -322,7 +326,11 @@ type
procedure SymbolProc;
procedure UnknownProc;
procedure SetD4syntax(const Value: boolean);
procedure InitNode(var Node: TSynFoldNodeInfo; EndOffs: Integer;
ABlockType: TPascalCodeFoldBlockType);
protected
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;
@ -334,7 +342,6 @@ type
function GetRangeClass: TSynCustomHighlighterRangeClass; override;
{$ENDIF}
procedure EndCodeFoldBlockLastLine;
function GetLastLineCodeFoldLevelFix: integer; override;
property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange;
public
{$IFNDEF SYN_CPPB_1} class {$ENDIF}
@ -365,11 +372,14 @@ type
procedure EnumUserSettings(settings: TStrings); override;
//code fold
function LastLineCodeFoldLevelFix: integer; override;
{$IFDEF SYN_LAZARUS}
function TopPascalCodeFoldBlockType: TPascalCodeFoldBlockType;
{$ENDIF}
Function GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings;
out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean; override;
function MinimumFoldLevel(Index: Integer): integer; override;
function EndFoldLevel(Index: Integer): integer; override;
function LastLineFoldLevelFix(Index: Integer): integer; override;
published
property AsmAttri: TSynHighlighterAttributes read fAsmAttri write fAsmAttri;
property CommentAttri: TSynHighlighterAttributes read fCommentAttri
@ -746,6 +756,13 @@ begin
//DebugLn(['TSynPasSyn.SetCompilerMode FCompilerMode=',ord(FCompilerMode),' FNestedComments=',FNestedComments]);
end;
procedure TSynPasSyn.GrowNodeInfoList;
begin
if FNodeInfoCount < length(FNodeInfoList) then
exit;
SetLength(FNodeInfoList, FNodeInfoCount + Max(10, FNodeInfoCount div 4));
end;
function TSynPasSyn.GetPasCodeFoldRange: TSynPasSynRange;
begin
Result := TSynPasSynRange(CodeFoldRange);
@ -1646,6 +1663,7 @@ begin
fRange := [];
fAsmStart := False;
fDefaultFilter := SYNS_FilterPascal;
FNodeInfoLine := -1;
end; { Create }
procedure TSynPasSyn.SetLine(const NewValue: string; LineNumber:Integer);
@ -1663,8 +1681,10 @@ begin
fLine := PChar(NewValue);
Run := 0;
{$ENDIF}
FNodeInfoLine := -1;
fLineNumber := LineNumber;
Next;
if not FCatchNodeInfo then
Next;
end; { SetLine }
procedure TSynPasSyn.AddressOpProc;
@ -2210,6 +2230,7 @@ begin
{$ELSE}
fRange := TRangeStates(PtrUInt(Value));
{$ENDIF}
FNodeInfoLine := -1;
FStartCodeFoldBlockLevel := FMinimumCodeFoldBlockLevel;
end;
@ -2259,189 +2280,55 @@ begin
Result := TPascalCodeFoldBlockType(PtrUInt(p));
end;
// ToDO: pass in Max for the search lines (Begin must be found always)
function TSynPasSyn.GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings;
out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean;
function GetLevelBeforeCaret: Integer;
var
l: Integer;
begin
SetRange(Lines.Ranges[LogicalCaret.Y - 1]);
FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel;
l := CurrentCodeFoldBlockLevel;
SetLine(Lines[LogicalCaret.Y - 1], LogicalCaret.Y - 1);
if (MinimumCodeFoldBlockLevel < CurrentCodeFoldBlockLevel)
then Result := MinimumCodeFoldBlockLevel
else Result := l;
while (Run <= LogicalCaret.x - 1) and not GetEol do begin
if (Run = LogicalCaret.x-1) and (Result <> CurrentCodeFoldBlockLevel) then
break;
FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel;
l := CurrentCodeFoldBlockLevel;
Next;
if (MinimumCodeFoldBlockLevel < CurrentCodeFoldBlockLevel)
then Result := MinimumCodeFoldBlockLevel
else Result := l;
end;
end;
function FindBegin(EndY, EndX, SeekLevel: Integer; out X1, X2: Integer;
out FoldType: TPascalCodeFoldBlockType): integer; // Returns Line
var
MinLvl: Integer;
begin
Result := EndY;
MinLvl := 0; // Search the current line always
repeat
SetRange(Lines.Ranges[Result - 1]);
//PasCodeFoldRange.MinimumCodeFoldBlockLevel;
if (EndX > 0) and (MinLvl <= SeekLevel) then begin
// Search in current Line
X1 := -1;
// Use MinimumCodefoldlevel to detect theimplicit end of "var"/"type" blocks at the next "begin"
FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel;
MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel; // Before SetLine = LastLine's MinLvl
SetLine(Lines[Result - 1], Result - 1);
while (Run <= EndX) and not GetEol do begin
if (MinimumCodeFoldBlockLevel <= SeekLevel) then begin
X1 := fTokenPos;
X2 := Run;
FoldType := TopPascalCodeFoldBlockType;
end;
FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel;
Next;
end;
if X1 >= 0 then exit;
end
else
MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel; // Before SetLine = LastLine's MinLvl
// Search previous lines
EndX := MaxInt;
dec(Result);
until Result = 0; // should always exit before
end;
function FindEnd(BeginY, BeginX2, SeekLevel: Integer;
out X1, X2, LvlBefore: Integer): integer; // Returns Line
var
c, MinLvl : Integer;
begin
Result := BeginY;
c := Lines.Count;
MinLvl := 0; // CurrentLine always has samller Minlevel
repeat
SetRange(Lines.Ranges[Result-1]);
if (MinLvl < SeekLevel) then begin
// Search in current Line
LvlBefore := CurrentCodeFoldBlockLevel;
SetLine(Lines[Result - 1], Result - 1);
if (FTokenPos < BeginX2) then
begin
while (FTokenPos < BeginX2) and not GetEol do
Next;
FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel;
end;
while not GetEol do
begin
if CurrentCodeFoldBlockLevel < SeekLevel then
begin
X1 := fTokenPos;
X2 := Run;
exit
end
else if (MinimumCodeFoldBlockLevel < SeekLevel) or
(CurrentCodeFoldBlockLevel + LastLineCodeFoldLevelFix < SeekLevel)
then
exit(-1); // This block ended in the previous line (implicit end)
LvlBefore := CurrentCodeFoldBlockLevel;
Next;
end;
end;
// Search next lines
BeginX2 := 0;
inc(Result);
if Result < c-1 then begin
SetRange(Lines.Ranges[Result]);
MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel;
end else begin
MinLvl := 0;
end;
until Result >= c;
Result := -1;
end;
function TSynPasSyn.MinimumFoldLevel(Index: Integer): integer;
var
CurStartLevel, CurEndLevel, CurStartPosX, CurEndPosX, CurPosY: Integer;
EndStartLevel: Integer;
ft, ft2: TPascalCodeFoldBlockType;
r: Pointer;
begin
Result := False;
CurPosY := LogicalCaret.Y;
CurStartLevel := GetLevelBeforeCaret;
CurEndLevel := CurrentCodeFoldBlockLevel;
CurStartPosX := fTokenPos; // 0 based
CurEndPosX := Run; // 0 based
IF CurEndLevel > CurStartLevel then begin
// block open: begin or middle
if not (TopPascalCodeFoldBlockType in PascalWordTrippletRanges) then
exit;
Y1 := CurPosY;
XB1 := CurStartPosX;
XE1 := CurEndPosX;
Y3 := FindEnd(CurPosY, CurEndPosX, CurEndLevel, XB3, XE3, EndStartLevel);
if Y3 < 0 then exit(false);
Result := true;
if (EndStartLevel - CurrentCodeFoldBlockLevel = 1) then begin;
Y2:=-2;
end else begin
if CurStartLevel = CurrentCodeFoldBlockLevel
then Y2 := FindBegin(Y3, XB3, CurrentCodeFoldBlockLevel+1, XB2, XE2, ft)
else Y2 := FindBegin(Y3, XB3, CurrentCodeFoldBlockLevel, XB2, XE2, ft);
if not (ft in PascalWordTrippletRanges) then
Y2 := -1;
end;
end
if Index = CurrentLines.Count - 1 then exit(0);
r := CurrentLines.Ranges[Index + 1]; // stored as the start of the next line
if (r <> nil) and (r <> NullRange) then
Result := TSynPasSynRange(r).MinimumCodeFoldBlockLevel
else
if CurStartLevel - CurEndLevel = 1 then begin
// block end, 1 lvl
Y1 := FindBegin(CurPosY, CurStartPosX, CurEndLevel, XB1, XE1, ft);
if not (ft in PascalWordTrippletRanges) then
exit;
Y2 := CurPosY;
XB2 := CurStartPosX;
XE2 := CurEndPosX;
Y3 := -2;
Result := true;
end
else
if CurEndLevel < CurStartLevel then begin
// block end, 2 lvl
Y2 := FindBegin(CurPosY, CurStartPosX, CurEndLevel+1, XB2, XE2, ft);
Y1 := FindBegin(Y2, XB2, CurEndLevel, XB1, XE1, ft2);
if not (ft in PascalWordTrippletRanges) then
Y2 := -1;
if not (ft2 in PascalWordTrippletRanges) then
Y1 := -1;
if (Y2 = -1) and (Y1 = -1) then
exit;
Y3 := CurPosY;
XB3 := CurStartPosX;
XE3 := CurEndPosX;
Result := true;
end;
Result := 0;
end;
inc(XB1);
inc(XE1);
inc(XB2);
inc(XE2);
inc(XB3);
inc(XE3);
function TSynPasSyn.EndFoldLevel(Index: Integer): integer;
var
r: Pointer;
begin
if Index = CurrentLines.Count - 1 then exit(0);
r := CurrentLines.Ranges[Index + 1]; // stored as the start of the next line
if (r <> nil) and (r <> NullRange) then
Result := TSynPasSynRange(r).CodeFoldStackSize
else
Result := 0;
end;
function TSynPasSyn.LastLineFoldLevelFix(Index: Integer): integer;
var
r: Pointer;
begin
if Index = CurrentLines.Count - 1 then exit(0);
r := CurrentLines.Ranges[Index + 1]; // stored as the start of the next line
if (r <> nil) and (r <> NullRange) then
Result := TSynPasSynRange(r).LastLineCodeFoldLevelFix
else
Result := 0;
end;
procedure TSynPasSyn.InitNode(var Node: TSynFoldNodeInfo; EndOffs: Integer;
ABlockType: TPascalCodeFoldBlockType);
begin
Node.LogXStart := Run;
Node.LogXEnd := Run + fStringLen;
Node.FoldLvlStart := CurrentCodeFoldBlockLevel;
Node.FoldLvlEnd := CurrentCodeFoldBlockLevel + EndOffs;
Node.FoldType := Pointer(PtrInt(ABlockType));
if ABlockType in PascalWordTrippletRanges then
Node.FoldAction := [sfaMarkup]
else
Node.FoldAction := [];
end;
function TSynPasSyn.StartPascalCodeFoldBlock(
@ -2451,15 +2338,29 @@ var
p: PtrInt;
begin
p := 0;
if FCatchNodeInfo and not SubBlock then begin // exclude subblocks, because they do not increase the foldlevel yet
GrowNodeInfoList;
InitNode(FNodeInfoList[FNodeInfoCount], +1, ABlockType);
if not SubBlock then
include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaOpen);
inc(FNodeInfoCount);
end;
if SubBlock then
p := PtrInt(CountPascalCodeFoldBlockOffset);
Result:=TSynCustomCodeFoldBlock(
inherited StartCodeFoldBlock(p+Pointer(PtrInt(ABlockType)), not SubBlock));
inherited StartCodeFoldBlock(p+Pointer(PtrInt(ABlockType)), not SubBlock));
end;
procedure TSynPasSyn.EndCodeFoldBlock(DecreaseLevel: Boolean);
begin
DecreaseLevel := TopCodeFoldBlockType < CountPascalCodeFoldBlockOffset;
if FCatchNodeInfo and DecreaseLevel then begin // exclude subblocks, because they do not increase the foldlevel yet
GrowNodeInfoList;
InitNode(FNodeInfoList[FNodeInfoCount], -1, TopPascalCodeFoldBlockType);
if DecreaseLevel then
include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaClose);
inc(FNodeInfoCount);
end;
inherited EndCodeFoldBlock(DecreaseLevel);
end;
@ -2468,9 +2369,9 @@ begin
if TopPascalCodeFoldBlockType <> cfbtBeginEnd then
exit;
while TopPascalCodeFoldBlockType = cfbtBeginEnd do
EndCodeFoldBlock;
EndCodeFoldBlockLastLine;
if TopPascalCodeFoldBlockType = cfbtProcedure then
EndCodeFoldBlock; // This procedure did have a begin/end block, so it must end too
EndCodeFoldBlockLastLine; // This procedure did have a begin/end block, so it must end too
end;
procedure TSynPasSyn.EndCodeFoldBlockLastLine;
@ -2484,12 +2385,45 @@ begin
end;
end;
function TSynPasSyn.GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo;
var
i: LongInt;
begin
if FNodeInfoLine <> Line then begin
FCatchNodeInfo := True;
FNodeInfoCount := 0;
SetRange(CurrentLines.Ranges[Line]);
SetLine(CurrentLines[Line], Line);
fStringLen := 0;
i := LastLineFoldLevelFix(Line);
while i < 0 do begin
EndCodeFoldBlock;
inc(i);
end;
NextToEol;
FCatchNodeInfo := False;
FNodeInfoLine := Line;
end;
if (index < 0) or (index >= FNodeInfoCount) then
Result := inherited GetFoldNodeInfo(Line, Index)
else
Result := FNodeInfoList[Index];
end;
function TSynPasSyn.GetFoldNodeInfoCount(Line: Integer): Integer;
begin
if FNodeInfoLine <> Line then
GetFoldNodeInfo(Line, 0);
Result := FNodeInfoCount;
end;
function TSynPasSyn.GetRangeClass: TSynCustomHighlighterRangeClass;
begin
Result:=TSynPasSynRange;
end;
function TSynPasSyn.GetLastLineCodeFoldLevelFix: integer;
function TSynPasSyn.LastLineCodeFoldLevelFix: integer;
begin
Result := TSynPasSynRange(CodeFoldRange).LastLineCodeFoldLevelFix;
end;