mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 08:19:53 +01:00 
			
		
		
		
	SynEdit: Refactored fold-highlighters: unify methods to get fold-nest info
git-svn-id: trunk@35115 -
This commit is contained in:
		
							parent
							
								
									e10dc0f7ea
								
							
						
					
					
						commit
						7a03599f16
					
				
							
								
								
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@ -2438,6 +2438,8 @@ components/synedit/test/testbasicsynedit.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testblockindent.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testbookmarks.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testfoldedview.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testhighlighterlfm.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testhighlightfoldbase.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testhighlightmulti.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testhighlightpas.pas svneol=native#text/pascal
 | 
			
		||||
components/synedit/test/testhighlightxml.pas svneol=native#text/pascal
 | 
			
		||||
 | 
			
		||||
@ -284,6 +284,50 @@ type
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  TSynEditFoldProviderNodeInfoList = array of TSynEditFoldProviderNodeInfo;
 | 
			
		||||
  TSynEditFoldProvider = class;
 | 
			
		||||
 | 
			
		||||
  (* TLazSynEditNestedFoldsList
 | 
			
		||||
     Provides Info on all foldable-blocks containing a given line (0 based index).
 | 
			
		||||
     That are:
 | 
			
		||||
     - All foldable blocks opening on a previous line, that are still open
 | 
			
		||||
       at the start of the line. (May end on this line or later)
 | 
			
		||||
     - Foldable blocks opening on that line. (OpeningOnLineCount)
 | 
			
		||||
 | 
			
		||||
     The data is NOT automatically invalidated.
 | 
			
		||||
  *)
 | 
			
		||||
 | 
			
		||||
  TLazSynEditNestedFoldsListEntry = record
 | 
			
		||||
    HNode: TSynFoldNodeInfo;    // Highlighter Node
 | 
			
		||||
    //FNode: TSynTextFoldAVLNode; // AvlFoldNode
 | 
			
		||||
    //Text, Keyword: String;
 | 
			
		||||
    LineIdx: TLineIdx;
 | 
			
		||||
     //ColIndex: Integer;
 | 
			
		||||
    //OpenCount: Integer;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  TLazSynEditNestedFoldsList = class
 | 
			
		||||
  private
 | 
			
		||||
    FFoldProvider: TSynEditFoldProvider;
 | 
			
		||||
    FFoldGroup: Integer;
 | 
			
		||||
    FLine: TLineIdx;
 | 
			
		||||
    procedure SetFoldGroup(AValue: Integer);
 | 
			
		||||
    procedure SetLines(AValue: TLineIdx);
 | 
			
		||||
  private
 | 
			
		||||
    FGroupCount: Integer;
 | 
			
		||||
    FGroupEndLevels, FGroupEndLevelsAtEval: Array of integer;
 | 
			
		||||
    FCount, FOpeningOnLineCount: Integer;
 | 
			
		||||
    FNestInfo: Array of TLazSynEditNestedFoldsListEntry;
 | 
			
		||||
    FEvaluationIndex: Integer;
 | 
			
		||||
    procedure InitSubGroupEndLevels;
 | 
			
		||||
    procedure InitNestInfoForIndex(AnIndex: Integer);
 | 
			
		||||
  public
 | 
			
		||||
    constructor Create(aFoldProvider: TSynEditFoldProvider);
 | 
			
		||||
    procedure Clear;
 | 
			
		||||
    function Count: Integer;
 | 
			
		||||
    function OpeningOnLineCount: Integer;
 | 
			
		||||
    property Line: TLineIdx read FLine write SetLines;
 | 
			
		||||
    property FoldGroup: Integer read FFoldGroup write SetFoldGroup;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  TSynEditFoldProvider = class
 | 
			
		||||
  private
 | 
			
		||||
@ -292,17 +336,21 @@ type
 | 
			
		||||
    FSelection: TSynEditSelection;
 | 
			
		||||
    FFoldTree : TSynTextFoldAVLTree;
 | 
			
		||||
    function GetFoldsAvailable: Boolean;
 | 
			
		||||
    function GetHighLighterWithLines: TSynCustomFoldHighlighter;
 | 
			
		||||
    function GetLineCapabilities(ALineIdx: Integer): TSynEditFoldLineCapabilities;
 | 
			
		||||
    function GetLineClassification(ALineIdx: Integer): TFoldNodeClassifications;
 | 
			
		||||
    procedure SetHighLighter(const AValue: TSynCustomFoldHighlighter);
 | 
			
		||||
  protected
 | 
			
		||||
    property HighLighterWithLines: TSynCustomFoldHighlighter read GetHighLighterWithLines;
 | 
			
		||||
  public
 | 
			
		||||
    constructor Create(aTextView : TSynEditStrings; AFoldTree : TSynTextFoldAVLTree);
 | 
			
		||||
    function FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
 | 
			
		||||
    function FoldOpenInfo(ALineIdx, AFoldIdx: Integer; AType: Integer = 0): TSynFoldNodeInfo;
 | 
			
		||||
 | 
			
		||||
    // Info about Folds opening on ALineIdx
 | 
			
		||||
    function  FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
 | 
			
		||||
    function  FoldOpenInfo(ALineIdx, AFoldIdx: Integer; AType: Integer = 0): TSynFoldNodeInfo;
 | 
			
		||||
    //property FoldOpenInfo[ALineIdx, AColumnIdx: Integer]: Integer read GetFoldOpenInfo;
 | 
			
		||||
    //property FoldInfoCount[ALineIdx: Integer]: Integer read GetFoldInfoCount;
 | 
			
		||||
    //property FoldInfo[ALineIdx, AColumnIdx: Integer]: Integer read GetFoldInfo;
 | 
			
		||||
    function FoldLineLength(ALine, AFoldIndex: Integer): integer;
 | 
			
		||||
 | 
			
		||||
    function  FoldLineLength(ALine, AFoldIndex: Integer): integer;
 | 
			
		||||
    function  InfoForFoldAtTextIndex(ALine, AFoldIndex : Integer;
 | 
			
		||||
                                     HideLen: Boolean = False;
 | 
			
		||||
                                     NeedLen: Boolean = True): TSynEditFoldProviderNodeInfo;
 | 
			
		||||
@ -2724,6 +2772,131 @@ begin
 | 
			
		||||
  fNestedNodesTree := nil;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TLazSynEditNestedFoldsList }
 | 
			
		||||
 | 
			
		||||
procedure TLazSynEditNestedFoldsList.SetLines(AValue: TLineIdx);
 | 
			
		||||
begin
 | 
			
		||||
  if FLine = AValue then Exit;
 | 
			
		||||
  FLine := AValue;
 | 
			
		||||
  // Todo: might be able to re-use old data
 | 
			
		||||
  Clear;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TLazSynEditNestedFoldsList.Clear;
 | 
			
		||||
begin
 | 
			
		||||
  FGroupCount := -1;
 | 
			
		||||
  FCount := -1;
 | 
			
		||||
  FOpeningOnLineCount := -1;
 | 
			
		||||
  FEvaluationIndex := -1;
 | 
			
		||||
  SetLength(FNestInfo, 0);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TLazSynEditNestedFoldsList.InitSubGroupEndLevels;
 | 
			
		||||
var
 | 
			
		||||
  hl: TSynCustomFoldHighlighter;
 | 
			
		||||
  i: integer;
 | 
			
		||||
begin
 | 
			
		||||
  if FGroupCount > 0 then
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  hl := FFoldProvider.HighLighterWithLines;
 | 
			
		||||
  if hl = nil then exit;
 | 
			
		||||
 | 
			
		||||
  if FFoldGroup = 0 then begin
 | 
			
		||||
    // special, join other groups (or some other...)
 | 
			
		||||
    FGroupCount := hl.FoldTypeCount;
 | 
			
		||||
    // start at 1, so FoldGroup can be used as index
 | 
			
		||||
    SetLength(FGroupEndLevels, FGroupCount + 1);
 | 
			
		||||
    SetLength(FGroupEndLevelsAtEval, FGroupCount + 1);
 | 
			
		||||
    for i := 1 to FGroupCount do
 | 
			
		||||
      FGroupEndLevels[i] := hl.FoldBlockEndLevel(FLine - 1, i) + OpeningOnLineCount;
 | 
			
		||||
      FGroupEndLevelsAtEval[i] := FGroupEndLevels[i];
 | 
			
		||||
  end
 | 
			
		||||
  else begin
 | 
			
		||||
    FGroupCount := 1;
 | 
			
		||||
    SetLength(FGroupEndLevels, 1);
 | 
			
		||||
    SetLength(FGroupEndLevelsAtEval, 1);
 | 
			
		||||
    FGroupEndLevels[0] := Count;
 | 
			
		||||
    FGroupEndLevelsAtEval[0] := FGroupEndLevels[0];
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TLazSynEditNestedFoldsList.InitNestInfoForIndex(AnIndex: Integer);
 | 
			
		||||
var
 | 
			
		||||
  CurLine: TLineIdx;
 | 
			
		||||
  hl: TSynCustomFoldHighlighter;
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  if (AnIndex >= Count) or (AnIndex >= FEvaluationIndex) then exit;
 | 
			
		||||
  hl := FFoldProvider.HighLighterWithLines;
 | 
			
		||||
  if hl = nil then exit;
 | 
			
		||||
 | 
			
		||||
  InitSubGroupEndLevels;
 | 
			
		||||
 | 
			
		||||
  if FEvaluationIndex = Count then
 | 
			
		||||
    CurLine := Line
 | 
			
		||||
  else
 | 
			
		||||
    CurLine := FNestInfo[FEvaluationIndex].LineIdx;
 | 
			
		||||
    // need index/column...
 | 
			
		||||
 | 
			
		||||
  inc(CurLine);
 | 
			
		||||
  while CurLine > 0 do begin
 | 
			
		||||
    dec(CurLine);
 | 
			
		||||
 | 
			
		||||
    if FFoldGroup = 0 then begin
 | 
			
		||||
      i := FGroupCount;
 | 
			
		||||
 | 
			
		||||
      while (i > 0) do begin
 | 
			
		||||
  //      hl.MinimumFoldLevel(CurLine, i)  // minimumPas
 | 
			
		||||
        dec(i);
 | 
			
		||||
      end;
 | 
			
		||||
      if i < 0 then continue;
 | 
			
		||||
    end
 | 
			
		||||
    else begin
 | 
			
		||||
      //if ... continue
 | 
			
		||||
    end;
 | 
			
		||||
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TLazSynEditNestedFoldsList.SetFoldGroup(AValue: Integer);
 | 
			
		||||
begin
 | 
			
		||||
  if FFoldGroup = AValue then Exit;
 | 
			
		||||
  FFoldGroup := AValue;
 | 
			
		||||
  Clear;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
constructor TLazSynEditNestedFoldsList.Create(aFoldProvider: TSynEditFoldProvider);
 | 
			
		||||
begin
 | 
			
		||||
  FFoldProvider := aFoldProvider;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TLazSynEditNestedFoldsList.Count: Integer;
 | 
			
		||||
var
 | 
			
		||||
  hl: TSynCustomFoldHighlighter;
 | 
			
		||||
begin
 | 
			
		||||
  Result := FCount;
 | 
			
		||||
  if Result >= 0 then exit;
 | 
			
		||||
  hl := FFoldProvider.HighLighterWithLines;
 | 
			
		||||
  if hl = nil then exit(-1);
 | 
			
		||||
 | 
			
		||||
  FCount := hl.FoldBlockEndLevel(FLine - 1, FFoldGroup) + OpeningOnLineCount;
 | 
			
		||||
  FEvaluationIndex := FCount;
 | 
			
		||||
  SetLength(FNestInfo, FCount);
 | 
			
		||||
  Result := FCount;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TLazSynEditNestedFoldsList.OpeningOnLineCount: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := FOpeningOnLineCount;
 | 
			
		||||
  if Result >= 0 then exit;
 | 
			
		||||
 | 
			
		||||
  FOpeningOnLineCount := FFoldProvider.FoldOpenCount(FLine);
 | 
			
		||||
  Result := FOpeningOnLineCount;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TSynEditFoldProvider }
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldProvider.GetLineCapabilities(ALineIdx: Integer): TSynEditFoldLineCapabilities;
 | 
			
		||||
@ -2744,8 +2917,8 @@ begin
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  FHighlighter.CurrentLines := FLines;
 | 
			
		||||
  if FHighlighter.FoldNestCount(ALineIdx - 1) > 0 then Result := Result + [cfFoldBody];
 | 
			
		||||
  if FHighlighter.FoldCloseCount(ALineIdx) > 0    then Result := Result + [cfFoldEnd, cfFoldBody];
 | 
			
		||||
  if FHighlighter.FoldBlockEndLevel(ALineIdx - 1) > 0 then Result := Result + [cfFoldBody];
 | 
			
		||||
  if FHighlighter.FoldBlockClosingCount(ALineIdx) > 0    then Result := Result + [cfFoldEnd, cfFoldBody];
 | 
			
		||||
 | 
			
		||||
  c := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([]);
 | 
			
		||||
  if c > 0 then begin
 | 
			
		||||
@ -2761,7 +2934,7 @@ begin
 | 
			
		||||
      Result := Result + [cfHideStart, cfSingleLineHide];
 | 
			
		||||
  end
 | 
			
		||||
  else
 | 
			
		||||
    if FHighlighter.FoldOpenCount(ALineIdx) > 0 then include(Result, cfFoldStart);
 | 
			
		||||
    if FHighlighter.FoldBlockOpeningCount(ALineIdx) > 0 then include(Result, cfFoldStart);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldProvider.GetLineClassification(ALineIdx: Integer): TFoldNodeClassifications;
 | 
			
		||||
@ -2777,6 +2950,14 @@ begin
 | 
			
		||||
            ((FSelection <> nil) and FSelection.SelAvail);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldProvider.GetHighLighterWithLines: TSynCustomFoldHighlighter;
 | 
			
		||||
begin
 | 
			
		||||
  Result := FHighlighter;
 | 
			
		||||
  if (Result = nil) then
 | 
			
		||||
    exit;
 | 
			
		||||
  Result.CurrentLines := FLines;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynEditFoldProvider.SetHighLighter(const AValue: TSynCustomFoldHighlighter);
 | 
			
		||||
begin
 | 
			
		||||
  if FHighlighter = AValue then exit;
 | 
			
		||||
@ -2790,30 +2971,18 @@ begin
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldProvider.FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  if (FHighlighter = nil) or (ALineIdx < 0) then begin
 | 
			
		||||
    if (AType=0) and (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) then exit(1);
 | 
			
		||||
    exit(0);
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  // Need to check alll nodes with FoldNodeInfoCount
 | 
			
		||||
  // Hide-able nodes can open and close on the same line "(* cmment *)"
 | 
			
		||||
  FHighlighter.CurrentLines := FLines;
 | 
			
		||||
  Result := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFold]);
 | 
			
		||||
  if (result > 0) and (AType > 0) then begin
 | 
			
		||||
    i := Result ;
 | 
			
		||||
    Result := 0;
 | 
			
		||||
    while i > 0 do begin
 | 
			
		||||
      dec(i);
 | 
			
		||||
      if FHighlighter.FoldNodeInfo[ALineIdx].NodeInfoEx(i, [sfaOpen, sfaFold]).FoldGroup = AType then
 | 
			
		||||
        inc(Result);
 | 
			
		||||
    end;
 | 
			
		||||
  end
 | 
			
		||||
  //Result := Result + FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFoldHide]];
 | 
			
		||||
  //Result := Result + FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOneLineOpen, sfaFoldHide]];
 | 
			
		||||
  else
 | 
			
		||||
  Result := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFold], AType);
 | 
			
		||||
  // fallback for HL without GetFoldNodeInfoCountEx
 | 
			
		||||
  if Result < 0 then
 | 
			
		||||
    Result := FHighlighter.FoldOpenCount(ALineIdx, AType);
 | 
			
		||||
    Result := FHighlighter.FoldBlockOpeningCount(ALineIdx, AType);
 | 
			
		||||
  if (AType=0) and (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) then
 | 
			
		||||
    inc(Result);
 | 
			
		||||
