SynEdit Folding: Improved block detection for Pop-up-Menu on fold-gutter

git-svn-id: trunk@19511 -
This commit is contained in:
martin 2009-04-19 12:44:11 +00:00
parent dcc7ce6884
commit 59d3bbd7e9
4 changed files with 89 additions and 25 deletions

View File

@ -173,7 +173,7 @@ type
TFoldViewNodeInfo = record
HNode: TSynFoldNodeInfo;
Text, Keyword: String;
LineNum, ColIndex, OpenIndex: Integer;
LineNum, ColIndex: Integer;
OpenCount: Integer;
Folded: boolean;
end;
@ -2170,36 +2170,72 @@ end;
function TSynEditFoldedView.OpenFoldInfo(aStartIndex, ColIndex: Integer): TFoldViewNodeInfo;
var
hl: TSynCustomFoldHighlighter;
n, o: Integer;
TypeCnt, Lvl: Integer;
EndLvl, CurLvl: Array of integer;
i, t, n, o: Integer;
nd: TSynFoldNodeInfo;
procedure GetEndLvl(l: Integer);
var i: integer;
begin
for i := 1 to TypeCnt do begin
EndLvl[i] := hl.FoldNestCount(l-1, i);
EndLvl[i] := EndLvl[i] + hl.FoldOpenCount(l, i);
CurLvl[i] := EndLvl[i];
end
end;
begin
if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter))
then exit;
hl := TSynCustomFoldHighlighter(FHighLighter);
hl.CurrentLines := fLines;
n := hl.FoldNestCount(AStartIndex-1);
while (ColIndex < n) do begin
TypeCnt := hl.FoldTypeCount;
Lvl := hl.FoldNestCount(AStartIndex-1);
i := 0;
if ColIndex >= Lvl then begin
// search current line
Lvl := Lvl + hl.FoldOpenCount(aStartIndex);
i := 1;
end;
SetLength(EndLvl, TypeCnt+1);
SetLength(CurLvl, TypeCnt+1);
GetEndLvl(aStartIndex);
GetEndLvl(aStartIndex);
aStartIndex := aStartIndex + i;
while (ColIndex < Lvl) and (aStartIndex > 0) do begin
dec(aStartIndex);
n := hl.FoldNestCount(AStartIndex-1);
if (hl.FoldOpenCount(aStartIndex) > 0) or
(hl.FoldCloseCount(aStartIndex) > 0) then begin
o := hl.FoldOpenCount(AStartIndex);
n := o;
for i := hl.FoldNodeInfoCount[aStartIndex] - 1 downto 0 do begin
nd := hl.FoldNodeInfo[aStartIndex, i];
t := nd.FoldGroup;
if sfaOpen in nd.FoldAction then begin
dec(n);
dec(CurLvl[t]);
if CurLvl[t] < EndLvl[t] then begin
dec(EndLvl[t]);
dec(Lvl);
if ColIndex = Lvl then begin
break;
end;
end;
end else
if sfaClose in nd.FoldAction then begin
inc(CurLvl[t]);
end;
end;
end
else
if hl.FoldNestCount(AStartIndex-1) = 0 then break;
end;
ColIndex := ColIndex - n;
o := hl.FoldOpenCount(AStartIndex);
Result.OpenCount := o;
n := hl.FoldNodeInfoCount[aStartIndex] - 1;
while (o > ColIndex) and (n >= 0) do begin
nd := hl.FoldNodeInfo[aStartIndex, n];
if sfaInvalid in nd.FoldAction then break;
if sfaClose in nd.FoldAction then inc(o);
if sfaOpen in nd.FoldAction then dec(o);
dec(n);
end;
inc(n);
Result.HNode := nd;
Result.OpenCount := o;
Result.Text := fLines[aStartIndex];
Result.Keyword := copy(Result.Text, 1 + nd.LogXStart, nd.LogXEnd-nd.LogXStart);
Result.LineNum := aStartIndex + 1;
Result.ColIndex := ColIndex; // for FoldAction
Result.OpenIndex := ColIndex; // for (2/3)
Result.ColIndex := n;
Result.Folded := IsFoldedAtTextIndex(aStartIndex, ColIndex);
end;

View File

