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

View File

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

View File

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

View File

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