end;
 | 
			
		||||
@ -2837,8 +3006,6 @@ function TSynEditFoldProvider.FoldOpenInfo(ALineIdx, AFoldIdx: Integer;
 | 
			
		||||
    Result.FoldGroup := -1;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
var
 | 
			
		||||
  i, x: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result.FoldAction := [sfaInvalid];
 | 
			
		||||
  if (FHighlighter = nil) or (ALineIdx < 0) then begin
 | 
			
		||||
@ -2848,27 +3015,13 @@ begin
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  FHighlighter.CurrentLines := FLines;
 | 
			
		||||
  if AType = 0 then
 | 
			
		||||
    if (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) and
 | 
			
		||||
      (AFoldIdx = FoldOpenCount(ALineIdx, 0)-1)
 | 
			
		||||
    then
 | 
			
		||||
      Result := BlockSelInfo(AFoldIdx-1)
 | 
			
		||||
    else
 | 
			
		||||
      Result := FHighlighter.FoldNodeInfo[ALineIdx].NodeInfoEx(AFoldIdx, [sfaOpen, sfaFold])
 | 
			
		||||
  else begin
 | 
			
		||||
    x := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFold]);
 | 
			
		||||
    i := 0;
 | 
			
		||||
    while i < x do begin
 | 
			
		||||
      Result := FHighlighter.FoldNodeInfo[ALineIdx].NodeInfoEx(i, [sfaOpen, sfaFold]);
 | 
			
		||||
      if (Result.FoldGroup = AType) then begin
 | 
			
		||||
        if AFoldIdx = 0 then
 | 
			
		||||
          exit;
 | 
			
		||||
        dec(AFoldIdx);
 | 
			
		||||
      end;
 | 
			
		||||
      inc(i);
 | 
			
		||||
    end;
 | 
			
		||||
    Result.FoldAction := [sfaInvalid];
 | 
			
		||||
  end;
 | 
			
		||||
  if (AType = 0) and (FSelection <> nil) and FSelection.SelAvail and
 | 
			
		||||
     (FSelection.FirstLineBytePos.Y=ALineIdx+1) and
 | 
			
		||||
     (AFoldIdx = FoldOpenCount(ALineIdx, AType)-1)
 | 
			
		||||
  then
 | 
			
		||||
    Result := BlockSelInfo(AFoldIdx)
 | 
			
		||||
  else
 | 
			
		||||
    Result := FHighlighter.FoldNodeInfo[ALineIdx].NodeInfoEx(AFoldIdx, [sfaOpen, sfaFold], AType);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldProvider.FoldLineLength(ALine, AFoldIndex: Integer): integer;
 | 
			
		||||
@ -3369,7 +3522,7 @@ begin
 | 
			
		||||
  while i < fLines.Count do begin
 | 
			
		||||
     // Todo: Highlighter should return a list of types that can return default folded
 | 
			
		||||
     // Currently PascalHl Type 2 = Region
 | 
			
		||||
    c := hl.FoldOpenCount(i, 2);
 | 
			
		||||
    c := hl.FoldBlockOpeningCount(i, 2);
 | 
			
		||||
    if c > 0 then begin
 | 
			
		||||
      c := hl.FoldNodeInfo[i].CountEx([sfaOpen, sfaFold]);
 | 
			
		||||
      j := 0;
 | 
			
		||||
@ -3855,9 +4008,9 @@ begin
 | 
			
		||||
  fFoldTree.Clear;
 | 
			
		||||
  i := 0;
 | 
			
		||||
  while i < fLines.Count do begin
 | 
			
		||||
    if (hl.FoldOpenCount(i, t) > 0)
 | 
			
		||||
    and (hl.FoldNestCount(i, t) > StartLevel) then begin
 | 
			
		||||
      c := hl.FoldOpenCount(i) -1;
 | 
			
		||||
    if (hl.FoldBlockOpeningCount(i, t) > 0)
 | 
			
		||||
    and (hl.FoldBlockEndLevel(i, t) > StartLevel) then begin
 | 
			
		||||
      c := hl.FoldBlockOpeningCount(i) -1;
 | 
			
		||||
      fldinf := FoldProvider.InfoForFoldAtTextIndex(i, c);
 | 
			
		||||
      // i is 0-based
 | 
			
		||||
      // FoldTree is 1-based AND first line remains visble
 | 
			
		||||
@ -4111,7 +4264,7 @@ begin
 | 
			
		||||
  hl := TSynCustomFoldHighlighter(HighLighter);
 | 
			
		||||
  if not assigned(hl) then
 | 
			
		||||
    exit(-1);
 | 
			
		||||
  Result := hl.FoldNestCount(AStartIndex-1, AType) + FoldProvider.FoldOpenCount(AStartIndex);
 | 
			
		||||
  Result := hl.FoldBlockEndLevel(AStartIndex-1, AType) + FoldProvider.FoldOpenCount(AStartIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynEditFoldedView.OpenFoldInfo(aStartIndex, ColIndex: Integer; AType: Integer = 0): TFoldViewNodeInfo;
 | 
			
		||||
@ -4126,13 +4279,13 @@ var
 | 
			
		||||
  begin
 | 
			
		||||
    if AType = 0 then begin;
 | 
			
		||||
      for i := 1 to TypeCnt do begin
 | 
			
		||||
        EndLvl[i] := hl.FoldNestCount(l-1, i);
 | 
			
		||||
        EndLvl[i] := hl.FoldBlockEndLevel(l-1, i);
 | 
			
		||||
        EndLvl[i] := EndLvl[i] + FoldProvider.FoldOpenCount(l, i);
 | 
			
		||||
        CurLvl[i] := EndLvl[i];
 | 
			
		||||
      end;
 | 
			
		||||
    end
 | 
			
		||||
    else begin
 | 
			
		||||
      EndLvl[0] := hl.FoldNestCount(l-1, AType);
 | 
			
		||||
      EndLvl[0] := hl.FoldBlockEndLevel(l-1, AType);
 | 
			
		||||
      EndLvl[0] := EndLvl[0] + FoldProvider.FoldOpenCount(l, AType);
 | 
			
		||||
      CurLvl[0] := EndLvl[0];
 | 
			
		||||
    end;
 | 
			
		||||
@ -4146,7 +4299,7 @@ begin
 | 
			
		||||
    TypeCnt := 1
 | 
			
		||||
  else
 | 
			
		||||
    TypeCnt := hl.FoldTypeCount;
 | 
			
		||||
  Lvl := hl.FoldNestCount(AStartIndex-1, AType);
 | 
			
		||||
  Lvl := hl.FoldBlockEndLevel(AStartIndex-1, AType);
 | 
			
		||||
  if ColIndex >= Lvl then begin
 | 
			
		||||
    n := ColIndex - Lvl;
 | 
			
		||||
    if AType = 0 then begin
 | 
			
		||||
@ -4165,8 +4318,8 @@ begin
 | 
			
		||||
    aStartIndex := aStartIndex;
 | 
			
		||||
    while (ColIndex < Lvl) and (aStartIndex > 0) do begin
 | 
			
		||||
      dec(aStartIndex);
 | 
			
		||||
      o := hl.FoldOpenCount(AStartIndex, AType);
 | 
			
		||||
      if (o > 0) or (hl.FoldCloseCount(aStartIndex, AType) > 0) then begin
 | 
			
		||||
      o := hl.FoldBlockOpeningCount(AStartIndex, AType);
 | 
			
		||||
      if (o > 0) or (hl.FoldBlockClosingCount(aStartIndex, AType) > 0) then begin
 | 
			
		||||
        n := o;
 | 
			
		||||
        c := hl.FoldNodeInfo[aStartIndex].CountEx([], AType) - 1;
 | 
			
		||||
        for i := c downto 0 do begin
 | 
			
		||||
@ -4194,7 +4347,7 @@ begin
 | 
			
		||||
        end;
 | 
			
		||||
      end
 | 
			
		||||
      else
 | 
			
		||||
      if hl.FoldNestCount(AStartIndex-1, AType) = 0 then break;
 | 
			
		||||
      if hl.FoldBlockEndLevel(AStartIndex-1, AType) = 0 then break;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
  Result.HNode := nd;
 | 
			
		||||
@ -4220,7 +4373,7 @@ begin
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  i := ALine;
 | 
			
		||||
  l := hl.FoldOpenCount(i - 1);
 | 
			
		||||
  l := hl.FoldBlockOpeningCount(i - 1);
 | 
			
		||||
  if l > 0 then begin
 | 
			
		||||
    node := fFoldTree.FindFoldForLine(ALine, true);
 | 
			
		||||
    if node.IsInFold and (node.StartLine = ALine +1) then begin
 | 
			
		||||
@ -4234,19 +4387,19 @@ begin
 | 
			
		||||
    else
 | 
			
		||||
      exit(ALine);
 | 
			
		||||
  end
 | 
			
		||||
  else if hl.FoldCloseCount(i - 1) > 0 then
 | 
			
		||||
  else if hl.FoldBlockClosingCount(i - 1) > 0 then
 | 
			
		||||
    dec(i);
 | 
			
		||||
  if (i < 0) or (hl.FoldNestCount(i-1) = 0) then
 | 
			
		||||
  if (i < 0) or (hl.FoldBlockEndLevel(i-1) = 0) then
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  l := 0;
 | 
			
		||||
  while (i > 0) and (l >= 0) do begin // (FoldMinLevel[i] >= l) do
 | 
			
		||||
    dec(i);
 | 
			
		||||
    l := l - hl.FoldOpenCount(i);
 | 
			
		||||
    l := l - hl.FoldBlockOpeningCount(i);
 | 
			
		||||
    if l >= 0 then
 | 
			
		||||
      l := l + hl.FoldCloseCount(i);
 | 
			
		||||
      l := l + hl.FoldBlockClosingCount(i);
 | 
			
		||||
  end;
 | 
			
		||||
  if (hl.FoldNestCount(i) > 0) then // TODO, check for collapsed at index = 0
 | 
			
		||||
  if (hl.FoldBlockEndLevel(i) > 0) then // TODO, check for collapsed at index = 0
 | 
			
		||||
    Result := i + 1;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,25 @@ $Id: synedithighlighter.pp 19051 2009-03-21 00:47:33Z martin $
 | 
			
		||||
You may retrieve the latest version of this file at the SynEdit home page,
 | 
			
		||||
located at http://SynEdit.SourceForge.net
 | 
			
		||||
 | 
			
		||||
Known Issues:
 | 
			
		||||
-------------------------------------------------------------------------------}
 | 
			
		||||
 | 
			
		||||
(* Naming Conventions:
 | 
			
		||||
   -  FoldBlock:
 | 
			
		||||
     A continuous range of lines, that can (optional) be folded.
 | 
			
		||||
     Which Foldblocks can be folded is decided by the Highlighter. It may be
 | 
			
		||||
     configurable.
 | 
			
		||||
     A Foldblock can contain other Foldbloccks (nested), but two Foldblocks can
 | 
			
		||||
     not overlap.
 | 
			
		||||
   -  FoldBlockLevel (FoldBlockNestLevel):
 | 
			
		||||
     The amount of FoldBlocks in which a line (or a point of text) is.
 | 
			
		||||
   -  FoldGroup:
 | 
			
		||||
     An independent set of FoldBlocks. FoldBlocks in different Groups may overlap.
 | 
			
		||||
     (e.g. IFDEF/REGION in the SynPasSyn allow for overlaps, rather than strict nesting)
 | 
			
		||||
     Some older code use "FoldType" instead
 | 
			
		||||
   -  FoldNode
 | 
			
		||||
     Start or End of a FoldBlock
 | 
			
		||||
*)
 | 
			
		||||
 | 
			
		||||
unit SynEditHighlighterFoldBase;
 | 
			
		||||
 | 
			
		||||
{$I synedit.inc}
 | 
			
		||||
@ -54,6 +70,42 @@ type
 | 
			
		||||
                   );
 | 
			
		||||
  TSynFoldActions = set of TSynFoldAction;
 | 
			
		||||
 | 
			
		||||
  (* TSynFoldBlockFilter
 | 
			
		||||
     used to specify which folds to include for:
 | 
			
		||||
     - FoldOpenCount, FoldCloseCount, FoldNestCount
 | 
			
		||||
     - maybe in future TLazSynFoldNodeInfoList
 | 
			
		||||
       TLazSynFoldNodeInfoList has additional filters
 | 
			
		||||
       TLazSynFoldNodeInfoList always uses the full set (sfbIncludeDisabled)
 | 
			
		||||
 | 
			
		||||
     A Highlighter is not required to implement this, or can choose to implement
 | 
			
		||||
     a subset only. For any field/value a Highlighter may simple assume default.
 | 
			
		||||
     - Highlighter that have only one "FoldGroup" do not require this.
 | 
			
		||||
     - Highlighter that do not store foldblocks that are unavailable (e.g. off by
 | 
			
		||||
       config) always return the same set
 | 
			
		||||
 | 
			
		||||
     Using a record, as argument is the virtual methods, allows to add further
 | 
			
		||||
     fields/values, without breaking inheritance.
 | 
			
		||||
     New fields values are expected to be ignored (handled as default) by existing
 | 
			
		||||
     highlighter.
 | 
			
		||||
 | 
			
		||||
     Callers of the method can:
 | 
			
		||||
     - use InitFoldBlockFilter to make sure all fields are set to default
 | 
			
		||||
     - use (none virtual) wrapper methods
 | 
			
		||||
  *)
 | 
			
		||||
  TSynFoldBlockFilterFlag = (
 | 
			
		||||
    sfbIncludeDisabled // Foldable by config = off
 | 
			
		||||
  );
 | 
			
		||||
  TSynFoldBlockFilterFlags = set of TSynFoldBlockFilterFlag;
 | 
			
		||||
  TSynFoldBlockFilter = record
 | 
			
		||||
    FoldGroup: integer;
 | 
			
		||||
    Flags: TSynFoldBlockFilterFlags;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
procedure InitFoldBlockFilter(out AFilter: TSynFoldBlockFilter;
 | 
			
		||||
                              AFoldGroup: Integer = 0; AFlag: TSynFoldBlockFilterFlags = []);
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  TSynFoldNodeInfo = record
 | 
			
		||||
    LineIndex: Integer;
 | 
			
		||||
    NodeIndex: Integer;          // Indicates the position within the list of info nodes (depends on search-Filter)
 | 
			
		||||
@ -204,7 +256,7 @@ type
 | 
			
		||||
 | 
			
		||||
  TSynCustomFoldHighlighter = class(TSynCustomHighlighter)
 | 
			
		||||
  protected
 | 
			
		||||
    // Config
 | 
			
		||||
    // Fold Config
 | 
			
		||||
    FFoldConfig: Array of TSynCustomFoldConfig;
 | 
			
		||||
    function GetFoldConfig(Index: Integer): TSynCustomFoldConfig; virtual;
 | 
			
		||||
    procedure SetFoldConfig(Index: Integer; const AValue: TSynCustomFoldConfig); virtual;
 | 
			
		||||