@ -110,6 +110,7 @@ type
FoldLvlStart, FoldLvlEnd: Integer;
FoldAction: TSynFoldActions;
FoldType: Pointer;
FoldGroup: Integer;
end;
{ TSynCustomFoldHighlighter }
@ -152,6 +153,7 @@ type
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;
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; virtual;
@ -317,6 +319,11 @@ begin
Result := 0;
end;
function TSynCustomFoldHighlighter.FoldTypeCount: integer;
begin
Result := 1;
end;
function TSynCustomFoldHighlighter.FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
UseCloseNodes: boolean): integer;
begin

View File

@ -203,7 +203,7 @@ begin
s := s + copy(inf.Text, inf.HNode.LogXStart, 30 + (30 - length(s)));
s2 := '';
if inf.OpenCount > 1 then
s2 := format(' (%d/%d)', [inf.OpenIndex+1, inf.OpenCount]);
s2 := format(' (%d/%d)', [inf.ColIndex+1, inf.OpenCount]);
m := TMenuItem.Create(FPopUp);
m.Caption := format('%4d %-12s %s', [ inf.LineNum, inf.Keyword+s2+':', s]);
m.ShowAlwaysCheckable := true;

View File

@ -472,6 +472,7 @@ type
function FoldOpenCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
function FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
function FoldNestCount(ALineIndex: Integer; AType: Integer = 0): integer; override;
function FoldTypeCount: integer; override;
function FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
UseCloseNodes: boolean = false): integer; override;
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; override;
@ -1890,6 +1891,7 @@ begin
end;
'{':
if NestedComments then begin
fStringLen := 1;
StartPascalCodeFoldBlock(cfbtNestedComment);
end;
end;
@ -1949,8 +1951,10 @@ begin
break;
end;
'{':
if NestedComments then
if NestedComments then begin
fStringLen := 1;
StartPascalCodeFoldBlock(cfbtNestedComment);
end;
end;
Inc(Run);
until (Run>=fLineLen);
@ -2104,8 +2108,9 @@ begin
else if NestedComments
and (fLine[Run] = '(') and (fLine[Run + 1] = '*') then
begin
Inc(Run,2);
fStringLen := 2;
StartPascalCodeFoldBlock(cfbtNestedComment);
Inc(Run,2);
end else
Inc(Run);
until (Run>=fLineLen) or (fLine[Run] in [#0, #10, #13]);
@ -2490,6 +2495,7 @@ end;
function TSynPasSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer = 0): integer;
var
inf, inf2: TSynPasRangeInfo;
r: TSynPasSynRange;
begin
Result := 0;
if (AType <> 1) then begin
@ -2497,7 +2503,8 @@ begin
inf2 := TSynHighlighterPasRangeList(CurrentRanges).PasRangeInfo[ALineIndex - 1];
end;
if (AType = 0) or (AType = 1) then
Result := EndPasFoldLevel(ALineIndex - 1) - MinimumPasFoldLevel(ALineIndex);
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
@ -2519,6 +2526,11 @@ begin
Result := Result + inf.EndLevelIfDef;
end;
function TSynPasSyn.FoldTypeCount: integer;
begin
Result := 3;
end;
function TSynPasSyn.FoldTypeAtNodeIndex(ALineIndex, FoldIndex: Integer;
UseCloseNodes: boolean): integer;
var
@ -2686,6 +2698,14 @@ begin
Node.FoldLvlStart := CurrentCodeFoldBlockLevel;
Node.FoldLvlEnd := CurrentCodeFoldBlockLevel + EndOffs;
Node.FoldType := Pointer(PtrInt(ABlockType));
case ABlockType of
cfbtRegion:
node.FoldGroup := 2;
cfbtIfDef:
node.FoldGroup := 3;
else
node.FoldGroup := 1;
end;
if ABlockType in PascalWordTrippletRanges then
Node.FoldAction := [sfaMarkup]
else
@ -2825,6 +2845,7 @@ begin
then begin
PasCodeFoldRange.DecLastLineCodeFoldLevelFix;
dec(FStartCodeFoldBlockLevel);
if FCatchNodeInfo then dec(FNodeInfoCount);
end;
if (PasCodeFoldRange.PasFoldEndLevel < FPasStartLevel) and
(FPasStartLevel > 0)
@ -3059,12 +3080,12 @@ begin
FNodeInfoCount := 0;
StartAtLineIndex(Line);
fStringLen := 0;
i := LastLineFoldLevelFix(Line);
NextToEol;
i := LastLineFoldLevelFix(Line+1);
while i < 0 do begin
EndCodeFoldBlock;
inc(i);
end;
NextToEol;
FCatchNodeInfo := False;
FNodeInfoLine := Line;
end;