mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-19 11:00:24 +02:00
SynEdit: added (initial) outline markup by x2nie https://github.com/x2nie/syneditmarkupnestedcolors
git-svn-id: trunk@52166 -
This commit is contained in:
parent
e78034e3ad
commit
94b7995f86
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -3784,6 +3784,7 @@ components/synedit/syneditmarks.pp svneol=native#text/plain
|
||||
components/synedit/syneditmarkup.pp svneol=native#text/plain
|
||||
components/synedit/syneditmarkupbracket.pp svneol=native#text/plain
|
||||
components/synedit/syneditmarkupctrlmouselink.pp svneol=native#text/plain
|
||||
components/synedit/syneditmarkupfoldcoloring.pas svneol=native#text/pascal
|
||||
components/synedit/syneditmarkupguttermark.pp svneol=native#text/pascal
|
||||
components/synedit/syneditmarkuphighall.pp svneol=native#text/plain
|
||||
components/synedit/syneditmarkupifdef.pp svneol=native#text/pascal
|
||||
|
@ -31,7 +31,8 @@ uses
|
||||
LazSynTextArea, SynRegExpr, SynTextDrawer, SynEditMarkupGutterMark,
|
||||
SynHighlighterBat, SynHighlighterIni, SynEditMarkupSpecialChar,
|
||||
SynEditTextDoubleWidthChars, SynEditTextSystemCharWidth, SynEditMarkupIfDef,
|
||||
SynPluginMultiCaret, synhighlighterpike, LazarusPackageIntf;
|
||||
SynPluginMultiCaret, synhighlighterpike, SynEditMarkupFoldColoring,
|
||||
LazarusPackageIntf;
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -37,7 +37,7 @@ Alternatively, the contents of these files may be used under the terms of the GN
|
||||
If you wish to allow use of your version of these files only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL.
|
||||
"/>
|
||||
<Version Major="1"/>
|
||||
<Files Count="83">
|
||||
<Files Count="84">
|
||||
<Item1>
|
||||
<Filename Value="synbeautifier.pas"/>
|
||||
<UnitName Value="SynBeautifier"/>
|
||||
@ -373,6 +373,10 @@ If you wish to allow use of your version of these files only under the terms of
|
||||
<Filename Value="synhighlighterpike.pas"/>
|
||||
<UnitName Value="synhighlighterpike"/>
|
||||
</Item83>
|
||||
<Item84>
|
||||
<Filename Value="syneditmarkupfoldcoloring.pas"/>
|
||||
<UnitName Value="SynEditMarkupFoldColoring"/>
|
||||
</Item84>
|
||||
</Files>
|
||||
<LazDoc Paths="docs\xml"/>
|
||||
<i18n>
|
||||
|
@ -80,6 +80,12 @@ type
|
||||
|
||||
sfaDefaultCollapsed,
|
||||
sfaMarkup, // This node can be highlighted, by the matching Word-Pair Markup
|
||||
sfaOutline, // This node will be higlighted by nested color replacing the token color
|
||||
sfaOutlineKeepLevel, // Direct children should not increase color dept. (But grandchild can.) e.g. "if","then" any "procedure"
|
||||
sfaOutlineMergeParent,// This node want to decrease current color depth. (But Previous sibling increased) e.g. "except", "finally"
|
||||
sfaOutlineForceIndent, // Node will temporary ignore sfaOutlineKeep. (Next sibling can.) e.g in NESTED "procedure"
|
||||
sfaOutlineNoColor, // Node will not painted by nested-coloring, but may increase color (e.g. any "procedure")
|
||||
sfaOutlineNoLine, // Node doesn't want to have vertical line. (e.g. "then")
|
||||
sfaInvalid, // Wrong Index
|
||||
|
||||
// TODO: deprecate
|
||||
@ -197,7 +203,7 @@ type
|
||||
property Line: TLineIdx read FLine write SetLine;
|
||||
end;
|
||||
|
||||
TSynCustomFoldConfigMode = (fmFold, fmHide, fmMarkup);
|
||||
TSynCustomFoldConfigMode = (fmFold, fmHide, fmMarkup, fmOutline);
|
||||
TSynCustomFoldConfigModes = set of TSynCustomFoldConfigMode;
|
||||
|
||||
{ TSynCustomFoldConfig }
|
||||
@ -1647,6 +1653,7 @@ begin
|
||||
if fmFold in AValue then FFoldActions := FFoldActions + [sfaFold, sfaFoldFold];
|
||||
if fmHide in AValue then FFoldActions := FFoldActions + [sfaFold, sfaFoldHide];
|
||||
if fmMarkup in AValue then FFoldActions := FFoldActions + [sfaMarkup];
|
||||
if fmOutline in AValue then FFoldActions := FFoldActions + [sfaOutline];
|
||||
DoOnChange;
|
||||
end;
|
||||
|
||||
|
664
components/synedit/syneditmarkupfoldcoloring.pas
Normal file
664
components/synedit/syneditmarkupfoldcoloring.pas
Normal file
@ -0,0 +1,664 @@
|
||||
{-------------------------------------------------------------------------------
|
||||
The contents of this file are subject to the Mozilla Public License
|
||||
Version 1.1 (the "License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
http://www.mozilla.org/MPL/
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS" basis,
|
||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
the specific language governing rights and limitations under the License.
|
||||
|
||||
The Original Code is: SynEditMarkupFoldColoring.pas, released 2015-12-07.
|
||||
Copyleft (c) 2015-2016 x2nie - Fathony Luth.
|
||||
|
||||
The Original SynEdit Project is based on mwCustomEdit.pas by Martin Waldenburg,
|
||||
part of the mwEdit component suite.
|
||||
Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg.
|
||||
All Rights Reserved.
|
||||
|
||||
Contributors to the SynEdit and mwEdit projects are listed in the
|
||||
Contributors.txt file.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of the
|
||||
GNU General Public License Version 2 or later (the "GPL"), in which case
|
||||
the provisions of the GPL are applicable instead of those above.
|
||||
If you wish to allow use of your version of this file only under the terms
|
||||
of the GPL and not to allow others to use your version of this file
|
||||
under the MPL, indicate your decision by deleting the provisions above and
|
||||
replace them with the notice and other provisions required by the GPL.
|
||||
If you do not delete the provisions above, a recipient may use your version
|
||||
of this file under either the MPL or the GPL.
|
||||
|
||||
|
||||
You may retrieve the latest version of this file at the SynEdit home page,
|
||||
located at http://SynEdit.SourceForge.net
|
||||
|
||||
But to run properly with this file, you need the Lazarus SynEdit LCL >= 1.6
|
||||
|
||||
|
||||
Features:
|
||||
- paint keywords in multiple colors, depends on fold block level or by config
|
||||
- paint vertical line between paired open~close fold
|
||||
- vertical line and/or keyword can be disabled
|
||||
- independent, can be used for any SynHighlighter
|
||||
- many features are well tested for PasSynPas.pas
|
||||
- only active when SynEdit.Highlighter is TSynCustomFoldHighlighter
|
||||
|
||||
|
||||
Known Issues:
|
||||
- Slowdown scrolling in large file ( > 4000 lines )
|
||||
- wrong drawing vertical lines position when a line is mixed with tab char
|
||||
- poor configuration
|
||||
- no design time
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------}
|
||||
unit SynEditMarkupFoldColoring;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils,Graphics, SynEditMarkup, SynEditMiscClasses, Controls,
|
||||
LCLProc, SynEditHighlighter, SynEditHighlighterFoldBase;
|
||||
|
||||
type
|
||||
|
||||
PMarkupFoldColorInfo = ^TMarkupFoldColorInfo;
|
||||
TMarkupFoldColorInfo = record
|
||||
Y, X, X2: Integer;
|
||||
ColorIdx: Integer;
|
||||
Border : Boolean;
|
||||
Ignore : Boolean; //no color no line
|
||||
SrcNode : TSynFoldNodeInfo;
|
||||
LevelBefore, LevelAfter : integer;//needed by non nest nodes
|
||||
end;
|
||||
|
||||
TMarkupFoldColorInfos = array of TMarkupFoldColorInfo;
|
||||
TSynFoldNodeInfos = array of TSynFoldNodeInfo; //for quick compare detection
|
||||
|
||||
{ TSynEditMarkupFoldColors }
|
||||
|
||||
TSynEditMarkupFoldColors = class(TSynEditMarkup)
|
||||
private
|
||||
FDefaultGroup: integer;
|
||||
// Physical Position
|
||||
FHighlights : TMarkupFoldColorInfos; //array of TMarkupFoldColorInfo;
|
||||
Colors : array of TColor;
|
||||
|
||||
{%region invalidating}
|
||||
CurrentY : integer; //??
|
||||
FCaretY : integer; // flag identify for refresh begin______
|
||||
FPrevCaretText : string; // flag identify for refresh begin______
|
||||
{%endregion}
|
||||
|
||||
procedure DoMarkupParentFoldAtRow(aRow: Integer);
|
||||
procedure DoMarkupParentCloseFoldAtRow(aRow: Integer);
|
||||
|
||||
function GetFoldHighLighter: TSynCustomFoldHighlighter;
|
||||
protected
|
||||
// Notifications about Changes to the text
|
||||
procedure DoTextChanged({%H-}StartLine, EndLine, {%H-}ACountDiff: Integer); override; // 1 based
|
||||
procedure DoCaretChanged(Sender: TObject); override;
|
||||
public
|
||||
constructor Create(ASynEdit : TSynEditBase);
|
||||
function GetMarkupAttributeAtRowCol(const aRow: Integer;
|
||||
const aStartCol: TLazSynDisplayTokenBound;
|
||||
const {%H-}AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor; override;
|
||||
procedure GetNextMarkupColAfterRowCol(const aRow: Integer;
|
||||
const aStartCol: TLazSynDisplayTokenBound;
|
||||
const {%H-}AnRtlInfo: TLazSynDisplayRtlInfo;
|
||||
out ANextPhys, ANextLog: Integer); override;
|
||||
|
||||
procedure PrepareMarkupForRow(aRow : Integer); override;
|
||||
property DefaultGroup : integer read FDefaultGroup write FDefaultGroup;
|
||||
end;
|
||||
|
||||
implementation
|
||||
uses
|
||||
SynEdit,SynEditTypes, SynEditFoldedView, SynEditMiscProcs;
|
||||
|
||||
{%region Sorting FoldInfo -fold}
|
||||
function CompareFI(Item1, Item2: Pointer): Integer;
|
||||
begin
|
||||
result := PMarkupFoldColorInfo(Item1)^.X - PMarkupFoldColorInfo(Item2)^.X;
|
||||
if result = 0 then
|
||||
result := PMarkupFoldColorInfo(Item1)^.X2 - PMarkupFoldColorInfo(Item2)^.X2;
|
||||
if result = 0 then
|
||||
result := (PMarkupFoldColorInfo(Item1)^.X2 - PMarkupFoldColorInfo(Item1)^.X)
|
||||
- (PMarkupFoldColorInfo(Item2)^.X2 - PMarkupFoldColorInfo(Item2)^.X);
|
||||
end;
|
||||
|
||||
function SortLeftMostFI(a: TMarkupFoldColorInfos): TMarkupFoldColorInfos;
|
||||
var
|
||||
l : TFpList;
|
||||
i : integer;
|
||||
begin
|
||||
l := TFpList.Create;
|
||||
for i := 0 to Pred(Length(a)) do
|
||||
l.Add( PMarkupFoldColorInfo(@a[i]) );
|
||||
l.Sort(@CompareFI);
|
||||
|
||||
SetLength(result, Length(a));
|
||||
for i := 0 to Pred(l.Count) do
|
||||
result[i] := PMarkupFoldColorInfo(l[i])^;
|
||||
l.Free;
|
||||
end;
|
||||
{%endregion}
|
||||
|
||||
{ TSynEditMarkupFoldColors }
|
||||
|
||||
constructor TSynEditMarkupFoldColors.Create(ASynEdit: TSynEditBase);
|
||||
begin
|
||||
inherited Create(ASynEdit);
|
||||
MarkupInfo.Foreground := clGreen;
|
||||
MarkupInfo.Background := clNone; //clFuchsia;
|
||||
MarkupInfo.Style := [];
|
||||
MarkupInfo.StyleMask := [];
|
||||
MarkupInfo.FrameEdges:= sfeLeft;//sfeAround;//sfeBottom;//
|
||||
|
||||
SetLength(Colors, 5);
|
||||
Colors[0] := clRed;
|
||||
Colors[1] := $000098F7; //orange
|
||||
Colors[2] := $0022CC40; //green
|
||||
//Colors[3] := $00D5D500; // $0098CC42; // $00D1D54A; // teal
|
||||
Colors[3] := $00FF682A; //blue
|
||||
Colors[4] := $00CF00C4; //purple
|
||||
end;
|
||||
|
||||
function TSynEditMarkupFoldColors.GetMarkupAttributeAtRowCol(
|
||||
const aRow: Integer; const aStartCol: TLazSynDisplayTokenBound;
|
||||
const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor;
|
||||
var
|
||||
i,x2both : integer;
|
||||
begin
|
||||
Result := nil;
|
||||
if (CurrentY = aRow) then begin
|
||||
|
||||
x2both := -3; //flag
|
||||
for i := 0 to length(FHighlights)-1 do
|
||||
with FHighlights[i] do
|
||||
if not Ignore
|
||||
and (X < X2)
|
||||
and (ColorIdx >= 0)
|
||||
and (aStartCol.Logical >= x)
|
||||
and (aStartCol.Logical < X2) then
|
||||
begin
|
||||
//MarkupInfo.FrameColor:= clGreen; //debug
|
||||
if x2both = -3 then //first call flag
|
||||
begin
|
||||
MarkupInfo.FrameColor:= clNone;
|
||||
MarkupInfo.Foreground:= clNone;
|
||||
MarkupInfo.Background:= clNone;
|
||||
MarkupInfo.FrameEdges:= sfeNone;
|
||||
x2both := 0;
|
||||
end;
|
||||
|
||||
Result := MarkupInfo;
|
||||
x2both := max(x2both, x2);
|
||||
MarkupInfo.SetFrameBoundsLog(x, x2both);
|
||||
if Border then
|
||||
begin
|
||||
MarkupInfo.FrameColor:= Colors[ColorIdx];
|
||||
MarkupInfo.FrameEdges:= sfeLeft;//sfeAround;//
|
||||
end
|
||||
else
|
||||
MarkupInfo.Foreground := Colors[ColorIdx];
|
||||
|
||||
//MarkupInfo.FrameEdges:= sfeAround; //debug
|
||||
|
||||
{//2nd debug
|
||||
if x > x2 then
|
||||
begin
|
||||
MarkupInfo.Background:= clYellow;
|
||||
MarkupInfo.SetFrameBoundsLog(x-1, x2+20);
|
||||
MarkupInfo.FrameColor:= clBlue; //debug
|
||||
end;}
|
||||
|
||||
//break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupFoldColors.GetNextMarkupColAfterRowCol(
|
||||
const aRow: Integer; const aStartCol: TLazSynDisplayTokenBound;
|
||||
const AnRtlInfo: TLazSynDisplayRtlInfo; out ANextPhys, ANextLog: Integer);
|
||||
var i : integer;
|
||||
begin
|
||||
ANextLog := -1;
|
||||
ANextPhys := -1;
|
||||
if (CurrentY = aRow) then
|
||||
for i := 0 to length(FHighlights)-1 do
|
||||
with FHighlights[i] do
|
||||
begin
|
||||
//if Ignore or (ColorIdx < 0) or (X >= X2) or (aStartCol.Logical >= x) or (aStartCol.Logical > X2) then
|
||||
//continue;
|
||||
if not Ignore and (ColorIdx >= 0) and (X < X2) and (aStartCol.Logical < x) and (aStartCol.Logical <= X2) then
|
||||
begin
|
||||
ANextLog := FHighlights[i].X;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TSynEditMarkupFoldColors.DoMarkupParentFoldAtRow(aRow: Integer);
|
||||
var
|
||||
i,lvl,z : integer; //iterate parents fold
|
||||
|
||||
procedure AddVerticalLine( ANode: TSynFoldNodeInfo );
|
||||
var x,j : integer;
|
||||
begin
|
||||
|
||||
//don't replace; don't add when already found
|
||||
x := ANode.LogXStart + 1;
|
||||
for j := 0 to Pred(length(FHighlights)) do
|
||||
if FHighlights[j].X = x then
|
||||
;//exit; //
|
||||
|
||||
z := Length(FHighlights);
|
||||
SetLength(FHighlights, z+1);
|
||||
with FHighlights[z] do begin
|
||||
SrcNode:= ANode; //needed by close node
|
||||
Border := ANode.LineIndex + 1 <> aRow;
|
||||
X := ANode.LogXStart + 1;
|
||||
Y := aRow;//ANode.LineIndex + 1;
|
||||
X2 := X+1; //ANode.LogXEnd + 1;
|
||||
Ignore := False;
|
||||
|
||||
if Border and (sfaOutlineNoLine in ANode.FoldAction) then
|
||||
Ignore := True;
|
||||
if not Border and (sfaOutlineNoColor in ANode.FoldAction) then
|
||||
Ignore := True;
|
||||
//else
|
||||
ColorIdx := lvl mod (length(Colors))
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
y, lvlB,lvlA: Integer;
|
||||
Nest : TLazSynEditNestedFoldsList;
|
||||
TmpNode: TSynFoldNodeInfo;
|
||||
NestCount : integer;
|
||||
procedure Later(var J:integer);
|
||||
begin
|
||||
inc(J);
|
||||
end;
|
||||
function Allowed(J: integer):boolean;
|
||||
begin
|
||||
result := J < NestCount;
|
||||
end;
|
||||
|
||||
begin
|
||||
y := aRow-1;
|
||||
Nest := TLazSynEditNestedFoldsList.Create(@GetFoldHighLighter);
|
||||
Nest.ResetFilter;
|
||||
Nest.Line := y;
|
||||
Nest.FoldGroup := FDefaultGroup;//1;//FOLDGROUP_PASCAL;
|
||||
Nest.FoldFlags := [sfbIncludeDisabled]; //[];//
|
||||
Nest.IncludeOpeningOnLine := True; //False; //
|
||||
NestCount := Nest.Count;
|
||||
|
||||
try
|
||||
lvl := 0;
|
||||
i := 0;
|
||||
while Allowed(i) do
|
||||
begin
|
||||
|
||||
TmpNode := Nest.HLNode[i];
|
||||
//find till valid
|
||||
while (sfaInvalid in TmpNode.FoldAction ) and Allowed(i+1) do //(i < Nest.Count) do
|
||||
begin
|
||||
Later(i);
|
||||
TmpNode := Nest.HLNode[i];
|
||||
end;
|
||||
//if not (sfaInvalid in TmpNode.FoldAction) then}
|
||||
|
||||
if (sfaOutline in TmpNode.FoldAction ) then
|
||||
//avoid bug of IncludeOpeningOnLine := False;
|
||||
if (sfaOpen in TmpNode.FoldAction) and (TmpNode.LineIndex + 1 = aRow) then
|
||||
begin {do nothing here} end
|
||||
else
|
||||
begin
|
||||
lvlB := lvl;
|
||||
|
||||
if ( sfaOutlineForceIndent in TmpNode.FoldAction) then
|
||||
inc(lvl);
|
||||
if ( sfaOutlineMergeParent in TmpNode.FoldAction) then
|
||||
dec(lvl);
|
||||
|
||||
AddVerticalLine(TmpNode);
|
||||
if not( sfaOutlineKeepLevel in TmpNode.FoldAction) then
|
||||
inc(lvl);
|
||||
|
||||
lvlA := lvl;
|
||||
|
||||
with FHighlights[z] do begin
|
||||
LevelBefore := lvlB;
|
||||
LevelAfter := lvlA;
|
||||
end;
|
||||
end;
|
||||
|
||||
Later(i);
|
||||
//break; //debug
|
||||
end;
|
||||
|
||||
finally
|
||||
Nest.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupFoldColors.DoMarkupParentCloseFoldAtRow(aRow: Integer);
|
||||
var
|
||||
lvl,z : integer;
|
||||
|
||||
procedure AddHighlight( ANode: TSynFoldNodeInfo );
|
||||
var x,j : integer;
|
||||
begin
|
||||
//don't replace; don't add when already found
|
||||
x := ANode.LogXStart + 1;
|
||||
|
||||
if ANode.LogXStart < ANode.LogXEnd then
|
||||
for j := 0 to Pred(length(FHighlights)) do
|
||||
if (FHighlights[j].X = x)
|
||||
and (FHighlights[j].Border)
|
||||
and (FHighlights[j].SrcNode.FoldType = ANode.FoldType )
|
||||
and (FHighlights[j].SrcNode.FoldLvlEnd = ANode.FoldLvlStart )
|
||||
then begin
|
||||
FHighlights[j].X2 := ANode.LogXEnd+1 ;//exit; //
|
||||
FHighlights[j].Border := False
|
||||
|
||||
end;
|
||||
|
||||
//exit; //debug
|
||||
z := Length(FHighlights);
|
||||
SetLength(FHighlights, z+1);
|
||||
with FHighlights[z] do begin
|
||||
Border := False;
|
||||
SrcNode:= ANode; //needed by close node
|
||||
Y := ANode.LineIndex + 1;
|
||||
X := ANode.LogXStart + 1;
|
||||
X2 := ANode.LogXEnd + 1;
|
||||
//ColorIdx := lvl;
|
||||
if not (sfaOutlineNocolor in ANode.FoldAction) then
|
||||
ColorIdx := lvl mod (length(Colors))
|
||||
else
|
||||
ColorIdx := -1;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
y,i,j,lvlB,lvlA : integer;
|
||||
HL: TSynCustomFoldHighlighter;
|
||||
NodeList: TLazSynFoldNodeInfoList;
|
||||
TmpNode: TSynFoldNodeInfo;
|
||||
Found : boolean;
|
||||
begin
|
||||
y := aRow -1;
|
||||
|
||||
HL := TCustomSynEdit(self.SynEdit).Highlighter as TSynCustomFoldHighlighter;
|
||||
HL.CurrentLines := Lines;
|
||||
HL.FoldNodeInfo[y].ClearFilter; // only needed once, in case the line was already used
|
||||
|
||||
NodeList := HL.FoldNodeInfo[y];
|
||||
NodeList.AddReference;
|
||||
try
|
||||
NodeList.ActionFilter := [sfaOutline];
|
||||
//NodeList.FoldFlags:= [sfbIncludeDisabled];
|
||||
lvl := 0;
|
||||
J := Length(FHighlights)-1;
|
||||
if J >=0 then
|
||||
lvl := max(0,FHighlights[J].LevelAfter);
|
||||
i := 0;
|
||||
repeat
|
||||
TmpNode := NodeList[i];
|
||||
|
||||
//find till valid
|
||||
while (sfaInvalid in TmpNode.FoldAction) and (i + 1 < NodeList.Count) do
|
||||
begin
|
||||
inc(i);
|
||||
TmpNode := NodeList[i];
|
||||
end;
|
||||
if not (sfaInvalid in TmpNode.FoldAction) and (sfaOutline in TmpNode.FoldAction) then begin
|
||||
if sfaOpen in TmpNode.FoldAction then
|
||||
begin
|
||||
lvlB := lvl;
|
||||
|
||||
if ( sfaOutlineForceIndent in TmpNode.FoldAction) then
|
||||
inc(lvl);
|
||||
if ( sfaOutlineMergeParent in TmpNode.FoldAction) then
|
||||
dec(lvl);
|
||||
|
||||
AddHighlight(TmpNode);
|
||||
if not( sfaOutlineKeepLevel in TmpNode.FoldAction) then
|
||||
inc(lvl);
|
||||
lvlA := lvl;
|
||||
|
||||
with FHighlights[z] do begin
|
||||
LevelBefore := lvlB;
|
||||
LevelAfter := lvlA;
|
||||
end;
|
||||
|
||||
end
|
||||
else
|
||||
if sfaClose in TmpNode.FoldAction then
|
||||
begin
|
||||
Found := False;
|
||||
for j := Length(FHighlights)-1 downto 0 do begin
|
||||
with FHighlights[j].SrcNode do begin
|
||||
if (FoldType = TmpNode.FoldType) and
|
||||
(FoldGroup = TmpNode.FoldGroup) and
|
||||
(sfaOpen in FoldAction) and
|
||||
// (FoldLvlEnd = TmpNode.FoldLvlStart)
|
||||
(NestLvlEnd = TmpNode.NestLvlStart)
|
||||
|
||||
then begin
|
||||
lvl := FHighlights[j].ColorIdx;
|
||||
lvlB := FHighlights[j].LevelBefore;
|
||||
Found := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if Found then begin
|
||||
AddHighlight(TmpNode);
|
||||
lvl := lvlB;
|
||||
end;
|
||||
|
||||
//if not( sfaOutlineKeepLevel in TmpNode.FoldAction) then
|
||||
//inc(lvl);
|
||||
end;
|
||||
end;
|
||||
|
||||
inc(i);
|
||||
until i >= NodeList.Count;
|
||||
|
||||
finally
|
||||
NodeList.ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupFoldColors.PrepareMarkupForRow(aRow: Integer);
|
||||
begin
|
||||
CurrentY := aRow;
|
||||
SetLength(FHighlights,0); //reset needed to prevent using of invalid area
|
||||
|
||||
if not (TCustomSynEdit(self.SynEdit).Highlighter is TSynCustomFoldHighlighter) then
|
||||
exit;
|
||||
|
||||
//DoMarkupFoldAtRow(aRow);
|
||||
DoMarkupParentFoldAtRow(aRow);
|
||||
DoMarkupParentCloseFoldAtRow(aRow);
|
||||
//DoMarkupRangeFoldAtRow(aRow);
|
||||
|
||||
FHighlights := SortLeftMostFI(FHighlights);
|
||||
end;
|
||||
|
||||
function TSynEditMarkupFoldColors.GetFoldHighLighter: TSynCustomFoldHighlighter;
|
||||
begin
|
||||
result := TCustomSynEdit(self.SynEdit).Highlighter as TSynCustomFoldHighlighter;
|
||||
end;
|
||||
|
||||
{.$define debug_FC_line_changed}
|
||||
procedure TSynEditMarkupFoldColors.DoTextChanged(StartLine, EndLine,
|
||||
ACountDiff: Integer);
|
||||
{$ifdef debug_FC_line_changed}
|
||||
var F : TCustomForm;
|
||||
begin
|
||||
F := GetParentForm(self.SynEdit);
|
||||
if F <> nil then
|
||||
//F.Caption := Format('Start:%d Endline:%d Diff:%d',[StartLine, EndLIne, ACountDiff]);
|
||||
F.Caption := F.Caption + Caret.LineText
|
||||
{$else}
|
||||
|
||||
|
||||
|
||||
function GetPairCloseFold(aRow, X : integer ): Integer;
|
||||
var
|
||||
y,i,LCnt : integer;
|
||||
HL: TSynCustomFoldHighlighter;
|
||||
NodeList: TLazSynFoldNodeInfoList;
|
||||
TmpNode, CloseNode: TSynFoldNodeInfo;
|
||||
|
||||
function FindEndNode(StartNode: TSynFoldNodeInfo;
|
||||
{var} YIndex, NIndex: Integer): TSynFoldNodeInfo;
|
||||
function SearchLine(ALineIdx: Integer; var ANodeIdx: Integer): TSynFoldNodeInfo;
|
||||
begin
|
||||
NodeList.Line := ALineIdx;
|
||||
repeat
|
||||
inc(ANodeIdx);
|
||||
Result := NodeList[ANodeIdx];
|
||||
until (sfaInvalid in Result.FoldAction)
|
||||
or (Result.NestLvlEnd <= StartNode.NestLvlStart);
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := SearchLine(YIndex, NIndex);
|
||||
if not (sfaInvalid in Result.FoldAction) then
|
||||
exit;
|
||||
|
||||
inc(YIndex);
|
||||
while (YIndex < LCnt) and
|
||||
(HL.FoldBlockMinLevel(YIndex, StartNode.FoldGroup, [sfbIncludeDisabled])
|
||||
> StartNode.NestLvlStart)
|
||||
do
|
||||
inc(YIndex);
|
||||
if YIndex = LCnt then
|
||||
exit;
|
||||
|
||||
NIndex := -1;
|
||||
Result := SearchLine(YIndex, NIndex);
|
||||
|
||||
if (Result.LogXEnd = 0) or (sfaLastLineClose in Result.FoldAction) then
|
||||
Result.FoldAction := [sfaInvalid]; // LastLine closed Node(maybe force-closed?)
|
||||
end;
|
||||
|
||||
begin
|
||||
Result := -1;
|
||||
y := aRow -1;
|
||||
|
||||
HL := TCustomSynEdit(self.SynEdit).Highlighter as TSynCustomFoldHighlighter;
|
||||
HL.CurrentLines := Lines;
|
||||
LCnt := Lines.Count;
|
||||
HL.FoldNodeInfo[y].ClearFilter; // only needed once, in case the line was already used
|
||||
|
||||
NodeList := HL.FoldNodeInfo[y];
|
||||
NodeList.AddReference;
|
||||
try
|
||||
NodeList.ActionFilter := [sfaOpen];
|
||||
i := 0;
|
||||
repeat
|
||||
TmpNode := NodeList[i];
|
||||
|
||||
if TmpNode.LogXStart < X-1 then
|
||||
begin
|
||||
inc(i);
|
||||
continue;
|
||||
end;
|
||||
|
||||
//find till valid
|
||||
while (sfaInvalid in TmpNode.FoldAction) and (i < NodeList.Count) do
|
||||
begin
|
||||
inc(i);
|
||||
TmpNode := NodeList[i];
|
||||
end;
|
||||
if not (sfaInvalid in TmpNode.FoldAction) then
|
||||
begin
|
||||
CloseNode := FindEndNode(TmpNode, y, i);
|
||||
//AddHighlight(TmpNode);
|
||||
Result := CloseNode.LineIndex;
|
||||
exit;
|
||||
end;
|
||||
|
||||
inc(i);
|
||||
until i >= NodeList.Count;
|
||||
|
||||
finally
|
||||
NodeList.ReleaseReference;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function IsFoldMoved( aRow: Integer ): integer;
|
||||
var S : string;
|
||||
i,n : integer;
|
||||
begin
|
||||
Result := -1;
|
||||
n := -1;
|
||||
|
||||
S := Caret.LineText;
|
||||
for i := 1 to Min(Length(S), Length(FPrevCaretText)) do
|
||||
begin
|
||||
if S[i] <> FPrevCaretText[i] then
|
||||
begin
|
||||
n := i;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if n < 0 then exit;
|
||||
|
||||
Result := GetPairCloseFold(aRow, n);
|
||||
//limit to screen bottom
|
||||
if Result > 0 then
|
||||
begin
|
||||
inc(Result);//because sometime 'end' has trailing vertical line
|
||||
with TCustomSynEdit(SynEdit) do
|
||||
Result := min(Result, TopLine +LinesInWindow);// . .RowToScreenRow(i);
|
||||
end;
|
||||
|
||||
end;
|
||||
var
|
||||
EndFoldLine,y : integer;
|
||||
begin
|
||||
if EndLine < 0 then exit; //already refreshed by syn
|
||||
exit;//debug
|
||||
|
||||
y := Caret.LineBytePos.y;
|
||||
EndFoldLine := IsFoldMoved(y);
|
||||
if EndFoldLine > 0 then
|
||||
begin
|
||||
InvalidateSynLines(y+1, EndFoldLine);
|
||||
end;
|
||||
|
||||
FPrevCaretText := Caret.LineText;
|
||||
// I found that almost anything has been repaint by the SynEdit,
|
||||
// except the trailing space editing: we should repaint them here.
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupFoldColors.DoCaretChanged(Sender: TObject);
|
||||
var Y : integer;
|
||||
begin
|
||||
Y := Caret.LineBytePos.y;
|
||||
if Y = FCaretY then exit;
|
||||
|
||||
FCaretY := Y;
|
||||
FPrevCaretText := Caret.LineText;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
@ -150,6 +150,10 @@ const
|
||||
cfbtIfDef, cfbtRegion,
|
||||
cfbtIfThen
|
||||
];
|
||||
PascalNoOutlineRanges: TPascalCodeFoldBlockTypes =
|
||||
[cfbtProgram,cfbtUnit,cfbtUnitSection, cfbtRegion, cfbtProcedure,
|
||||
cfbtVarType,
|
||||
cfbtIfDef, cfbtAnsiComment..cfbtSlashComment];
|
||||
|
||||
// restrict cdecl etc to places where they can be.
|
||||
// this needs a better parser
|
||||
@ -4032,6 +4036,8 @@ begin
|
||||
else
|
||||
Result.SupportedModes := [fmFold] + m;
|
||||
end;
|
||||
if not (TPascalCodeFoldBlockType(Index) in PascalNoOutlineRanges) then
|
||||
Result.SupportedModes := Result.SupportedModes + [fmOutline];
|
||||
|
||||
if (TPascalCodeFoldBlockType(Index) in [cfbtIfThen]) then
|
||||
m := [];
|
||||
@ -4039,6 +4045,10 @@ begin
|
||||
Result.Modes := [fmFold, fmHide] + m
|
||||
else
|
||||
Result.Modes := [fmFold] + m;
|
||||
|
||||
if not (TPascalCodeFoldBlockType(Index) in PascalNoOutlineRanges) then
|
||||
Result.Modes := Result.Modes + [fmOutline];
|
||||
|
||||
end;
|
||||
|
||||
function TSynPasSyn.CreateRangeList(ALines: TSynEditStringsBase): TSynHighlighterRangeList;
|
||||
|
Loading…
Reference in New Issue
Block a user