@ -220,36 +272,55 @@ type
 | 
			
		||||
    FRootCodeFoldBlock: TSynCustomCodeFoldBlock;
 | 
			
		||||
    FFoldNodeInfoList: TLazSynFoldNodeInfoList;
 | 
			
		||||
  protected
 | 
			
		||||
    function CreateFoldNodeInfoList: TLazSynFoldNodeInfoList; virtual;
 | 
			
		||||
    function GetFoldNodeInfo(Line: TLineIdx): TLazSynFoldNodeInfoList;
 | 
			
		||||
    procedure InitFoldNodeInfo(AList: TLazSynFoldNodeInfoList; Line: TLineIdx); virtual;
 | 
			
		||||
  protected
 | 
			
		||||
    property CodeFoldRange: TSynCustomHighlighterRange read FCodeFoldRange;
 | 
			
		||||
    // "Range"
 | 
			
		||||
    function GetRangeClass: TSynCustomHighlighterRangeClass; virtual;
 | 
			
		||||
    procedure CreateRootCodeFoldBlock; virtual; // set RootCodeFoldBlock
 | 
			
		||||
    property CodeFoldRange: TSynCustomHighlighterRange read FCodeFoldRange;
 | 
			
		||||
    function TopCodeFoldBlockType(DownIndex: Integer = 0): Pointer;
 | 
			
		||||
    property RootCodeFoldBlock: TSynCustomCodeFoldBlock read FRootCodeFoldBlock
 | 
			
		||||
      write FRootCodeFoldBlock;
 | 
			
		||||
 | 
			
		||||
    // Open/Close Folds
 | 
			
		||||
    function StartCodeFoldBlock(ABlockType: Pointer;
 | 
			
		||||
              IncreaseLevel: Boolean = true): TSynCustomCodeFoldBlock; virtual;
 | 
			
		||||
    procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); virtual;
 | 
			
		||||
    procedure CreateRootCodeFoldBlock; virtual;
 | 
			
		||||
    property RootCodeFoldBlock: TSynCustomCodeFoldBlock read FRootCodeFoldBlock
 | 
			
		||||
      write FRootCodeFoldBlock;
 | 
			
		||||
 | 
			
		||||
    // Info about Folds
 | 
			
		||||
    function CreateFoldNodeInfoList: TLazSynFoldNodeInfoList; virtual;
 | 
			
		||||
    function GetFoldNodeInfo(Line: TLineIdx): TLazSynFoldNodeInfoList;
 | 
			
		||||
    procedure InitFoldNodeInfo(AList: TLazSynFoldNodeInfoList; Line: TLineIdx); virtual;
 | 
			
		||||
 | 
			
		||||
    // Info about Folds, on currently set line/range (simply forwarding to range
 | 
			
		||||
    function MinimumCodeFoldBlockLevel: integer; virtual;
 | 
			
		||||
    function CurrentCodeFoldBlockLevel: integer; virtual;
 | 
			
		||||
  public
 | 
			
		||||
    constructor Create(AOwner: TComponent); override;
 | 
			
		||||
    destructor Destroy; override;
 | 
			
		||||
    function GetRange: Pointer; override;
 | 
			
		||||
 | 
			
		||||
    function MinimumCodeFoldBlockLevel: integer; virtual;
 | 
			
		||||
    function CurrentCodeFoldBlockLevel: integer; virtual;
 | 
			
		||||
    // Info about Folds
 | 
			
		||||
    function FoldBlockOpeningCount(ALineIndex: TLineIdx;
 | 
			
		||||
                                   const AFilter: TSynFoldBlockFilter): integer; virtual; overload;
 | 
			
		||||
    function FoldBlockClosingCount(ALineIndex: TLineIdx;
 | 
			
		||||
                                   const AFilter: TSynFoldBlockFilter): integer; virtual; overload;
 | 
			
		||||
    function FoldBlockEndLevel(ALineIndex: TLineIdx;
 | 
			
		||||
                               const AFilter: TSynFoldBlockFilter): integer; virtual; overload;
 | 
			
		||||
    function FoldBlockMinLevel(ALineIndex: TLineIdx;
 | 
			
		||||
                               const AFilter: TSynFoldBlockFilter): integer; virtual; overload;
 | 
			
		||||
 | 
			
		||||
    // requires CurrentLines;
 | 
			
		||||
    function MinimumFoldLevel(Index: Integer): integer; virtual; abstract;      // TODO: Move to Fold*
 | 
			
		||||
    function EndFoldLevel(Index: Integer): integer; virtual; abstract;          // TODO: Replace with FoldNestCount
 | 
			
		||||
    function FoldBlockOpeningCount(ALineIndex: TLineIdx; AFoldGroup: integer = 0;
 | 
			
		||||
                                   AFlags: TSynFoldBlockFilterFlags = []): integer; overload;
 | 
			
		||||
    function FoldBlockClosingCount(ALineIndex: TLineIdx; AFoldGroup: integer = 0;
 | 
			
		||||
                                   AFlags: TSynFoldBlockFilterFlags = []): integer; overload;
 | 
			
		||||
    function FoldBlockEndLevel(ALineIndex: TLineIdx; AFoldGroup: integer = 0;
 | 
			
		||||
                               AFlags: TSynFoldBlockFilterFlags = []): integer; overload;
 | 
			
		||||
    function FoldBlockMinLevel(ALineIndex: TLineIdx; AFoldGroup: integer = 0;
 | 
			
		||||
                               AFlags: TSynFoldBlockFilterFlags = []): integer; overload;
 | 
			
		||||
 | 
			
		||||
    function FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer;  deprecated;
 | 
			
		||||
    function FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer; deprecated;
 | 
			
		||||
    function FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer; deprecated;
 | 
			
		||||
 | 
			
		||||
    // fold-nodes that can be collapsed
 | 
			
		||||
    // Highlighter can join several fold structures Or leave out some
 | 
			
		||||
    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 FoldTypeCount: integer; virtual;
 | 
			
		||||
    function FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
 | 
			
		||||
             UseCloseNodes: boolean = false): integer; virtual; // TODO: could be deprecated ./ only child-classes
 | 
			
		||||
@ -296,6 +367,13 @@ function AllocateHighlighterRanges(
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
 | 
			
		||||
procedure InitFoldBlockFilter(out AFilter: TSynFoldBlockFilter; AFoldGroup: Integer;
 | 
			
		||||
  AFlag: TSynFoldBlockFilterFlags = []);
 | 
			
		||||
begin
 | 
			
		||||
  AFilter.FoldGroup := AFoldGroup;
 | 
			
		||||
  AFilter.Flags     := AFlag;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function CompareSynHighlighterRanges(Data1, Data2: Pointer): integer;
 | 
			
		||||
var
 | 
			
		||||
  Range1: TSynCustomHighlighterRange;
 | 
			
		||||
@ -597,6 +675,92 @@ begin
 | 
			
		||||
  Result:=fRanges.GetEqual(FCodeFoldRange);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockOpeningCount(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  Result := FoldBlockEndLevel(ALineIndex, AFilter) - FoldBlockMinLevel(ALineIndex, AFilter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockClosingCount(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  Result := FoldBlockEndLevel(ALineIndex - 1, AFilter) - FoldBlockMinLevel(ALineIndex, AFilter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockEndLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: Pointer;
 | 
			
		||||
begin
 | 
			
		||||
  Assert(CurrentRanges <> nil, 'TSynCustomFoldHighlighter.FoldBlockEndLevel requires CurrentRanges');
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := CurrentRanges[ALineIndex];
 | 
			
		||||
  if (r <> nil) and (r <> NullRange) then
 | 
			
		||||
    Result := TSynCustomHighlighterRange(r).CodeFoldStackSize
 | 
			
		||||
  else
 | 
			
		||||
    Result:=0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockMinLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: Pointer;
 | 
			
		||||
begin
 | 
			
		||||
  Assert(CurrentRanges <> nil, 'TSynCustomFoldHighlighter.FoldBlockMinLevelrequires CurrentRanges');
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := CurrentRanges[ALineIndex];
 | 
			
		||||
  if (r <> nil) and (r <> NullRange) then
 | 
			
		||||
    Result := TSynCustomHighlighterRange(r).MinimumCodeFoldBlockLevel
 | 
			
		||||
  else
 | 
			
		||||
    Result:=0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockOpeningCount(ALineIndex: TLineIdx;
 | 
			
		||||
  AFoldGroup: integer; AFlags: TSynFoldBlockFilterFlags): integer;
 | 
			
		||||
var
 | 
			
		||||
  Filter: TSynFoldBlockFilter;
 | 
			
		||||
begin
 | 
			
		||||
  Filter.FoldGroup := AFoldGroup;
 | 
			
		||||
  Filter.Flags := AFlags;
 | 
			
		||||
  Result := FoldBlockOpeningCount(ALineIndex, Filter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockClosingCount(ALineIndex: TLineIdx;
 | 
			
		||||
  AFoldGroup: integer; AFlags: TSynFoldBlockFilterFlags): integer;
 | 
			
		||||
var
 | 
			
		||||
  Filter: TSynFoldBlockFilter;
 | 
			
		||||
begin
 | 
			
		||||
  Filter.FoldGroup := AFoldGroup;
 | 
			
		||||
  Filter.Flags := AFlags;
 | 
			
		||||
  Result := FoldBlockClosingCount(ALineIndex, Filter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockEndLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  AFoldGroup: integer; AFlags: TSynFoldBlockFilterFlags): integer;
 | 
			
		||||
var
 | 
			
		||||
  Filter: TSynFoldBlockFilter;
 | 
			
		||||
begin
 | 
			
		||||
  Filter.FoldGroup := AFoldGroup;
 | 
			
		||||
  Filter.Flags := AFlags;
 | 
			
		||||
  Result := FoldBlockEndLevel(ALineIndex, Filter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldBlockMinLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  AFoldGroup: integer; AFlags: TSynFoldBlockFilterFlags): integer;
 | 
			
		||||
var
 | 
			
		||||
  Filter: TSynFoldBlockFilter;
 | 
			
		||||
begin
 | 
			
		||||
  Filter.FoldGroup := AFoldGroup;
 | 
			
		||||
  Filter.Flags := AFlags;
 | 
			
		||||
  Result := FoldBlockMinLevel(ALineIndex, Filter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynCustomFoldHighlighter.ResetRange;
 | 
			
		||||
begin
 | 
			
		||||
  FCodeFoldRange.Clear;
 | 
			
		||||
@ -605,6 +769,7 @@ end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.MinimumCodeFoldBlockLevel: integer;
 | 
			
		||||
begin
 | 
			
		||||
  assert(FCodeFoldRange <> nil, 'MinimumCodeFoldBlockLevel requires FCodeFoldRange');
 | 
			
		||||
  Result := FCodeFoldRange.MinimumCodeFoldBlockLevel;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
@ -625,25 +790,23 @@ end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.CurrentCodeFoldBlockLevel: integer;
 | 
			
		||||
begin
 | 
			
		||||
  if CodeFoldRange<>nil then
 | 
			
		||||
    Result:=CodeFoldRange.CodeFoldStackSize
 | 
			
		||||
  else
 | 
			
		||||
    Result:=0;
 | 
			
		||||
  assert(FCodeFoldRange <> nil, 'MinimumCodeFoldBlockLevel requires FCodeFoldRange');
 | 
			
		||||
  Result := FCodeFoldRange.CodeFoldStackSize;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
begin
 | 
			
		||||
  result := 0;
 | 
			
		||||
  result := FoldBlockOpeningCount(ALineIndex, AType);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
begin
 | 
			
		||||
  result := 0;
 | 
			
		||||
  result := FoldBlockClosingCount(ALineIndex, AType);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  Result := FoldBlockEndLevel(ALineIndex, AType);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomFoldHighlighter.FoldTypeCount: integer;
 | 
			
		||||
@ -661,7 +824,7 @@ function TSynCustomFoldHighlighter.FoldLineLength(ALineIndex, FoldIndex: Integer
 | 
			
		||||
begin
 | 
			
		||||
  Result := FoldEndLine(ALineIndex, FoldIndex);
 | 
			
		||||
  // check if fold last line of block (not mixed "end begin")
 | 
			
		||||
  if (EndFoldLevel(Result) > MinimumFoldLevel(Result)) then
 | 
			
		||||
  if (FoldBlockEndLevel(Result) > FoldBlockMinLevel(Result)) then
 | 
			
		||||
    dec(Result);
 | 
			
		||||
  // Amount of lines, that will become invisible (excludes the cfCollapsed line)
 | 
			
		||||
  Result := Result - ALineIndex;
 | 
			
		||||
@ -672,13 +835,12 @@ var
 | 
			
		||||
  lvl, cnt: Integer;
 | 
			
		||||
  e, m: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  //atype := FoldTypeAtNodeIndex(ALineIndex, FoldIndex);
 | 
			
		||||
  cnt := CurrentLines.Count;
 | 
			
		||||
  e := EndFoldLevel(ALineIndex);
 | 
			
		||||
  m := MinimumFoldLevel(ALineIndex);
 | 
			
		||||
  e := FoldBlockEndLevel(ALineIndex);
 | 
			
		||||
  m := FoldBlockMinLevel(ALineIndex);
 | 
			
		||||
  lvl := Min(m+1+FoldIndex, e);
 | 
			
		||||
  Result := ALineIndex + 1;
 | 
			
		||||
  while (Result < cnt) and (MinimumFoldLevel(Result) >= lvl) do inc(Result);
 | 
			
		||||
  while (Result < cnt) and (FoldBlockMinLevel(Result) >= lvl) do inc(Result);
 | 
			
		||||
  if (Result = cnt) then
 | 
			
		||||
    dec(Result);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
@ -75,13 +75,6 @@ type
 | 
			
		||||
    procedure EndXmlNodeCodeFoldBlock(ClosePos: Integer = -1; AName: String = '');
 | 
			
		||||
  public
 | 
			
		||||
    procedure SetLine({$IFDEF FPC}const {$ENDIF}NewValue: string; LineNumber:Integer); override;
 | 
			
		||||
  public
 | 
			
		||||
    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;
 | 
			
		||||
    // TODO: make private
 | 
			
		||||
    function MinimumFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
    function EndFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
@ -122,50 +115,6 @@ begin
 | 
			
		||||
  FXmlRangeInfoClosePos := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.FoldOpenCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.FoldCloseCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex - 1) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.FoldNestCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.MinimumFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.MinimumCodeFoldBlockLevel
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.EndFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.CodeFoldStackSize
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynCustomXmlHighlighter.StartXmlCodeFoldBlock(ABlockType: Integer): TSynCustomCodeFoldBlock;
 | 
			
		||||
var
 | 
			
		||||
  FoldBlock: Boolean;
 | 
			
		||||
@ -232,11 +181,11 @@ begin
 | 
			
		||||
 | 
			
		||||
      if i = 0 then begin
 | 
			
		||||
        i := LineIndex - 1;
 | 
			
		||||
        lvl := EndFoldLevel(i);
 | 
			
		||||
        lvl := FoldBlockEndLevel(i);
 | 
			
		||||
        while i >= 0 do begin
 | 
			
		||||
          if MinimumFoldLevel(i) < lvl then begin
 | 
			
		||||
          if FoldBlockMinLevel(i) < lvl then begin
 | 
			
		||||
            LInfo := TSynHighlighterXmlRangeList(CurrentRanges).XmlRangeInfo[i].ElementOpenList;
 | 
			
		||||
            k := length(LInfo) - Max(EndFoldLevel(i) - lvl, 0) - 1;
 | 
			
		||||
            k := length(LInfo) - Max(FoldBlockEndLevel(i) - lvl, 0) - 1;
 | 
			
		||||
            while (k >= 0) do begin
 | 
			
		||||
              if (LInfo[k] = AName) then
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
@ -140,7 +140,10 @@ var
 | 
			
		||||
      exit;
 | 
			
		||||
 | 
			
		||||
    inc(YIndex);
 | 
			
		||||
    while (YIndex < LCnt) and (HL.MinimumFoldLevel(YIndex) > StartNode.NestLvlStart) do
 | 
			
		||||
    while (YIndex < LCnt) and
 | 
			
		||||
          (HL.FoldBlockMinLevel(YIndex, StartNode.FoldGroup, [sfbIncludeDisabled])
 | 
			
		||||
           > StartNode.NestLvlStart)
 | 
			
		||||
    do
 | 
			
		||||
      inc(YIndex);
 | 
			
		||||
    if YIndex = LCnt then
 | 
			
		||||
      exit;
 | 
			
		||||
@ -172,7 +175,9 @@ var
 | 
			
		||||
      exit;
 | 
			
		||||
 | 
			
		||||
    dec(YIndex);
 | 
			
		||||
    while (YIndex >= 0) and (HL.MinimumFoldLevel(YIndex) > EndNode.NestLvlEnd) do
 | 
			
		||||
    while (YIndex >= 0) and
 | 
			
		||||
          (HL.FoldBlockMinLevel(YIndex, EndNode.FoldGroup, [sfbIncludeDisabled]) > EndNode.NestLvlEnd)
 | 
			
		||||
    do
 | 
			
		||||
      dec(YIndex);
 | 
			
		||||
    if YIndex < 0 then
 | 
			
		||||
      exit;
 | 
			
		||||
 | 
			
		||||
@ -157,14 +157,6 @@ type
 | 
			
		||||
    function GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig; override;
 | 
			
		||||
    function GetFoldConfigCount: Integer; override;
 | 
			
		||||
    function GetFoldConfigInternalCount: Integer; override;
 | 
			
		||||
  public
 | 
			
		||||
    // folding
 | 
			
		||||
    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;
 | 
			
		||||
    // TODO: make private
 | 
			
		||||
    function MinimumFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
    function EndFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
  published
 | 
			
		||||
    property UnknownAttri: TSynHighlighterAttributes read FUnknownAttri write FUnknownAttri;
 | 
			
		||||
    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
 | 
			
		||||
@ -747,56 +739,6 @@ begin
 | 
			
		||||
  Result := ord(high(TDiffCodeFoldBlockType)) - ord(low(TDiffCodeFoldBlockType)) + 1;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
// EndLvl = MinLvl(+1)
 | 
			
		||||
// MinLvl = Min(Min, Min(+1))
 | 
			
		||||
 | 
			
		||||
function TSynDiffSyn.FoldOpenCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := Max(0, MinimumFoldLevel(ALineIndex+1) - MinimumFoldLevel(ALineIndex));
 | 
			
		||||
  //Result := EndFoldLevel(ALineIndex) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynDiffSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := Max(0, MinimumFoldLevel(ALineIndex) - MinimumFoldLevel(ALineIndex+1));
 | 
			
		||||
  //Result := EndFoldLevel(ALineIndex - 1) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynDiffSyn.FoldNestCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := MinimumFoldLevel(ALineIndex+1);
 | 
			
		||||
  //Result := EndFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynDiffSyn.MinimumFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.MinimumCodeFoldBlockLevel
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynDiffSyn.EndFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.CodeFoldStackSize
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
initialization
 | 
			
		||||
  RegisterPlaceableHighlighter(TSynDiffSyn);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,7 @@ type
 | 
			
		||||
    // internal type / no config
 | 
			
		||||
    cfbtLfmNone
 | 
			
		||||
    );
 | 
			
		||||
  TLfmCodeFoldBlockTypes = set of TLfmCodeFoldBlockType;
 | 
			
		||||
 | 
			
		||||
  TProcTableProc = procedure of object;
 | 
			
		||||
 | 
			
		||||
@ -148,14 +149,6 @@ type
 | 
			
		||||
    procedure SetRange(Value: Pointer); override;
 | 
			
		||||
    procedure ResetRange; override;
 | 
			
		||||
    property IdentChars;
 | 
			
		||||
  public
 | 
			
		||||
    // folding
 | 
			
		||||
    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;
 | 
			
		||||
    // TODO: make private
 | 
			
		||||
    function MinimumFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
    function EndFoldLevel(ALineIndex: Integer): integer; override;
 | 
			
		||||
  published
 | 
			
		||||
    property CommentAttri: TSynHighlighterAttributes read fCommentAttri
 | 
			
		||||
      write fCommentAttri;
 | 
			
		||||
@ -612,50 +605,6 @@ begin
 | 
			
		||||
  fRange := rsUnknown;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynLFMSyn.FoldOpenCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynLFMSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex - 1) - MinimumFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynLFMSyn.FoldNestCount(ALineIndex: Integer; AType: Integer): integer;
 | 
			
		||||
begin
 | 
			
		||||
  If AType <> 0 then exit(0);
 | 
			
		||||
  Result := EndFoldLevel(ALineIndex);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynLFMSyn.MinimumFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.MinimumCodeFoldBlockLevel
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynLFMSyn.EndFoldLevel(ALineIndex: Integer): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynCustomHighlighterRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  r := TSynCustomHighlighterRange(CurrentRanges[ALineIndex]);
 | 
			
		||||
  if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
    Result := r.CodeFoldStackSize
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynLFMSyn.SetRange(Value: Pointer);
 | 
			
		||||
begin
 | 
			
		||||
  inherited;
 | 
			
		||||
 | 
			
		||||
@ -174,6 +174,11 @@ const
 | 
			
		||||
      cfbtNone
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  FOLDGROUP_PASCAL = 1;
 | 
			
		||||
  FOLDGROUP_REGION = 2;
 | 
			
		||||
  FOLDGROUP_IFDEF  = 3;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  TPascalCompilerMode = (
 | 
			
		||||
@ -319,7 +324,9 @@ type
 | 
			
		||||
    fD4syntax: boolean;
 | 
			
		||||
    FCatchNodeInfo: Boolean;
 | 
			
		||||
    FCatchNodeInfoList: TLazSynPasFoldNodeInfoList;
 | 
			
		||||
    // Divider
 | 
			
		||||
    FDividerDrawConfig: Array [TSynPasDividerDrawLocation] of TSynDividerDrawConfig;
 | 
			
		||||
 | 
			
		||||
    function GetPasCodeFoldRange: TSynPasSynRange;
 | 
			
		||||
    procedure SetCompilerMode(const AValue: TPascalCompilerMode);
 | 
			
		||||
    procedure SetExtendedKeywordsMode(const AValue: Boolean);
 | 
			
		||||
@ -449,9 +456,10 @@ type
 | 
			
		||||
    procedure SymbolProc;
 | 
			
		||||
    procedure UnknownProc;
 | 
			
		||||
    procedure SetD4syntax(const Value: boolean);
 | 
			
		||||
    procedure InitNode(var Node: TSynFoldNodeInfo; EndOffs: Integer;
 | 
			
		||||
    procedure InitNode(out Node: TSynFoldNodeInfo; EndOffs: Integer;
 | 
			
		||||
                       ABlockType: TPascalCodeFoldBlockType; aActions: TSynFoldActions;
 | 
			
		||||
                       AIsFold: Boolean);
 | 
			
		||||
    // Divider
 | 
			
		||||
    procedure CreateDividerDrawConfig;
 | 
			
		||||
    procedure DestroyDividerDrawConfig;
 | 
			
		||||
  protected
 | 
			
		||||
@ -459,11 +467,17 @@ type
 | 
			
		||||
    function GetIdentChars: TSynIdentChars; override;
 | 
			
		||||
    function IsFilterStored: boolean; override;                                 //mh 2000-10-08
 | 
			
		||||
  protected
 | 
			
		||||
    // "Range"
 | 
			
		||||
    function GetRangeClass: TSynCustomHighlighterRangeClass; override;
 | 
			
		||||
    procedure CreateRootCodeFoldBlock; override;
 | 
			
		||||
    function CreateRangeList(ALines: TSynEditStringsBase): TSynHighlighterRangeList; override;
 | 
			
		||||
    function UpdateRangeInfoAtLine(Index: Integer): Boolean; override; // Returns true if range changed
 | 
			
		||||
 | 
			
		||||
    property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange;
 | 
			
		||||
    function TopPascalCodeFoldBlockType
 | 
			
		||||
             (DownIndex: Integer = 0): TPascalCodeFoldBlockType;
 | 
			
		||||
 | 
			
		||||
    // Open/Close Folds
 | 
			
		||||
    function StartPascalCodeFoldBlock
 | 
			
		||||
             (ABlockType: TPascalCodeFoldBlockType): TSynCustomCodeFoldBlock;
 | 
			
		||||
    procedure EndPascalCodeFoldBlock(NoMarkup: Boolean = False);
 | 
			
		||||
@ -473,24 +487,19 @@ type
 | 
			
		||||
    procedure StartCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
 | 
			
		||||
    procedure EndCustomCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType);
 | 
			
		||||
 | 
			
		||||
    // Info about Folds
 | 
			
		||||
    function CreateFoldNodeInfoList: TLazSynFoldNodeInfoList; override;
 | 
			
		||||
    procedure InitFoldNodeInfo(AList: TLazSynFoldNodeInfoList; Line: TLineIdx); override;
 | 
			
		||||
  protected
 | 
			
		||||
    property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange;
 | 
			
		||||
    function TopPascalCodeFoldBlockType
 | 
			
		||||
             (DownIndex: Integer = 0): TPascalCodeFoldBlockType;
 | 
			
		||||
 | 
			
		||||
  public
 | 
			
		||||
    function MinimumPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
 | 
			
		||||
    function EndPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
 | 
			
		||||
  protected
 | 
			
		||||
    function LastLinePasFoldLevelFix(Index: Integer; AType: Integer = 1): integer; // foldable nodes
 | 
			
		||||
    function LastLineFoldLevelFix(Index: Integer): integer;                        // all nodes
 | 
			
		||||
    function LastLinePasFoldLevelFix(Index: Integer; AType: Integer = 1): integer; // TODO deprecated; // foldable nodes
 | 
			
		||||
 | 
			
		||||
    // Divider
 | 
			
		||||
    function GetDrawDivider(Index: integer): TSynDividerDrawConfigSetting; override;
 | 
			
		||||
    function GetDividerDrawConfig(Index: Integer): TSynDividerDrawConfig; override;
 | 
			
		||||
    function GetDividerDrawConfigCount: Integer; override;
 | 
			
		||||
 | 
			
		||||
    // Fold Config
 | 
			
		||||
    function GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig; override;
 | 
			
		||||
    function GetFoldConfigCount: Integer; override;
 | 
			
		||||
    function GetFoldConfigInternalCount: Integer; override;
 | 
			
		||||
@ -523,19 +532,18 @@ type
 | 
			
		||||
    function UseUserSettings(settingIndex: integer): boolean; override;
 | 
			
		||||
    procedure EnumUserSettings(settings: TStrings); override;
 | 
			
		||||
 | 
			
		||||
    // fold-nodes that can be collapsed
 | 
			
		||||
    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;
 | 
			
		||||
    // Info about Folds
 | 
			
		||||
    //function FoldBlockOpeningCount(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload;
 | 
			
		||||
    //function FoldBlockClosingCount(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload;
 | 
			
		||||
    function FoldBlockEndLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload;
 | 
			
		||||
    function FoldBlockMinLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload;
 | 
			
		||||
 | 
			
		||||
    function FoldTypeCount: integer; override;
 | 
			
		||||
    function FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;                // accesses FoldNodeInfo
 | 
			
		||||
             UseCloseNodes: boolean = false): integer; override;
 | 
			
		||||
    function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; override; // accesses FoldNodeInfo
 | 
			
		||||
    function FoldEndLine(ALineIndex, FoldIndex: Integer): integer; override;    // accesses FoldNodeInfo
 | 
			
		||||
 | 
			
		||||
    // All fold nodes // TODO: make private
 | 
			
		||||
    function MinimumFoldLevel(Index: Integer): integer; override;
 | 
			
		||||
    function EndFoldLevel(Index: Integer): integer; override;
 | 
			
		||||
  published
 | 
			
		||||
    property AsmAttri: TSynHighlighterAttributes read fAsmAttri write fAsmAttri;
 | 
			
		||||
    property CommentAttri: TSynHighlighterAttributes read fCommentAttri
 | 
			
		||||
@ -1091,7 +1099,6 @@ begin
 | 
			
		||||
    if TopPascalCodeFoldBlockType in [cfbtVarType, cfbtLocalVarType] then
 | 
			
		||||
      EndPascalCodeFoldBlockLastLine;
 | 
			
		||||
    StartPascalCodeFoldBlock(cfbtAsm);
 | 
			
		||||
    //debugln('TSynPasSyn.Func37 BEGIN ',dbgs(ord(TopPascalCodeFoldBlockType)),' LineNumber=',dbgs(fLineNumber),' ',dbgs(MinimumCodeFoldBlockLevel),' ',dbgs(CurrentCodeFoldBlockLevel));
 | 
			
		||||
  end
 | 
			
		||||
  else Result := tkIdentifier;
 | 
			
		||||
end;
 | 
			
		||||
@ -2361,7 +2368,7 @@ begin
 | 
			
		||||
  fLine:=PChar(Pointer(fLineStr));
 | 
			
		||||
  Run := 0;
 | 
			
		||||
  Inherited SetLine(NewValue,LineNumber);
 | 
			
		||||
  FStartCodeFoldBlockLevel := MinimumCodeFoldBlockLevel;
 | 
			
		||||
  FStartCodeFoldBlockLevel := PasCodeFoldRange.MinimumCodeFoldBlockLevel;
 | 
			
		||||
  PasCodeFoldRange.LastLineCodeFoldLevelFix := 0;
 | 
			
		||||
  PasCodeFoldRange.PasFoldFixLevel := 0;
 | 
			
		||||
  PasCodeFoldRange.PasFoldMinLevel := PasCodeFoldRange.PasFoldEndLevel;
 | 
			
		||||
@ -3156,6 +3163,100 @@ begin
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldBlockEndLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
var
 | 
			
		||||
  inf: TSynPasRangeInfo;
 | 
			
		||||
  r, r2: Pointer;
 | 
			
		||||
begin
 | 
			
		||||
  Assert(CurrentRanges <> nil, 'TSynCustomFoldHighlighter.FoldBlockEndLevel requires CurrentRanges');
 | 
			
		||||
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count - 1) then
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_REGION, FOLDGROUP_IFDEF] then
 | 
			
		||||
    inf := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex];
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_PASCAL] then begin
 | 
			
		||||
    // All or Pascal
 | 
			
		||||
    r := CurrentRanges[ALineIndex];
 | 
			
		||||
    if (r <> nil) and (r <> NullRange) then begin
 | 
			
		||||
      r2 := TSynPasSynRange(CurrentRanges[ALineIndex + 1]);
 | 
			
		||||
      if sfbIncludeDisabled in AFilter.Flags then begin
 | 
			
		||||
        Result := TSynPasSynRange(r).CodeFoldStackSize;
 | 
			
		||||
        if (r2 <> nil) and (r2 <> NullRange) then
 | 
			
		||||
          Result := Result + TSynPasSynRange(r2).LastLineCodeFoldLevelFix;
 | 
			
		||||
      end
 | 
			
		||||
      else begin
 | 
			
		||||
        Result := TSynPasSynRange(r).PasFoldEndLevel;
 | 
			
		||||
        if (r2 <> nil) and (r2 <> NullRange) then
 | 
			
		||||
          Result := Result + TSynPasSynRange(r2).PasFoldFixLevel;
 | 
			
		||||
      end;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_REGION] then begin
 | 
			
		||||
    // All or REGION
 | 
			
		||||
    Result := Result + inf.EndLevelRegion;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_IFDEF] then begin
 | 
			
		||||
    // All or IFDEF
 | 
			
		||||
    Result := Result + inf.EndLevelIfDef;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldBlockMinLevel(ALineIndex: TLineIdx;
 | 
			
		||||
  const AFilter: TSynFoldBlockFilter): integer;
 | 
			
		||||
var
 | 
			
		||||
  inf: TSynPasRangeInfo;
 | 
			
		||||
  r, r2: Pointer;
 | 
			
		||||
begin
 | 
			
		||||
  Assert(CurrentRanges <> nil, 'TSynCustomFoldHighlighter.FoldBlockMinLevel requires CurrentRanges');
 | 
			
		||||
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  if (ALineIndex < 0) or (ALineIndex >= CurrentLines.Count - 1) then
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_REGION, FOLDGROUP_IFDEF] then
 | 
			
		||||
    inf := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex];
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_PASCAL] then begin
 | 
			
		||||
    // All or Pascal
 | 
			
		||||
    (* Range.EndLevel can be smaller. because it Range.MinLevel does not know the LastLiineFix
 | 
			
		||||
       Using a copy of FoldBlockEndLevel *)
 | 
			
		||||
    r := CurrentRanges[ALineIndex];
 | 
			
		||||
    if (r <> nil) and (r <> NullRange) then begin
 | 
			
		||||
      r2 := TSynPasSynRange(CurrentRanges[ALineIndex + 1]);
 | 
			
		||||
      if sfbIncludeDisabled in AFilter.Flags then begin
 | 
			
		||||
        Result := TSynPasSynRange(r).CodeFoldStackSize;
 | 
			
		||||
        if (r2 <> nil) and (r2 <> NullRange) then
 | 
			
		||||
          Result := Result + TSynPasSynRange(r2).LastLineCodeFoldLevelFix;
 | 
			
		||||
        // now Result = FoldBlockEndLevel
 | 
			
		||||
        Result := Min(Result, TSynPasSynRange(r).MinimumCodeFoldBlockLevel);
 | 
			
		||||
      end
 | 
			
		||||
      else begin
 | 
			
		||||
        Result := TSynPasSynRange(r).PasFoldEndLevel;
 | 
			
		||||
        if (r2 <> nil) and (r2 <> NullRange) then
 | 
			
		||||
          Result := Result + TSynPasSynRange(r2).PasFoldFixLevel;
 | 
			
		||||
        // now Result = FoldBlockEndLevel
 | 
			
		||||
        Result := Min(Result, TSynPasSynRange(r).PasFoldMinLevel);
 | 
			
		||||
      end;
 | 
			
		||||
    end;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_REGION] then begin
 | 
			
		||||
    // All or REGION
 | 
			
		||||
    Result := Result + inf.MinLevelRegion;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  if AFilter.FoldGroup  in [0, FOLDGROUP_IFDEF] then begin
 | 
			
		||||
    // All or IFDEF
 | 
			
		||||
    Result := Result + inf.MinLevelIfDef;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.TopPascalCodeFoldBlockType(DownIndex: Integer = 0): TPascalCodeFoldBlockType;
 | 
			
		||||
var
 | 
			
		||||
  p: Pointer;
 | 
			
		||||
@ -3166,63 +3267,6 @@ begin
 | 
			
		||||
  Result := TPascalCodeFoldBlockType(PtrUInt(p));
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
var
 | 
			
		||||
  inf: TSynPasRangeInfo;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  if not(AType in [1, 4]) 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;
 | 
			
		||||
  if (AType = 4) then
 | 
			
		||||
    Result := EndPasFoldLevel(ALineIndex, 4) - MinimumPasFoldLevel(ALineIndex, 4);
 | 
			
		||||
  if Result < 0 then
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
var
 | 
			
		||||
  inf, inf2: TSynPasRangeInfo;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  if not(AType in [1, 4]) 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)
 | 
			
		||||
            - min(MinimumPasFoldLevel(ALineIndex), EndPasFoldLevel(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;
 | 
			
		||||
  if (AType = 4) then
 | 
			
		||||
    Result := EndPasFoldLevel(ALineIndex - 1, 4)
 | 
			
		||||
            - min(MinimumPasFoldLevel(ALineIndex, 4), EndPasFoldLevel(ALineIndex, 4));
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer;
 | 
			
		||||
var
 | 
			
		||||
  inf: TSynPasRangeInfo;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 0;
 | 
			
		||||
  if not(AType in [1, 4]) 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;
 | 
			
		||||
  if (AType = 4) then
 | 
			
		||||
    Result := EndPasFoldLevel(ALineIndex, 4);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.FoldTypeCount: integer;
 | 
			
		||||
begin
 | 
			
		||||
  Result := 3;
 | 
			
		||||
@ -3264,7 +3308,7 @@ begin
 | 
			
		||||
 | 
			
		||||
  Result := FoldEndLine(ALineIndex, FoldIndex);
 | 
			
		||||
  // check if fold last line of block (not mixed "end begin")
 | 
			
		||||
  if (EndPasFoldLevel(Result, atype) > MinimumPasFoldLevel(Result, atype)) then
 | 
			
		||||
  if (FoldBlockEndLevel(Result, atype) > FoldBlockMinLevel(Result, atype)) then
 | 
			
		||||
    dec(Result);
 | 
			
		||||
  // Amount of lines, that will become invisible (excludes the cfCollapsed line)
 | 
			
		||||
  Result := Result - ALineIndex;
 | 
			
		||||
@ -3292,81 +3336,13 @@ begin
 | 
			
		||||
  lvl := node.FoldLvlEnd;
 | 
			
		||||
 | 
			
		||||
  Result := ALineIndex + 1;
 | 
			
		||||
  while (Result < cnt) and (MinimumPasFoldLevel(Result, atype) >= lvl) do inc(Result);
 | 
			
		||||
  while (Result < cnt) and (FoldBlockMinLevel(Result, atype) >= lvl) do inc(Result);
 | 
			
		||||
  // check if fold last line of block (not mixed "end begin")
 | 
			
		||||
  // and not lastlinefix
 | 
			
		||||
  if (Result = cnt) then
 | 
			
		||||
    dec(Result);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.MinimumPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynPasSynRange;
 | 
			
		||||
begin
 | 
			
		||||
  case AType of
 | 
			
		||||
    2:
 | 
			
		||||
      Result := TSynHighlighterPasRangeList(CurrentRanges).
 | 
			
		||||
                  PasRangeInfo[Index].MinLevelRegion;
 | 
			
		||||
    3:
 | 
			
		||||
      Result := TSynHighlighterPasRangeList(CurrentRanges).
 | 
			
		||||
                  PasRangeInfo[Index].MinLevelIfDef;
 | 
			
		||||
    4:  // all pascal nodes (incl. not folded)
 | 
			
		||||
      begin
 | 
			
		||||
        if (Index < 0) or (Index >= CurrentLines.Count) then
 | 
			
		||||
          exit(0);
 | 
			
		||||
        r := TSynPasSynRange(CurrentRanges[Index]);
 | 
			
		||||
        if (r <> nil) and (Pointer(r) <> NullRange) then begin
 | 
			
		||||
          Result := Min(r.CodeFoldStackSize + LastLinePasFoldLevelFix(Index + 1, 4),
 | 
			
		||||
                        r.MinimumCodeFoldBlockLevel);
 | 
			
		||||
        end else
 | 
			
		||||
          Result := 0;
 | 
			
		||||
      end;
 | 
			
		||||
    else
 | 
			
		||||
      begin
 | 
			
		||||
        if (Index < 0) or (Index >= CurrentLines.Count) then
 | 
			
		||||
          exit(0);
 | 
			
		||||
        r := TSynPasSynRange(CurrentRanges[Index]);
 | 
			
		||||
        if (r <> nil) and (Pointer(r) <> NullRange) then begin
 | 
			
		||||
          Result := Min(r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1),
 | 
			
		||||
                        r.PasFoldMinLevel)
 | 
			
		||||
        end else
 | 
			
		||||
          Result := 0;
 | 
			
		||||
      end;
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.EndPasFoldLevel(Index: Integer; AType: Integer = 1): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynPasSynRange;
 | 
			
		||||
begin
 | 
			
		||||
  if (Index < 0) or (Index >= CurrentLines.Count - 1) then
 | 
			
		||||
    exit(0);
 | 
			
		||||
  case AType of
 | 
			
		||||
    2:
 | 
			
		||||
      Result := TSynHighlighterPasRangeList(CurrentRanges).
 | 
			
		||||
                  PasRangeInfo[Index].EndLevelRegion;
 | 
			
		||||
    3:
 | 
			
		||||
      Result := TSynHighlighterPasRangeList(CurrentRanges).
 | 
			
		||||
                  PasRangeInfo[Index].EndLevelIfDef;
 | 
			
		||||
    4:  // all pascal nodes (incl. not folded)
 | 
			
		||||
      begin
 | 
			
		||||
        r := TSynPasSynRange(CurrentRanges[Index]);
 | 
			
		||||
        if (r <> nil) and (Pointer(r) <> NullRange) then
 | 
			
		||||
          Result := r.CodeFoldStackSize
 | 
			
		||||
        else
 | 
			
		||||
          Result := 0;
 | 
			
		||||
      end;
 | 
			
		||||
    else
 | 
			
		||||
      begin
 | 
			
		||||
        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; AType: Integer = 1): integer;
 | 
			
		||||
var
 | 
			
		||||
  r: TSynPasSynRange;
 | 
			
		||||
@ -3397,49 +3373,7 @@ begin
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.MinimumFoldLevel(Index: Integer): 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.CodeFoldStackSize + LastLineFoldLevelFix(Index + 1),
 | 
			
		||||
                  r.MinimumCodeFoldBlockLevel)
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.EndFoldLevel(Index: Integer): 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.CodeFoldStackSize + LastLineFoldLevelFix(Index + 1)
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TSynPasSyn.LastLineFoldLevelFix(Index: Integer): 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.LastLineCodeFoldLevelFix
 | 
			
		||||
  else
 | 
			
		||||
    Result := 0;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
procedure TSynPasSyn.InitNode(var Node: TSynFoldNodeInfo; EndOffs: Integer;
 | 
			
		||||
procedure TSynPasSyn.InitNode(out Node: TSynFoldNodeInfo; EndOffs: Integer;
 | 
			
		||||
  ABlockType: TPascalCodeFoldBlockType; aActions: TSynFoldActions; AIsFold: Boolean);
 | 
			
		||||
var
 | 
			
		||||
  OneLine: Boolean;
 | 
			
		||||
@ -3455,30 +3389,29 @@ begin
 | 
			
		||||
  case ABlockType of
 | 
			
		||||
    cfbtRegion:
 | 
			
		||||
      begin
 | 
			
		||||
        node.FoldGroup := 2;
 | 
			
		||||
        node.FoldGroup := FOLDGROUP_REGION;
 | 
			
		||||
        Node.FoldLvlStart := FSynPasRangeInfo.EndLevelRegion;
 | 
			
		||||
        Node.NestLvlStart := FSynPasRangeInfo.EndLevelRegion;
 | 
			
		||||
        OneLine := (EndOffs < 0) and (Node.FoldLvlStart > FSynPasRangeInfo.MinLevelRegion);
 | 
			
		||||
      end;
 | 
			
		||||
    cfbtIfDef:
 | 
			
		||||
      begin
 | 
			
		||||
        node.FoldGroup := 3;
 | 
			
		||||
        node.FoldGroup := FOLDGROUP_IFDEF;
 | 
			
		||||
        Node.FoldLvlStart := FSynPasRangeInfo.EndLevelIfDef;
 | 
			
		||||
        Node.NestLvlStart := FSynPasRangeInfo.EndLevelIfDef;
 | 
			
		||||
        OneLine := (EndOffs < 0) and (Node.FoldLvlStart > FSynPasRangeInfo.MinLevelIfDef);
 | 
			
		||||
      end;
 | 
			
		||||
    else
 | 
			
		||||
      begin
 | 
			
		||||
        node.FoldGroup := FOLDGROUP_PASCAL;
 | 
			
		||||
        if AIsFold then begin
 | 
			
		||||
          node.FoldGroup := 1;
 | 
			
		||||
          Node.FoldLvlStart := PasCodeFoldRange.PasFoldEndLevel;
 | 
			
		||||
          Node.NestLvlStart := CurrentCodeFoldBlockLevel;
 | 
			
		||||
          Node.NestLvlStart := PasCodeFoldRange.CodeFoldStackSize;
 | 
			
		||||
          OneLine := (EndOffs < 0) and (Node.FoldLvlStart > PasCodeFoldRange.PasFoldMinLevel); // MinimumCodeFoldBlockLevel);
 | 
			
		||||
        end else begin
 | 
			
		||||
          node.FoldGroup := 4;
 | 
			
		||||
          Node.FoldLvlStart := PasCodeFoldRange.CodeFoldStackSize;
 | 
			
		||||
          Node.NestLvlStart := CurrentCodeFoldBlockLevel;
 | 
			
		||||
          OneLine := (EndOffs < 0) and (Node.FoldLvlStart > PasCodeFoldRange.MinimumCodeFoldBlockLevel); // MinimumCodeFoldBlockLevel);
 | 
			
		||||
          Node.NestLvlStart := PasCodeFoldRange.CodeFoldStackSize;
 | 
			
		||||
          OneLine := (EndOffs < 0) and (Node.FoldLvlStart > PasCodeFoldRange.MinimumCodeFoldBlockLevel);
 | 
			
		||||
        end;
 | 
			
		||||
      end;
 | 
			
		||||
  end;
 | 
			
		||||
@ -3584,7 +3517,7 @@ begin
 | 
			
		||||
  NextToEol;
 | 
			
		||||
 | 
			
		||||
  fStringLen := 0;
 | 
			
		||||
  i := LastLineFoldLevelFix(Line+1);
 | 
			
		||||
  i := LastLinePasFoldLevelFix(Line+1, 4);
 | 
			
		||||
  while i < 0 do begin
 | 
			
		||||
    EndPascalCodeFoldBlock;
 | 
			
		||||
    inc(i);
 | 
			
		||||
@ -3706,7 +3639,7 @@ begin
 | 
			
		||||
  EndPascalCodeFoldBlock;
 | 
			
		||||
  if FAtLineStart then begin
 | 
			
		||||
    // If we are not at linestart, new folds could have been opened => handle as normal close
 | 
			
		||||
    if (CurrentCodeFoldBlockLevel < FStartCodeFoldBlockLevel) and
 | 
			
		||||
    if (PasCodeFoldRange.CodeFoldStackSize < FStartCodeFoldBlockLevel) and
 | 
			
		||||
      (FStartCodeFoldBlockLevel > 0)
 | 
			
		||||
    then begin
 | 
			
		||||
      PasCodeFoldRange.DecLastLineCodeFoldLevelFix;
 | 
			
		||||
@ -3738,7 +3671,7 @@ function TSynPasSyn.GetDrawDivider(Index: integer): TSynDividerDrawConfigSetting
 | 
			
		||||
  begin
 | 
			
		||||
    i := 0;
 | 
			
		||||
    j := StartLvl;
 | 
			
		||||
    m := CurrentCodeFoldBlockLevel;
 | 
			
		||||
    m := PasCodeFoldRange.CodeFoldStackSize;;
 | 
			
		||||
    t := TopPascalCodeFoldBlockType(j);
 | 
			
		||||
    while (i <= MaxDepth) and (j < m) and
 | 
			
		||||
          ((t in CountTypes) or (t in SkipTypes)) do begin
 | 
			
		||||
@ -3759,17 +3692,20 @@ var
 | 
			
		||||
begin
 | 
			
		||||
  Result := inherited;
 | 
			
		||||
  if (index = 0) then exit;
 | 
			
		||||
  CloseCnt :=  EndFoldLevel(Index - 1) - MinimumFoldLevel(Index);
 | 
			
		||||
  if (CloseCnt = 0) or (MinimumFoldLevel(Index) <> EndFoldLevel(Index)) then // not a mixed line
 | 
			
		||||
  CloseCnt :=  FoldBlockClosingCount(Index, FOLDGROUP_PASCAL, [sfbIncludeDisabled]);
 | 
			
		||||
  if (CloseCnt = 0) or
 | 
			
		||||
     (FoldBlockMinLevel(Index, FOLDGROUP_PASCAL, [sfbIncludeDisabled])
 | 
			
		||||
      <> FoldBlockEndLevel(Index, FOLDGROUP_PASCAL, [sfbIncludeDisabled]))
 | 
			
		||||
  then // not a mixed line
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
  // SetRange[Index] has the folds at the start of this line
 | 
			
		||||
  // ClosedByNextLine: Folds closed by the next lines LastLineFix
 | 
			
		||||
  //                   must be taken from SetRange[Index+1] (end of this line)
 | 
			
		||||
  ClosedByNextLine := -LastLineFoldLevelFix(Index + 1);
 | 
			
		||||
  ClosedByNextLine := -LastLinePasFoldLevelFix(Index + 1, 4);
 | 
			
		||||
  // ClosedInLastLine: Folds Closed by this lines LastLineFix
 | 
			
		||||
  //                   must be ignored. (They are part of SetRange[Index] / this line)
 | 
			
		||||
  ClosedInLastLine := -LastLineFoldLevelFix(Index);
 | 
			
		||||
  ClosedInLastLine := -LastLinePasFoldLevelFix(Index, 4);
 | 
			
		||||
 | 
			
		||||
  // Get the highest close-offset
 | 
			
		||||
  i := ClosedByNextLine - 1;
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,7 @@ interface
 | 
			
		||||
{$I SynEdit.inc}
 | 
			
		||||
 | 
			
		||||
uses
 | 
			
		||||
  Classes, math, Graphics, SynEditTypes, SynEditHighlighter,
 | 
			
		||||
  Classes, Graphics, SynEditTypes, SynEditHighlighter,
 | 
			
		||||
  SynEditHighlighterFoldBase, SynEditHighlighterXMLBase;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
@ -98,22 +98,6 @@ type
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  { TSynHighlighterXmlRangeList }
 | 
			
		||||
 | 
			
		||||
  TSynHighlighterXmlRangeList = class(TSynHighlighterRangeList)
 | 
			
		||||
  private
 | 
			
		||||
    FItemOffset: Integer;
 | 
			
		||||
    function GetXmlRangeInfo(Index: Integer): TSynXmlRangeInfo;
 | 
			
		||||
    procedure SetXmlRangeInfo(Index: Integer; const AValue: TSynXmlRangeInfo);
 | 
			
		||||
  protected
 | 
			
		||||
    procedure SetCapacity(const AValue: Integer); override;
 | 
			
		||||
  public
 | 
			
		||||
    constructor Create;
 | 
			
		||||
    procedure Move(AFrom, ATo, ALen: Integer); override;
 | 
			
		||||
    property XmlRangeInfo[Index: Integer]: TSynXmlRangeInfo
 | 
			
		||||
      read GetXmlRangeInfo write SetXmlRangeInfo;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  TProcTableProc = procedure of object;
 | 
			
		||||
 | 
			
		||||
  { TSynXMLSyn }
 | 
			
		||||
@ -1010,65 +994,8 @@ begin
 | 
			
		||||
  Result := ord(high(TXmlCodeFoldBlockType)) - ord(low(TXmlCodeFoldBlockType)) + 1;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
{ TSynHighlighterXmlRangeList }
 | 
			
		||||
 | 
			
		||||
function TSynHighlighterXmlRangeList.GetXmlRangeInfo(Index: Integer): TSynXmlRangeInfo;
 | 
			
		||||
begin
 | 
			
		||||
  if (Index < 0) or (Index >= Count) then begin
 | 
			
		||||
    Result.ElementOpenList := nil;
 | 
			
		||||
    exit;
 | 
			
		||||
  end;
 | 
			
		||||
  Result := TSynXmlRangeInfo((ItemPointer[Index] + FItemOffset)^);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynHighlighterXmlRangeList.SetXmlRangeInfo(Index: Integer;
 | 
			
		||||
  const AValue: TSynXmlRangeInfo);
 | 
			
		||||
begin
 | 
			
		||||
  TSynXmlRangeInfo((ItemPointer[Index] + FItemOffset)^) := AValue;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynHighlighterXmlRangeList.SetCapacity(const AValue: Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: LongInt;
 | 
			
		||||
begin
 | 
			
		||||
  for i := AValue to Capacity-1 do
 | 
			
		||||
    with TSynXmlRangeInfo((ItemPointer[i] + FItemOffset)^) do begin
 | 
			
		||||
      ElementOpenList := nil;
 | 
			
		||||
      ElementCloseList := nil;
 | 
			
		||||
    end;
 | 
			
		||||
  inherited SetCapacity(AValue);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
constructor TSynHighlighterXmlRangeList.Create;
 | 
			
		||||
begin
 | 
			
		||||
  inherited;
 | 
			
		||||
  FItemOffset := ItemSize;
 | 
			
		||||
  ItemSize := FItemOffset + SizeOf(TSynXmlRangeInfo);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TSynHighlighterXmlRangeList.Move(AFrom, ATo, ALen: Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: LongInt;
 | 
			
		||||
begin
 | 
			
		||||
  if ATo > AFrom then
 | 
			
		||||
    for i:= Max(AFrom + ALen, ATo) to ATo + ALen - 1 do // move forward
 | 
			
		||||
      with TSynXmlRangeInfo((ItemPointer[i] + FItemOffset)^) do begin
 | 
			
		||||
        ElementOpenList := nil;
 | 
			
		||||
        ElementCloseList := nil;
 | 
			
		||||
      end
 | 
			
		||||
  else
 | 
			
		||||
    for i:= ATo to Min(ATo + ALen , AFrom) - 1 do // move backward
 | 
			
		||||
      with TSynXmlRangeInfo((ItemPointer[i] + FItemOffset)^) do begin
 | 
			
		||||
        ElementOpenList := nil;
 | 
			
		||||
        ElementCloseList := nil;
 | 
			
		||||
      end;
 | 
			
		||||
  inherited Move(AFrom, ATo, ALen);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
initialization
 | 
			
		||||
  RegisterPlaceableHighlighter(TSynXMLSyn);
 | 
			
		||||
 | 
			
		||||
end.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,13 +39,14 @@ type
 | 
			
		||||
    function TestText5: TStringArray;
 | 
			
		||||
    function TestText6: TStringArray;
 | 
			
		||||
    function TestText7: TStringArray;
 | 
			
		||||
    function TestText8: TStringArray;
 | 
			
		||||
    function TestTextHide(ALen: Integer): TStringArray;
 | 
			
		||||
    function TestTextHide2(ALen: Integer): TStringArray;
 | 
			
		||||
    function TestTextHide3: TStringArray;
 | 
			
		||||
    function TestTextHide4: TStringArray;
 | 
			
		||||
    function TestTextPlain: TStringArray;
 | 
			
		||||
  protected
 | 
			
		||||
    procedure TstSetText(AName: String; AText: TStringArray);
 | 
			
		||||
    procedure TstSetText(AName: String; AText: Array of String);
 | 
			
		||||
    procedure TstFold(AName: String; AFoldAtIndex: integer; AExpectedLines: Array of Integer);
 | 
			
		||||
    procedure TstFold(AName: String; AFoldAtIndex, AFoldAtColum: integer; AExpectedLines: Array of Integer);
 | 
			
		||||
    procedure TstFold(AName: String; AFoldAtIndex, AFoldAtColum, AFoldAtColCnt: integer;
 | 
			
		||||
@ -66,6 +67,7 @@ type
 | 
			
		||||
    procedure TestFoldEdit;
 | 
			
		||||
    procedure TestFoldStateFromText;
 | 
			
		||||
    procedure TestFoldStateDesc;
 | 
			
		||||
    procedure TestFoldProvider;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
@ -73,7 +75,7 @@ implementation
 | 
			
		||||
type
 | 
			
		||||
  TSynEditFoldedViewHack = class(TSynEditFoldedView) end;
 | 
			
		||||
 | 
			
		||||
procedure TTestFoldedView.TstSetText(AName: String; AText: TStringArray);
 | 
			
		||||
procedure TTestFoldedView.TstSetText(AName: String; AText: array of String);
 | 
			
		||||
begin
 | 
			
		||||
  PopBaseName;
 | 
			
		||||
  ReCreateEdit;
 | 
			
		||||
@ -406,6 +408,32 @@ begin
 | 
			
		||||
  Result[26] := '';
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestFoldedView.TestText8: TStringArray;
 | 
			
		||||
begin
 | 
			
		||||
  // end begin lines, with mixed type
 | 
			
		||||
  SetLength(Result, 20);
 | 
			
		||||
  Result[0]  := 'program Foo;';
 | 
			
		||||
  Result[1]  := 'procedure a;';
 | 
			
		||||
  Result[2]  := 'begin';
 | 
			
		||||
  Result[3]  := '{%region}';
 | 
			
		||||
  Result[4]  := '{%endregion} {$ifdef x}';
 | 
			
		||||
  Result[5]  := '             {$endif} if a then begin';
 | 
			
		||||
  Result[6]  := '                      end;             {%region}';
 | 
			
		||||
  Result[7]  := '{%endregion} {$ifdef x}';
 | 
			
		||||
  Result[8]  := '             {$endif} if a then begin';
 | 
			
		||||
  Result[9]  := '                        writeln(1);';
 | 
			
		||||
  Result[10] := '{%region}             end;';
 | 
			
		||||
  Result[11] := '  writeln(1);';
 | 
			
		||||
  Result[12] := '{%endregion}  if a then begin';
 | 
			
		||||
  Result[13] := '                        writeln(1);';
 | 
			
		||||
  Result[14] := '{$ifdef x}    end;';
 | 
			
		||||
  Result[15] := '  writeln(1);';
 | 
			
		||||
  Result[16] := '{$endif}';
 | 
			
		||||
  Result[17] := '  writeln(1);';
 | 
			
		||||
  Result[18] := 'end';
 | 
			
		||||
  Result[19] := '';
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestFoldedView.TestTextHide(ALen: Integer): TStringArray;
 | 
			
		||||
begin
 | 
			
		||||
  SetLength(Result, 3+ALen);
 | 
			
		||||
@ -1457,6 +1485,161 @@ begin
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestFoldedView.TestFoldProvider;
 | 
			
		||||
  procedure DoTestOpenCounts(AName: string; AType: Integer; AExp: Array of Integer);
 | 
			
		||||
  var
 | 
			
		||||
    i: Integer;
 | 
			
		||||
  begin
 | 
			
		||||
    AName := AName + ' (type=' + IntToStr(AType)+') ';
 | 
			
		||||
    for i := low(AExp) to high(AExp) do
 | 
			
		||||
      DebugLn([BaseTestName+AName+ ' line=' + IntToStr(i)+ ' exp=', AExp[i],'   Got=', FoldedView.FoldProvider.FoldOpenCount(i, AType)]);
 | 
			
		||||
    for i := low(AExp) to high(AExp) do
 | 
			
		||||
      AssertEquals(BaseTestName+AName+ ' line=' + IntToStr(i),
 | 
			
		||||
                   AExp[i], FoldedView.FoldProvider.FoldOpenCount(i, AType));
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  // TSynEditFoldProvider.FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
 | 
			
		||||
  PushBaseName('');
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText1', TestText);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone]);
 | 
			
		||||
  //                       p  P  B  ~  -
 | 
			
		||||
  DoTestOpenCounts('', 0, [1, 1, 1, 0, 0]); // all (fold conf)
 | 
			
		||||
  DoTestOpenCounts('', 1, [1, 1, 1, 0, 0]); // pas
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 1, 1, 0, 0]); // pas (incl unfolded)
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0]); // $if
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText1 (2)', TestText);
 | 
			
		||||
  EnableFolds([cfbtTopBeginEnd]);
 | 
			
		||||
  //                       p  P  B  ~  -
 | 
			
		||||
  DoTestOpenCounts('', 0, [0, 0, 1, 0, 0]); // all (fold conf)
 | 
			
		||||
  DoTestOpenCounts('', 1, [0, 0, 1, 0, 0]); // pas
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 1, 1, 0, 0]); // pas (incl unfolded)
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0]); // $if
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText1 (3)', TestText);
 | 
			
		||||
  EnableFolds([cfbtProcedure, cfbtBeginEnd]);
 | 
			
		||||
  //                       p  P  B  ~  -
 | 
			
		||||
  DoTestOpenCounts('', 0, [0, 1, 0, 0, 0]); // all (fold conf)
 | 
			
		||||
  DoTestOpenCounts('', 1, [0, 1, 0, 0, 0]); // pas
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 1, 1, 0, 0]); // pas (incl unfolded)
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0]); // $if
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText2', TestText2);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone]);
 | 
			
		||||
  //                                      if    else
 | 
			
		||||
  //                       p  PP B  -  B  B  ~  -B ~  -  -  ~
 | 
			
		||||
  DoTestOpenCounts('', 0, [1, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [1, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText2 (2)', TestText2);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtProgram, cfbtRegion]);
 | 
			
		||||
  //                       p  PP B  -  B  B  ~  -B ~  -  -  ~
 | 
			
		||||
  DoTestOpenCounts('', 0, [0, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [0, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText3', TestText3);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone],  [cfbtSlashComment]);
 | 
			
		||||
  //                                      if    else        // one-line-comment
 | 
			
		||||
  //                       p  $  P  -  B  %B ~  --B~  -  -  /
 | 
			
		||||
  DoTestOpenCounts('', 0, [1, 1, 1, 0, 1, 2, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // %if
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText3 (2)', TestText3);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtProgram, cfbtRegion],  [cfbtSlashComment]);
 | 
			
		||||
  //                       p  $  P  -  B  %B ~  --B~  -  -  /
 | 
			
		||||
  DoTestOpenCounts('', 0, [0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // %if
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText3 (3)', TestText3);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtProgram, cfbtIfDef], []);
 | 
			
		||||
  //                       p  $  P  -  B  %B ~  --B~  -  -  /
 | 
			
		||||
  DoTestOpenCounts('', 0, [0, 0, 1, 0, 1, 2, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // %if
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  for i := 0 to 2 do begin // pos of $IFDEF does not matter
 | 
			
		||||
    TstSetText('TestTextPasHl-'+IntToStr(i)+'', TestTextPasHl(i));
 | 
			
		||||
    EnableFolds([cfbtBeginEnd..cfbtNone],  [cfbtSlashComment]);
 | 
			
		||||
    //                             if       $E // one-line-comment
 | 
			
		||||
    //                       p  P  $bb-  -  -  /
 | 
			
		||||
    DoTestOpenCounts('', 0, [1, 1, 3, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 1, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    //DoTestOpenCounts('', 4, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
    DoTestOpenCounts('', 3, [0, 0, 1, 0, 0, 0, 0]); // %if
 | 
			
		||||
 | 
			
		||||
    TstSetText('TestTextPasHl-'+IntToStr(i)+'', TestTextPasHl(i));
 | 
			
		||||
    EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtBeginEnd],  [cfbtSlashComment]);
 | 
			
		||||
    //                             if       $E // one-line-comment
 | 
			
		||||
    //                       p  P  $bb-  -  -  /
 | 
			
		||||
    DoTestOpenCounts('', 0, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 1, [1, 1, 1, 0, 0, 0, 1]);
 | 
			
		||||
    //DoTestOpenCounts('', 4, [1, 1, 1, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
    DoTestOpenCounts('', 3, [0, 0, 1, 0, 0, 0, 0]); // %if
 | 
			
		||||
 | 
			
		||||
    TstSetText('TestTextPasHl-'+IntToStr(i)+'', TestTextPasHl(i));
 | 
			
		||||
    EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtIfDef],  [cfbtSlashComment]);
 | 
			
		||||
    //                             if       $E // one-line-comment
 | 
			
		||||
    //                       p  P  $bb-  -  -  /
 | 
			
		||||
    DoTestOpenCounts('', 0, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 1, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    //DoTestOpenCounts('', 4, [1, 1, 2, 0, 0, 0, 1]);
 | 
			
		||||
    DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0, 0]); // %region
 | 
			
		||||
    DoTestOpenCounts('', 3, [0, 0, 0, 0, 0, 0, 0]); // %if
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText4', TestText4);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone],  [cfbtSlashComment]);
 | 
			
		||||
  //                       pPBB  -  B  -  B  -
 | 
			
		||||
  DoTestOpenCounts('', 0, [3, 1, 0, 1, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [3, 1, 0, 1, 0, 1]);
 | 
			
		||||
  //DoTestOpenCounts('', 4, [3, 1, 0, 1, 0, 1]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 0, 0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  TstSetText('TestText8', TestText8);
 | 
			
		||||
  EnableFolds([cfbtBeginEnd..cfbtNone],  [cfbtSlashComment]);
 | 
			
		||||
  //                       p  P  B  %  $  B  %  $  B  ~  %  ~  B  ~  $  ~  -  ~  -
 | 
			
		||||
  DoTestOpenCounts('', 0, [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 1, [1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
//DoTestOpenCounts('', 4, [1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 2, [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
 | 
			
		||||
  DoTestOpenCounts('', 3, [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]);
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
initialization
 | 
			
		||||
 | 
			
		||||
  RegisterTest(TTestFoldedView); 
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										136
									
								
								components/synedit/test/testhighlighterlfm.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								components/synedit/test/testhighlighterlfm.pas
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
			
		||||
unit TestHighlighterLfm;
 | 
			
		||||
 | 
			
		||||
{$mode objfpc}{$H+}
 | 
			
		||||
 | 
			
		||||
interface
 | 
			
		||||
 | 
			
		||||
uses
 | 
			
		||||
  Classes, SysUtils, testregistry, TestBase, Forms, LCLProc, TestHighlightFoldBase,
 | 
			
		||||
  SynEdit, SynEditTypes, SynHighlighterLFM, SynEditHighlighterFoldBase;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  { TTestBaseHighlighterLem }
 | 
			
		||||
 | 
			
		||||
  TTestBaseHighlighterLem = class(TTestBaseHighlighterFoldBase)
 | 
			
		||||
  protected
 | 
			
		||||
    function LfmHighLighter: TSynLFMSyn;
 | 
			
		||||
    function CreateTheHighLighter: TSynCustomFoldHighlighter; override;
 | 
			
		||||
    procedure EnableFolds(AEnbledTypes: TLfmCodeFoldBlockTypes;
 | 
			
		||||
                          AHideTypes: TLfmCodeFoldBlockTypes = [];
 | 
			
		||||
                          ANoFoldTypes: TLfmCodeFoldBlockTypes = []
 | 
			
		||||
                         );
 | 
			
		||||
    //procedure DebugFoldInfo(ALineIdx: Integer; AFilter: TSynFoldActions; Group: Integer=0);
 | 
			
		||||
    //procedure DebugFoldInfo(AFilter: TSynFoldActions; Group: Integer=0);
 | 
			
		||||
    //function FoldActionsToString(AFoldActions: TSynFoldActions): String;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
  { TTestHighlighterLfm }
 | 
			
		||||
 | 
			
		||||
  TTestHighlighterLfm = class(TTestBaseHighlighterLem)
 | 
			
		||||
  protected
 | 
			
		||||
    function TestTextFoldInfo1: TStringArray;
 | 
			
		||||
 | 
			
		||||
    procedure CheckTokensForLine(Name: String; LineIdx: Integer; ExpTokens: Array of TtkTokenKind);
 | 
			
		||||
  published
 | 
			
		||||
    procedure TestFoldInfo;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
 | 
			
		||||
{ TTestBaseHighlighterLem }
 | 
			
		||||
 | 
			
		||||
function TTestBaseHighlighterLem.LfmHighLighter: TSynLFMSyn;
 | 
			
		||||
begin
 | 
			
		||||
  Result := TSynLFMSyn(FTheHighLighter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestBaseHighlighterLem.CreateTheHighLighter: TSynCustomFoldHighlighter;
 | 
			
		||||
begin
 | 
			
		||||
  Result := TSynLFMSyn.Create(nil);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterLem.EnableFolds(AEnbledTypes: TLfmCodeFoldBlockTypes;
 | 
			
		||||
  AHideTypes: TLfmCodeFoldBlockTypes; ANoFoldTypes: TLfmCodeFoldBlockTypes);
 | 
			
		||||
var
 | 
			
		||||
  i: TLfmCodeFoldBlockType;
 | 
			
		||||
begin
 | 
			
		||||
  for i := low(TLfmCodeFoldBlockType) to high(TLfmCodeFoldBlockType) do begin
 | 
			
		||||
    LfmHighLighter.FoldConfig[ord(i)].Enabled := i in AEnbledTypes;
 | 
			
		||||
    if (i in ANoFoldTypes) then
 | 
			
		||||
      LfmHighLighter.FoldConfig[ord(i)].Modes := []
 | 
			
		||||
    else
 | 
			
		||||
      LfmHighLighter.FoldConfig[ord(i)].Modes := [fmFold];
 | 
			
		||||
    if i in AHideTypes then
 | 
			
		||||
      LfmHighLighter.FoldConfig[ord(i)].Modes := LfmHighLighter.FoldConfig[ord(i)].Modes + [fmHide]
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestHighlighterLfm.TestTextFoldInfo1: TStringArray;
 | 
			
		||||
begin
 | 
			
		||||
  SetLength(Result, 11);
 | 
			
		||||
  Result[0] := 'object BreakPointGroupDlg: TBreakPointGroupDlg';
 | 
			
		||||
  Result[1] := '  Left = 431';
 | 
			
		||||
  Result[2] := '  Height = 225';
 | 
			
		||||
  Result[3] := '  object ButtonPanel1: TButtonPanel';
 | 
			
		||||
  Result[4] := '    Left = 6';
 | 
			
		||||
  Result[5] := '  end';
 | 
			
		||||
  Result[6] := '  object Label1: TLabel';
 | 
			
		||||
  Result[7] := '    Left = 0';
 | 
			
		||||
  Result[8] := '  end';
 | 
			
		||||
  Result[9] := 'end';
 | 
			
		||||
  Result[10] := '';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterLfm.CheckTokensForLine(Name: String; LineIdx: Integer;
 | 
			
		||||
  ExpTokens: array of TtkTokenKind);
 | 
			
		||||
var
 | 
			
		||||
  c: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  LfmHighLighter.StartAtLineIndex(LineIdx);
 | 
			
		||||
  c := 0;
 | 
			
		||||
  while not LfmHighLighter.GetEol do begin
 | 
			
		||||
    //DebugLn([LfmHighLighter.GetToken,' (',PasHighLighter.GetTokenID ,') at ', PasHighLighter.GetTokenPos]);
 | 
			
		||||
    AssertEquals(Name + 'TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c),  ord(ExpTokens[c]), ord(LfmHighLighter.GetTokenID));
 | 
			
		||||
    LfmHighLighter.Next;
 | 
			
		||||
    inc(c);
 | 
			
		||||
    if c >= length(ExpTokens) then
 | 
			
		||||
      break;
 | 
			
		||||
  end;
 | 
			
		||||
  AssertEquals(Name+ 'TokenId Line='+IntToStr(LineIdx)+'  amount of tokens', length(ExpTokens), c );
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterLfm.TestFoldInfo;
 | 
			
		||||
begin
 | 
			
		||||
  ReCreateEdit;
 | 
			
		||||
 | 
			
		||||
  //  DebugFoldInfo([]);
 | 
			
		||||
 | 
			
		||||
  {%region}
 | 
			
		||||
  SetLines(TestTextFoldInfo1);
 | 
			
		||||
  EnableFolds([cfbtLfmObject..cfbtLfmNone]);
 | 
			
		||||
  PushBaseName('Text 1 all folds');
 | 
			
		||||
 | 
			
		||||
  EnableFolds([cfbtLfmObject..cfbtLfmNone], [cfbtLfmNone]);
 | 
			
		||||
  AssertEquals('Len 0', 9, LfmHighLighter.FoldLineLength(0,0));
 | 
			
		||||
  //AssertEquals('Len 1', 0, LfmHighLighter.FoldLineLength(1,0));
 | 
			
		||||
  AssertEquals('Len 3', 2, LfmHighLighter.FoldLineLength(3,0));
 | 
			
		||||
  //AssertEquals('Len 4', 0, LfmHighLighter.FoldLineLength(4,0));
 | 
			
		||||
  //AssertEquals('Len 5', 0, LfmHighLighter.FoldLineLength(5,0));
 | 
			
		||||
  AssertEquals('Len 6', 2, LfmHighLighter.FoldLineLength(6,0));
 | 
			
		||||
 | 
			
		||||
  CheckFoldOpenCounts('', [1, 0, 0, 1, 0, 0, 1, 0, 0, 0]);
 | 
			
		||||
 | 
			
		||||
  {%endregion}
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
initialization
 | 
			
		||||
 | 
			
		||||
  RegisterTest(TTestHighlighterLfm);
 | 
			
		||||
end.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										116
									
								
								components/synedit/test/testhighlightfoldbase.pas
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								components/synedit/test/testhighlightfoldbase.pas
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,116 @@
 | 
			
		||||
unit TestHighlightFoldBase;
 | 
			
		||||
 | 
			
		||||
{$mode objfpc}{$H+}
 | 
			
		||||
 | 
			
		||||
interface
 | 
			
		||||
 | 
			
		||||
uses
 | 
			
		||||
  Classes, SysUtils, testregistry, TestBase, Forms, LCLProc,
 | 
			
		||||
  SynEdit, SynEditTypes, SynEditHighlighterFoldBase;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
 | 
			
		||||
  // used by Fold / MarkupWord
 | 
			
		||||
 | 
			
		||||
  { TTestBaseHighlighterPas }
 | 
			
		||||
 | 
			
		||||
  { TTestBaseHighlighterFoldBase }
 | 
			
		||||
 | 
			
		||||
  TTestBaseHighlighterFoldBase = class(TTestBase)
 | 
			
		||||
  protected
 | 
			
		||||
    FTheHighLighter: TSynCustomFoldHighlighter;
 | 
			
		||||
    function CreateTheHighLighter: TSynCustomFoldHighlighter; virtual; abstract;
 | 
			
		||||
    procedure SetUp; override;
 | 
			
		||||
    procedure TearDown; override;
 | 
			
		||||
    procedure ReCreateEdit; reintroduce;
 | 
			
		||||
 | 
			
		||||
    procedure CheckFoldOpenCounts(Name: String; Expected: Array of Integer);
 | 
			
		||||
    procedure CheckFoldInfoCounts(Name: String; Filter: TSynFoldActions; Expected: Array of Integer);
 | 
			
		||||
    procedure CheckFoldInfoCounts(Name: String; Filter: TSynFoldActions; Group: Integer; Expected: Array of Integer);
 | 
			
		||||
 | 
			
		||||
    function FoldActionsToString(AFoldActions: TSynFoldActions): String;
 | 
			
		||||
  end;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
implementation
 | 
			
		||||
 | 
			
		||||
{ TTestBaseHighlighterFoldBase }
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.SetUp;
 | 
			
		||||
begin
 | 
			
		||||
  FTheHighLighter := nil;
 | 
			
		||||
  inherited SetUp;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.TearDown;
 | 
			
		||||
begin
 | 
			
		||||
  if Assigned(SynEdit) then
 | 
			
		||||
    SynEdit.Highlighter := nil;
 | 
			
		||||
  FreeAndNil(FTheHighLighter);
 | 
			
		||||
  inherited TearDown;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.ReCreateEdit;
 | 
			
		||||
begin
 | 
			
		||||
  if Assigned(SynEdit) then
 | 
			
		||||
    SynEdit.Highlighter := nil;
 | 
			
		||||
  FreeAndNil(FTheHighLighter);
 | 
			
		||||
  inherited ReCreateEdit;
 | 
			
		||||
  FTheHighLighter := CreateTheHighLighter;
 | 
			
		||||
  SynEdit.Highlighter := FTheHighLighter;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.CheckFoldOpenCounts(Name: String;
 | 
			
		||||
  Expected: array of Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  for i := 0 to high(Expected) do
 | 
			
		||||
    AssertEquals(Name + 'OpenCount Line OLD='+IntToStr(i),  Expected[i], FTheHighLighter.FoldOpenCount(i));
 | 
			
		||||
 | 
			
		||||
  for i := 0 to high(Expected) do
 | 
			
		||||
    AssertEquals(Name + 'OpenCount Line='+IntToStr(i),  Expected[i], FTheHighLighter.FoldBlockOpeningCount(i));
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.CheckFoldInfoCounts(Name: String;
 | 
			
		||||
  Filter: TSynFoldActions; Expected: array of Integer);
 | 
			
		||||
begin
 | 
			
		||||
  CheckFoldInfoCounts(Name, Filter, 0, Expected);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterFoldBase.CheckFoldInfoCounts(Name: String;
 | 
			
		||||
  Filter: TSynFoldActions; Group: Integer; Expected: array of Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
  l: TLazSynFoldNodeInfoList;
 | 
			
		||||
begin
 | 
			
		||||
  for i := 0 to high(Expected) do begin
 | 
			
		||||
    l := FTheHighLighter.FoldNodeInfo[i];
 | 
			
		||||
    AssertEquals(Name + 'InfoCount(Ex) Line='+IntToStr(i),
 | 
			
		||||
                 Expected[i],
 | 
			
		||||
                 l.CountEx(Filter, Group));
 | 
			
		||||
    l.ClearFilter;
 | 
			
		||||
    l.ActionFilter := Filter;
 | 
			
		||||
    l.GroupFilter := Group;
 | 
			
		||||
    AssertEquals(Name + 'InfoCount Line='+IntToStr(i),
 | 
			
		||||
                 Expected[i],
 | 
			
		||||
                 FTheHighLighter.FoldNodeInfo[i].Count);
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestBaseHighlighterFoldBase.FoldActionsToString(AFoldActions: TSynFoldActions): String;
 | 
			
		||||
var
 | 
			
		||||
  s: string;
 | 
			
		||||
  i: TSynFoldAction;
 | 
			
		||||
begin
 | 
			
		||||
  Result:='';
 | 
			
		||||
  for i := low(TSynFoldAction) to high(TSynFoldAction) do
 | 
			
		||||
    if i in AFoldActions then begin
 | 
			
		||||
      WriteStr(s, i);
 | 
			
		||||
      Result := Result + s + ',';
 | 
			
		||||
    end;
 | 
			
		||||
  if Result <> '' then SetLength(Result, Length(Result)-1);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
end.
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ unit TestHighlightPas;
 | 
			
		||||
interface
 | 
			
		||||
 | 
			
		||||
uses
 | 
			
		||||
  Classes, SysUtils, testregistry, TestBase, Forms, LCLProc,
 | 
			
		||||
  Classes, SysUtils, testregistry, TestBase, Forms, LCLProc, TestHighlightFoldBase,
 | 
			
		||||
  SynEdit, SynEditTypes, SynHighlighterPas, SynEditHighlighterFoldBase;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
@ -14,12 +14,10 @@ type
 | 
			
		||||
 | 
			
		||||
  { TTestBaseHighlighterPas }
 | 
			
		||||
 | 
			
		||||
  TTestBaseHighlighterPas = class(TTestBase)
 | 
			
		||||
  TTestBaseHighlighterPas = class(TTestBaseHighlighterFoldBase)
 | 
			
		||||
  protected
 | 
			
		||||
    PasHighLighter: TSynPasSyn;
 | 
			
		||||
    procedure SetUp; override;
 | 
			
		||||
    procedure TearDown; override;
 | 
			
		||||
    procedure ReCreateEdit; reintroduce;
 | 
			
		||||
    function PasHighLighter: TSynPasSyn;
 | 
			
		||||
    function CreateTheHighLighter: TSynCustomFoldHighlighter; override;
 | 
			
		||||
    procedure EnableFolds(AEnbledTypes: TPascalCodeFoldBlockTypes;
 | 
			
		||||
                          AHideTypes: TPascalCodeFoldBlockTypes = [];
 | 
			
		||||
                          ANoFoldTypes: TPascalCodeFoldBlockTypes = []
 | 
			
		||||
@ -38,12 +36,8 @@ type
 | 
			
		||||
    function TestTextFoldInfo3: TStringArray;
 | 
			
		||||
    function TestTextFoldInfo4(AIfCol: Integer): TStringArray;
 | 
			
		||||
 | 
			
		||||
    procedure CheckFoldOpenCounts(Name: String; Expected: Array of Integer);
 | 
			
		||||
    procedure CheckFoldInfoCounts(Name: String; Filter: TSynFoldActions; Expected: Array of Integer);
 | 
			
		||||
    procedure CheckFoldInfoCounts(Name: String; Filter: TSynFoldActions; Group: Integer; Expected: Array of Integer);
 | 
			
		||||
    procedure CheckTokensForLine(Name: String; LineIdx: Integer; ExpTokens: Array of TtkTokenKind);
 | 
			
		||||
 | 
			
		||||
    function FoldActionsToString(AFoldActions: TSynFoldActions): String;
 | 
			
		||||
  published
 | 
			
		||||
    procedure TestFoldInfo;
 | 
			
		||||
    procedure TestExtendedKeywordsAndStrings;
 | 
			
		||||
@ -60,28 +54,14 @@ implementation
 | 
			
		||||
 | 
			
		||||
{ TTestBaseHighlighterPas }
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterPas.SetUp;
 | 
			
		||||
function TTestBaseHighlighterPas.PasHighLighter: TSynPasSyn;
 | 
			
		||||
begin
 | 
			
		||||
  PasHighLighter := nil;
 | 
			
		||||
  inherited SetUp;
 | 
			
		||||
  Result := TSynPasSyn(FTheHighLighter);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterPas.TearDown;
 | 
			
		||||
function TTestBaseHighlighterPas.CreateTheHighLighter: TSynCustomFoldHighlighter;
 | 
			
		||||
begin
 | 
			
		||||
  if Assigned(SynEdit) then
 | 
			
		||||
    SynEdit.Highlighter := nil;
 | 
			
		||||
  FreeAndNil(PasHighLighter);
 | 
			
		||||
  inherited TearDown;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterPas.ReCreateEdit;
 | 
			
		||||
begin
 | 
			
		||||
  if Assigned(SynEdit) then
 | 
			
		||||
    SynEdit.Highlighter := nil;
 | 
			
		||||
  FreeAndNil(PasHighLighter);
 | 
			
		||||
  inherited ReCreateEdit;
 | 
			
		||||
  PasHighLighter := TSynPasSyn.Create(nil);
 | 
			
		||||
  SynEdit.Highlighter := PasHighLighter;
 | 
			
		||||
  Result := TSynPasSyn.Create(nil);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestBaseHighlighterPas.EnableFolds(AEnbledTypes: TPascalCodeFoldBlockTypes;
 | 
			
		||||
@ -114,8 +94,8 @@ begin
 | 
			
		||||
  l.GroupFilter := Group;
 | 
			
		||||
  debugln(['### Foldinfo Line: ', ALineIdx,
 | 
			
		||||
           ' Cnt=', l.Count, ' CntEx=', c,
 | 
			
		||||
           '   PasMinLvl=',PasHighLighter.MinimumPasFoldLevel(ALineIdx,1),
 | 
			
		||||
           ' EndLvl=',PasHighLighter.EndPasFoldLevel(ALineIdx,1),
 | 
			
		||||
           '   PasMinLvl=', PasHighLighter.FoldBlockMinLevel(ALineIdx,1),
 | 
			
		||||
           ' EndLvl=',PasHighLighter.FoldBlockEndLevel(ALineIdx,1),
 | 
			
		||||
           //' Nestcnt=',PasHighLighter.FoldNestCount(ALineIdx,1),
 | 
			
		||||
            ' : ', copy(SynEdit.Lines[ALineIdx],1,40)]);
 | 
			
		||||
  debugln('Idx: LogXStart End  FldLvlStart End  NestLvlStart End  FldType FldTypeCompat FldGroup FldAction');
 | 
			
		||||
@ -231,40 +211,6 @@ begin
 | 
			
		||||
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterPas.CheckFoldOpenCounts(Name: String; Expected: array of Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
begin
 | 
			
		||||
  for i := 0 to high(Expected) do
 | 
			
		||||
    AssertEquals(Name + 'OpenCount Line='+IntToStr(i),  Expected[i], PasHighLighter.FoldOpenCount(i));
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterPas.CheckFoldInfoCounts(Name: String; Filter: TSynFoldActions;
 | 
			
		||||
  Expected: array of Integer);
 | 
			
		||||
begin
 | 
			
		||||
  CheckFoldInfoCounts(Name, Filter, 0, Expected);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterPas.CheckFoldInfoCounts(Name: String;
 | 
			
		||||
  Filter: TSynFoldActions; Group: Integer; Expected: array of Integer);
 | 
			
		||||
var
 | 
			
		||||
  i: Integer;
 | 
			
		||||
  l: TLazSynFoldNodeInfoList;
 | 
			
		||||
begin
 | 
			
		||||
  for i := 0 to high(Expected) do begin
 | 
			
		||||
    l := PasHighLighter.FoldNodeInfo[i];
 | 
			
		||||
    AssertEquals(Name + 'InfoCount(Ex) Line='+IntToStr(i),
 | 
			
		||||
                 Expected[i],
 | 
			
		||||
                 l.CountEx(Filter, Group));
 | 
			
		||||
    l.ClearFilter;
 | 
			
		||||
    l.ActionFilter := Filter;
 | 
			
		||||
    l.GroupFilter := Group;
 | 
			
		||||
    AssertEquals(Name + 'InfoCount Line='+IntToStr(i),
 | 
			
		||||
                 Expected[i],
 | 
			
		||||
                 PasHighLighter.FoldNodeInfo[i].Count);
 | 
			
		||||
  end;
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterPas.CheckTokensForLine(Name: String; LineIdx: Integer;
 | 
			
		||||
  ExpTokens: array of TtkTokenKind);
 | 
			
		||||
var
 | 
			
		||||
@ -283,21 +229,6 @@ begin
 | 
			
		||||
  AssertEquals(Name+ 'TokenId Line='+IntToStr(LineIdx)+'  amount of tokens', length(ExpTokens), c );
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
function TTestHighlighterPas.FoldActionsToString(AFoldActions: TSynFoldActions
 | 
			
		||||
  ): String;
 | 
			
		||||
var
 | 
			
		||||
  s: string;
 | 
			
		||||
  i: TSynFoldAction;
 | 
			
		||||
begin
 | 
			
		||||
  Result:='';
 | 
			
		||||
  for i := low(TSynFoldAction) to high(TSynFoldAction) do
 | 
			
		||||
    if i in AFoldActions then begin
 | 
			
		||||
      WriteStr(s, i);
 | 
			
		||||
      Result := Result + s + ',';
 | 
			
		||||
    end;
 | 
			
		||||
  if Result <> '' then SetLength(Result, Length(Result)-1);
 | 
			
		||||
end;
 | 
			
		||||
 | 
			
		||||
procedure TTestHighlighterPas.TestFoldInfo;
 | 
			
		||||
begin
 | 
			
		||||
  ReCreateEdit;
 | 
			
		||||
@ -1013,12 +944,12 @@ begin
 | 
			
		||||
      CheckFoldInfoCounts('', [], 4, [1, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 2]);
 | 
			
		||||
 | 
			
		||||
      //### Foldinfo Line: 0   PasMinLvl=0 EndLvl=0 : program Foo;
 | 
			
		||||
      CheckNode( 0, [], 4,   0,   0, 7,   0, 0,   0, 1,   10, 10,  4, [sfaOpen,sfaMarkup]);   // program
 | 
			
		||||
      CheckNode( 0, [], 4,   0,   0, 7,   0, 0,   0, 1,   10, 10,  1, [sfaOpen,sfaMarkup]);   // program
 | 
			
		||||
      //### Foldinfo Line: 1   PasMinLvl=0 EndLvl=0 : procedure a;
 | 
			
		||||
      CheckNode( 1, [], 4,   0,   0, 9,   1, 1,   1, 2,   3, 3,  4, [sfaOpen,sfaMarkup]);   // procedure
 | 
			
		||||
      CheckNode( 1, [], 4,   0,   0, 9,   1, 1,   1, 2,   3, 3,  1, [sfaOpen,sfaMarkup]);   // procedure
 | 
			
		||||
      //### Foldinfo Line: 2   PasMinLvl=0 EndLvl=0 : {$IFDEF A}
 | 
			
		||||
      //### Foldinfo Line: 3   PasMinLvl=0 EndLvl=0 : begin
 | 
			
		||||
      CheckNode( 3, [], 4,   0,   0, 5,   2, 2,   2, 3,   1, 0,  4, [sfaOpen,sfaMarkup]);   // begin
 | 
			
		||||
      CheckNode( 3, [], 4,   0,   0, 5,   2, 2,   2, 3,   1, 0,  1, [sfaOpen,sfaMarkup]);   // begin
 | 
			
		||||
      //### Foldinfo Line: 4   PasMinLvl=0 EndLvl=0 : {$ENDIF}
 | 
			
		||||
      //### Foldinfo Line: 5   PasMinLvl=0 EndLvl=1 :   {$IFDEF B} if a then begin {$ENDIF}
 | 
			
		||||
      CheckNode( 5, [], 4,   0,   23, 28,   0, 1,   3, 4,   0, 0,  1, [sfaOpen,sfaMarkup,sfaFold,sfaFoldFold]);   //  begin
 | 
			
		||||
@ -1026,16 +957,16 @@ begin
 | 
			
		||||
      //### Foldinfo Line: 7   PasMinLvl=0 EndLvl=0 :   end;
 | 
			
		||||
      CheckNode( 7, [], 4,   0,   2, 5,   1, 0,   4, 3,   0, 0,  1, [sfaClose,sfaMarkup,sfaFold]);   //  end
 | 
			
		||||
      //### Foldinfo Line: 8   PasMinLvl=0 EndLvl=0 : end;
 | 
			
		||||
      CheckNode( 8, [], 4,   0,   0, 3,   3, 3,   3, 2,   1, 0,  4, [sfaClose,sfaMarkup]);   // end;
 | 
			
		||||
      CheckNode( 8, [], 4,   1,   0, 3,   2, 2,   2, 1,   3, 3,  4, [sfaClose,sfaMarkup]);   // end;
 | 
			
		||||
      CheckNode( 8, [], 4,   0,   0, 3,   3, 3,   3, 2,   1, 0,  1, [sfaClose,sfaMarkup]);   // end;
 | 
			
		||||
      CheckNode( 8, [], 4,   1,   0, 3,   2, 2,   2, 1,   3, 3,  1, [sfaClose,sfaMarkup]);   // end;
 | 
			
		||||
      //### Foldinfo Line: 9   PasMinLvl=0 EndLvl=1 : begin
 | 
			
		||||
      CheckNode( 9, [], 4,   0,   0, 5,   0, 1,   1, 2,   0, 0,  1, [sfaOpen,sfaMarkup,sfaFold,sfaFoldFold]);   // begin
 | 
			
		||||
      //### Foldinfo Line: 10   PasMinLvl=0 EndLvl=0 : end.
 | 
			
		||||
      CheckNode(10, [], 4,   0,   0, 3,   1, 0,   2, 1,   0, 0,  1, [sfaClose,sfaMarkup,sfaFold]);   // end.
 | 
			
		||||
      CheckNode(10, [], 4,   1,   0, 3,   1, 1,   1, 0,   10, 10,  4, [sfaClose,sfaMarkup]);   // end.
 | 
			
		||||
      CheckNode(10, [], 4,   1,   0, 3,   1, 1,   1, 0,   10, 10,  1, [sfaClose,sfaMarkup]);   // end.
 | 
			
		||||
      //### Foldinfo Line: 11   PasMinLvl=0 EndLvl=0 : //
 | 
			
		||||
      CheckNode(11, [], 4,   0,   0, 2,   0, 0,   0, 1,   22, 22,  4, [sfaOpen]);   // //
 | 
			
		||||
      CheckNode(11, [], 4,   1,   2, 2,   1, 1,   1, 0,   22, 22,  4, [sfaClose,sfaLastLineClose]);   // /
 | 
			
		||||
      CheckNode(11, [], 4,   0,   0, 2,   0, 0,   0, 1,   22, 22,  1, [sfaOpen]);   // //
 | 
			
		||||
      CheckNode(11, [], 4,   1,   2, 2,   1, 1,   1, 0,   22, 22,  1, [sfaClose,sfaLastLineClose]);   // /
 | 
			
		||||
    {%endregion TEXT 1 -- [cfbtBeginEnd..cfbtNone], [] grp=4}
 | 
			
		||||
 | 
			
		||||
    {%region TEXT 1 -- [cfbtBeginEnd..cfbtNone], [sfaFold]}
 | 
			
		||||
@ -1116,7 +1047,7 @@ begin
 | 
			
		||||
      //### Foldinfo Line: 0   PasMinLvl=0 EndLvl=1 : program Foo;
 | 
			
		||||
      CheckNode( 0, [], 0,   0,   0, 7,   0, 1,   0, 1,   10, 10,  1, [sfaOpen,sfaMarkup,sfaFold,sfaFoldFold]);
 | 
			
		||||
      //### Foldinfo Line: 1   PasMinLvl=1 EndLvl=1 : procedure a;
 | 
			
		||||
      CheckNode( 1, [], 0,   0,   0, 9,   1, 1,   1, 2,   3, 3,  4, [sfaOpen,sfaMarkup]);
 | 
			
		||||
      CheckNode( 1, [], 0,   0,   0, 9,   1, 1,   1, 2,   3, 3,  1, [sfaOpen,sfaMarkup]);
 | 
			
		||||
      //### Foldinfo Line: 2   PasMinLvl=1 EndLvl=1 : {$IFDEF A}
 | 
			
		||||
      CheckNode( 2, [], 0,   0,   2, 7,   0, 1,   0, 1,   18, 18,  3, [sfaOpen,sfaFold,sfaFoldFold]);
 | 
			
		||||
      //### Foldinfo Line: 3   PasMinLvl=1 EndLvl=2 : begin
 | 
			
		||||
@ -1132,7 +1063,7 @@ begin
 | 
			
		||||
      CheckNode( 7, [], 0,   0,   2, 5,   3, 2,   4, 3,   0, 0,  1, [sfaClose,sfaMarkup,sfaFold]);
 | 
			
		||||
      //### Foldinfo Line: 8   PasMinLvl=1 EndLvl=1 : end;
 | 
			
		||||
      CheckNode( 8, [], 0,   0,   0, 3,   2, 1,   3, 2,   1, 0,  1, [sfaClose,sfaMarkup,sfaFold]);
 | 
			
		||||
      CheckNode( 8, [], 0,   1,   0, 3,   2, 2,   2, 1,   3, 3,  4, [sfaClose,sfaMarkup]);
 | 
			
		||||
      CheckNode( 8, [], 0,   1,   0, 3,   2, 2,   2, 1,   3, 3,  1, [sfaClose,sfaMarkup]);
 | 
			
		||||
      //### Foldinfo Line: 9   PasMinLvl=1 EndLvl=2 : begin
 | 
			
		||||
      CheckNode( 9, [], 0,   0,   0, 5,   1, 2,   1, 2,   0, 0,  1, [sfaOpen,sfaMarkup,sfaFold,sfaFoldFold]);
 | 
			
		||||
      //### Foldinfo Line: 10   PasMinLvl=0 EndLvl=0 : end.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user