mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-04 03:37:59 +01:00
SynEdit: Basic folding for XML
git-svn-id: trunk@22616 -
This commit is contained in:
parent
6cf3d0b52a
commit
21eb56256f
@ -209,6 +209,7 @@ type
|
||||
fUpdateCount: integer; //mh 2001-09-13
|
||||
fEnabled: Boolean;
|
||||
fWordBreakChars: TSynIdentChars;
|
||||
FIsScanning: Boolean;
|
||||
procedure SetCurrentLines(const AValue: TSynEditStrings);
|
||||
procedure SetDrawDividerLevel(const AValue: Integer);
|
||||
procedure SetEnabled(const Value: boolean); //DDH 2001-10-23
|
||||
@ -239,6 +240,7 @@ type
|
||||
function GetDrawDivider(Index: integer): TSynDividerDrawConfigSetting; virtual;
|
||||
function GetDividerDrawConfig(Index: Integer): TSynDividerDrawConfig; virtual;
|
||||
function GetDividerDrawConfigCount: Integer; virtual;
|
||||
property IsScanning: Boolean read FIsScanning;
|
||||
public
|
||||
procedure DefHighlightChange(Sender: TObject);
|
||||
property AttributeChangeNeedScan: Boolean read FAttributeChangeNeedScan;
|
||||
@ -324,7 +326,7 @@ type
|
||||
property DividerDrawConfigCount: Integer read GetDividerDrawConfigCount;
|
||||
published
|
||||
property DefaultFilter: string read GetDefaultFilter write SetDefaultFilter
|
||||
stored IsFilterStored;
|
||||
stored IsFilterStored; deprecated;
|
||||
property Enabled: boolean read fEnabled write SetEnabled default TRUE; //DDH 2001-10-23
|
||||
end;
|
||||
|
||||
@ -945,7 +947,7 @@ begin
|
||||
if Src is ClassType then
|
||||
SampleSource := Src.SampleSource;
|
||||
fWordBreakChars := Src.WordBreakChars;
|
||||
DefaultFilter := Src.DefaultFilter;
|
||||
//DefaultFilter := Src.DefaultFilter;
|
||||
Enabled := Src.Enabled;
|
||||
end else
|
||||
inherited Assign(Source);
|
||||
@ -1221,18 +1223,23 @@ function TSynCustomHighlighter.ScanFrom(Index: integer; AtLeastTilIndex: integer
|
||||
var
|
||||
c: LongInt;
|
||||
begin
|
||||
Result := Index;
|
||||
c := CurrentLines.Count;
|
||||
StartAtLineIndex(Result);
|
||||
NextToEol;
|
||||
while UpdateRangeInfoAtLine(Result) or
|
||||
(Result <= AtLeastTilIndex+1)
|
||||
do begin
|
||||
inc(Result);
|
||||
if Result = c then
|
||||
break;
|
||||
ContinueNextLine;
|
||||
FIsScanning := True;
|
||||
try
|
||||
Result := Index;
|
||||
c := CurrentLines.Count;
|
||||
StartAtLineIndex(Result);
|
||||
NextToEol;
|
||||
while UpdateRangeInfoAtLine(Result) or
|
||||
(Result <= AtLeastTilIndex+1)
|
||||
do begin
|
||||
inc(Result);
|
||||
if Result = c then
|
||||
break;
|
||||
ContinueNextLine;
|
||||
NextToEol;
|
||||
end;
|
||||
finally
|
||||
FIsScanning := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -599,6 +599,7 @@ end;
|
||||
|
||||
procedure TSynLFMSyn.ResetRange;
|
||||
begin
|
||||
inherited;
|
||||
fRange := rsUnknown;
|
||||
end;
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ interface
|
||||
{$I SynEdit.inc}
|
||||
|
||||
uses
|
||||
SysUtils, Classes,
|
||||
SysUtils, Classes, math, LCLProc,
|
||||
{$IFDEF SYN_CLX}
|
||||
Qt, QControls, QGraphics,
|
||||
{$ELSE}
|
||||
@ -67,7 +67,7 @@ uses
|
||||
{$ENDIF}
|
||||
Controls, Graphics,
|
||||
{$ENDIF}
|
||||
SynEditTypes, SynEditHighlighter;
|
||||
SynEditTypes, SynEditTextBuffer, SynEditHighlighter, SynEditHighlighterFoldBase;
|
||||
|
||||
type
|
||||
TtkTokenKind = (tkAposAttrValue, tkAposEntityRef, tkAttribute, tkCDATA,
|
||||
@ -84,7 +84,7 @@ type
|
||||
);
|
||||
|
||||
TRangeState = (rsAposAttrValue, rsAPosEntityRef, rsAttribute, rsCDATA,
|
||||
rsComment, rsElement, rsEntityRef, rsEqual, rsProcessingInstruction,
|
||||
rsComment, rsElement, rsCloseElement, rsOpenElement, rsEntityRef, rsEqual, rsProcessingInstruction,
|
||||
rsQuoteAttrValue, rsQuoteEntityRef, rsText,
|
||||
//
|
||||
rsnsAposAttrValue, rsnsAPosEntityRef, rsnsEqual, rsnsQuoteAttrValue,
|
||||
@ -96,11 +96,46 @@ type
|
||||
rsDocTypeQuoteEntityRef}
|
||||
);
|
||||
|
||||
TXmlCodeFoldBlockType = (
|
||||
cfbtXmlNone,
|
||||
cfbtXmlElement, // <foo>
|
||||
cfbtXmlComment, // <!-- -->
|
||||
cfbtXmlCData, // <![CDATA[ ]]>
|
||||
cfbtXmlDocType, // <!DOCTYPE
|
||||
cfbtXmlProcess // <?
|
||||
);
|
||||
|
||||
TSynXmlRangeInfo = record
|
||||
ElementOpenList: Array of String; // List of words opened in this line (and still open at the end of line)
|
||||
ElementCloseList: Array of Smallint; // include close, for open on same line
|
||||
end;
|
||||
|
||||
{ TSynHighlighterXmlRangeList }
|
||||
|
||||
TSynHighlighterXmlRangeList = class(TSynHighlighterRangeList)
|
||||
private
|
||||
function GetXmlRangeInfo(Index: Integer): TSynXmlRangeInfo;
|
||||
procedure SetXmlRangeInfo(Index: Integer; const AValue: TSynXmlRangeInfo);
|
||||
protected
|
||||
procedure SetCapacity(const AValue: Integer); override;
|
||||
function ItemSize: Integer; override;
|
||||
public
|
||||
procedure Move(AFrom, ATo, ALen: Integer); override;
|
||||
property XmlRangeInfo[Index: Integer]: TSynXmlRangeInfo
|
||||
read GetXmlRangeInfo write SetXmlRangeInfo;
|
||||
end;
|
||||
|
||||
TProcTableProc = procedure of object;
|
||||
|
||||
TSynXMLSyn = class(TSynCustomHighlighter)
|
||||
{ TSynXMLSyn }
|
||||
|
||||
TSynXMLSyn = class(TSynCustomFoldHighlighter)
|
||||
private
|
||||
fRange: TRangeState;
|
||||
FXmlRangeInfo: TSynXmlRangeInfo;
|
||||
FXmlRangeInfoChanged: Boolean;
|
||||
FXmlRangeInfoOpenPos: integer;
|
||||
FXmlRangeInfoClosePos: integer;
|
||||
fLine: PChar;
|
||||
Run: Longint;
|
||||
fTokenPos: Integer;
|
||||
@ -144,8 +179,20 @@ type
|
||||
procedure QEntityRefProc;
|
||||
procedure AEntityRefProc;
|
||||
protected
|
||||
function UpdateRangeInfoAtLine(Index: Integer): Boolean; override; // Returns true if range changed
|
||||
function GetIdentChars: TSynIdentChars; override;
|
||||
function GetSampleSource : String; override;
|
||||
protected
|
||||
// folding
|
||||
procedure CreateRootCodeFoldBlock; override;
|
||||
function CreateRangeList: TSynHighlighterRangeList; override;
|
||||
|
||||
function StartXmlCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType): TSynCustomCodeFoldBlock;
|
||||
function StartXmlElemCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType;
|
||||
OpenPos: Integer; AName: String): TSynCustomCodeFoldBlock;
|
||||
procedure EndXmlCodeFoldBlock;
|
||||
procedure EndXmlElemCodeFoldBlock(ClosePos: Integer = -1; AName: String = '');
|
||||
function TopXmlCodeFoldBlockType(DownIndex: Integer = 0): TXmlCodeFoldBlockType;
|
||||
public
|
||||
{$IFNDEF SYN_CPPB_1} class {$ENDIF}
|
||||
function GetLanguageName: string; override;
|
||||
@ -168,6 +215,15 @@ 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;
|
||||
function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; override;
|
||||
// TODO: make private
|
||||
function MinimumFoldLevel(ALineIndex: Integer): integer; override;
|
||||
function EndFoldLevel(ALineIndex: Integer): integer; override;
|
||||
published
|
||||
property ElementAttri: TSynHighlighterAttributes read fElementAttri
|
||||
write fElementAttri;
|
||||
@ -206,6 +262,7 @@ uses
|
||||
|
||||
const
|
||||
NameChars : set of char = ['0'..'9', 'a'..'z', 'A'..'Z', '_', '.', ':', '-'];
|
||||
MaxFoldNestDeep = 500;
|
||||
|
||||
constructor TSynXMLSyn.Create(AOwner: TComponent);
|
||||
begin
|
||||
@ -322,6 +379,12 @@ end;
|
||||
procedure TSynXMLSyn.SetLine({$IFDEF FPC}const {$ENDIF}NewValue: string;
|
||||
LineNumber:Integer);
|
||||
begin
|
||||
inherited;
|
||||
FXmlRangeInfo := TSynHighlighterXmlRangeList(CurrentRanges).XmlRangeInfo[LineIndex]; // From this line, not from the previous line
|
||||
FXmlRangeInfoChanged := False;
|
||||
FXmlRangeInfoOpenPos := 0;
|
||||
FXmlRangeInfoClosePos := 0;
|
||||
|
||||
fLine := PChar(NewValue);
|
||||
Run := 0;
|
||||
fLineNumber := LineNumber;
|
||||
@ -359,22 +422,29 @@ end;
|
||||
procedure TSynXMLSyn.LessThanProc;
|
||||
begin
|
||||
Inc(Run);
|
||||
if (fLine[Run] = '/') then
|
||||
if (fLine[Run] = '/') then begin
|
||||
Inc(Run);
|
||||
fTokenID := tkSymbol;
|
||||
fRange := rsCloseElement;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (fLine[Run] = '!') then
|
||||
begin
|
||||
if NextTokenIs('--') then begin
|
||||
fTokenID := tkSymbol;
|
||||
fRange := rsComment;
|
||||
StartXmlCodeFoldBlock(cfbtXmlComment);
|
||||
Inc(Run, 3);
|
||||
end else if NextTokenIs('DOCTYPE') then begin
|
||||
fTokenID := tkDocType;
|
||||
fRange := rsDocType;
|
||||
StartXmlCodeFoldBlock(cfbtXmlDocType);
|
||||
Inc(Run, 7);
|
||||
end else if NextTokenIs('[CDATA[') then begin
|
||||
fTokenID := tkCDATA;
|
||||
fRange := rsCDATA;
|
||||
StartXmlCodeFoldBlock(cfbtXmlCData);
|
||||
Inc(Run, 7);
|
||||
end else begin
|
||||
fTokenID := tkSymbol;
|
||||
@ -384,15 +454,20 @@ begin
|
||||
end else if fLine[Run]= '?' then begin
|
||||
fTokenID := tkProcessingInstruction;
|
||||
fRange := rsProcessingInstruction;
|
||||
StartXmlCodeFoldBlock(cfbtXmlProcess);
|
||||
Inc(Run);
|
||||
end else begin
|
||||
fTokenID := tkSymbol;
|
||||
fRange := rsElement;
|
||||
fRange := rsOpenElement;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.GreaterThanProc;
|
||||
begin
|
||||
if (Run > 0) and (fLine[Run - 1] = '/') then
|
||||
if TopXmlCodeFoldBlockType = cfbtXmlElement then
|
||||
EndXmlElemCodeFoldBlock;
|
||||
|
||||
fTokenId := tkSymbol;
|
||||
fRange:= rsText;
|
||||
Inc(Run);
|
||||
@ -400,11 +475,14 @@ end;
|
||||
|
||||
procedure TSynXMLSyn.CommentProc;
|
||||
begin
|
||||
if (fLine[Run] = '-') and (fLine[Run + 1] = '-') and (fLine[Run + 2] = '>')
|
||||
if (fLine[Run] = '-') and (fLine[Run + 1] = '-') and
|
||||
(fLine[Run + 2] = '>')
|
||||
then begin
|
||||
fTokenID := tkSymbol;
|
||||
fRange:= rsText;
|
||||
Inc(Run, 3);
|
||||
if TopXmlCodeFoldBlockType = cfbtXmlComment then
|
||||
EndXmlCodeFoldBlock;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
@ -438,6 +516,8 @@ begin
|
||||
then begin
|
||||
fRange := rsText;
|
||||
Inc(Run);
|
||||
if TopXmlCodeFoldBlockType = cfbtXmlProcess then
|
||||
EndXmlCodeFoldBlock;
|
||||
break;
|
||||
end;
|
||||
Inc(Run);
|
||||
@ -479,6 +559,8 @@ begin
|
||||
end;
|
||||
'>': begin
|
||||
fRange := rsAttribute;
|
||||
if TopXmlCodeFoldBlockType = cfbtXmlDocType then
|
||||
EndXmlCodeFoldBlock;
|
||||
Inc(Run);
|
||||
Break;
|
||||
end;
|
||||
@ -513,10 +595,13 @@ begin
|
||||
|
||||
while not (fLine[Run] in [#0, #10, #13]) do
|
||||
begin
|
||||
if (fLine[Run] = '>') and (fLine[Run - 1] = ']')
|
||||
if (Run >= 2) and (fLine[Run] = '>') and (fLine[Run - 1] = ']') and
|
||||
(fLine[Run - 2] = ']')
|
||||
then begin
|
||||
fRange := rsText;
|
||||
Inc(Run);
|
||||
if TopXmlCodeFoldBlockType = cfbtXmlCData then
|
||||
EndXmlCodeFoldBlock;
|
||||
break;
|
||||
end;
|
||||
Inc(Run);
|
||||
@ -524,9 +609,20 @@ begin
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.ElementProc;
|
||||
var
|
||||
NameStart: LongInt;
|
||||
begin
|
||||
if fLine[Run] = '/' then Inc(Run);
|
||||
if fLine[Run] = '/' then
|
||||
Inc(Run);
|
||||
NameStart := Run;
|
||||
while (fLine[Run] in NameChars) do Inc(Run);
|
||||
|
||||
if fRange = rsOpenElement then
|
||||
StartXmlElemCodeFoldBlock(cfbtXmlElement, NameStart, Copy(fLine, NameStart + 1, Run - NameStart));
|
||||
|
||||
if fRange = rsCloseElement then
|
||||
EndXmlElemCodeFoldBlock(NameStart, Copy(fLine, NameStart + 1, Run - NameStart)); // TODO: defer until ">" reached
|
||||
|
||||
fRange := rsAttribute;
|
||||
fTokenID := tkElement;
|
||||
end;
|
||||
@ -695,10 +791,28 @@ begin
|
||||
fRange := rsAPosAttrValue;
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.UpdateRangeInfoAtLine(Index: Integer): Boolean;
|
||||
var
|
||||
InfoOpenLenChanged, InfoCloseLenChanged: Boolean;
|
||||
begin
|
||||
Result := inherited UpdateRangeInfoAtLine(Index);
|
||||
InfoOpenLenChanged := Length(FXmlRangeInfo.ElementOpenList) <> FXmlRangeInfoOpenPos;
|
||||
InfoCloseLenChanged := Length(FXmlRangeInfo.ElementCloseList) <> FXmlRangeInfoClosePos;
|
||||
if FXmlRangeInfoChanged or InfoOpenLenChanged or InfoCloseLenChanged then begin
|
||||
Result := True;
|
||||
if InfoOpenLenChanged then
|
||||
SetLength(FXmlRangeInfo.ElementOpenList, FXmlRangeInfoOpenPos);
|
||||
if InfoCloseLenChanged then
|
||||
SetLength(FXmlRangeInfo.ElementCloseList, FXmlRangeInfoClosePos);
|
||||
TSynHighlighterXmlRangeList(CurrentRanges).XmlRangeInfo[LineIndex] := FXmlRangeInfo; // Store on this line
|
||||
FXmlRangeInfoChanged := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.IdentProc;
|
||||
begin
|
||||
case fRange of
|
||||
rsElement:
|
||||
rsElement, rsOpenElement, rsCloseElement:
|
||||
begin
|
||||
ElementProc{$IFDEF FPC}(){$ENDIF};
|
||||
end;
|
||||
@ -859,19 +973,83 @@ end;
|
||||
|
||||
function TSynXMLSyn.GetRange: Pointer;
|
||||
begin
|
||||
Result := Pointer(PtrInt(fRange));
|
||||
CodeFoldRange.RangeType:=Pointer(PtrUInt(Integer(fRange)));
|
||||
Result := inherited;
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.SetRange(Value: Pointer);
|
||||
begin
|
||||
fRange := TRangeState(PtrUInt(Value));
|
||||
inherited;
|
||||
fRange := TRangeState(Integer(PtrUInt(CodeFoldRange.RangeType)));
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.ReSetRange;
|
||||
begin
|
||||
inherited;
|
||||
fRange:= rsText;
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.FoldOpenCount(ALineIndex: Integer; AType: Integer): integer;
|
||||
begin
|
||||
Result := EndFoldLevel(ALineIndex) - MinimumFoldLevel(ALineIndex);
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.FoldCloseCount(ALineIndex: Integer; AType: Integer): integer;
|
||||
begin
|
||||
Result := EndFoldLevel(ALineIndex - 1) - MinimumFoldLevel(ALineIndex);
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.FoldNestCount(ALineIndex: Integer; AType: Integer): integer;
|
||||
begin
|
||||
Result := EndFoldLevel(ALineIndex);
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.FoldLineLength(ALineIndex, FoldIndex: Integer): integer;
|
||||
var
|
||||
i, lvl, cnt: Integer;
|
||||
e, m: Integer;
|
||||
begin
|
||||
//atype := FoldTypeAtNodeIndex(ALineIndex, FoldIndex);
|
||||
cnt := CurrentLines.Count;
|
||||
e := EndFoldLevel(ALineIndex);
|
||||
m := MinimumFoldLevel(ALineIndex);
|
||||
lvl := Min(m+1+FoldIndex, e);
|
||||
i := ALineIndex + 1;
|
||||
while (i < cnt) and (MinimumFoldLevel(i) >= lvl) do inc(i);
|
||||
// check if fold last line of block (not mixed "end begin")
|
||||
// and not lastlinefix
|
||||
if (i = cnt) or (EndFoldLevel(i) > MinimumFoldLevel(i)) then
|
||||
dec(i);
|
||||
// Amount of lines, that will become invisible (excludes the cfCollapsed line)
|
||||
Result := i - ALineIndex;
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.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 TSynXMLSyn.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 TSynXMLSyn.GetIdentChars: TSynIdentChars;
|
||||
begin
|
||||
Result := ['0'..'9', 'a'..'z', 'A'..'Z', '_', '.', '-'] + TSynSpecialChars;
|
||||
@ -894,6 +1072,181 @@ begin
|
||||
'</root>';
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.CreateRootCodeFoldBlock;
|
||||
begin
|
||||
inherited CreateRootCodeFoldBlock;
|
||||
RootCodeFoldBlock.InitRootBlockType(Pointer(PtrInt(cfbtXmlNone)));
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.CreateRangeList: TSynHighlighterRangeList;
|
||||
begin
|
||||
Result := TSynHighlighterXmlRangeList.Create;
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.StartXmlCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType): TSynCustomCodeFoldBlock;
|
||||
begin
|
||||
if CodeFoldRange.CodeFoldStackSize >= MaxFoldNestDeep then exit;
|
||||
StartCodeFoldBlock(Pointer(PtrInt(ABlockType)));
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.StartXmlElemCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType;
|
||||
OpenPos: Integer; AName: String): TSynCustomCodeFoldBlock;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
If IsScanning then begin
|
||||
AName := LowerCase(AName);
|
||||
i := Length(FXmlRangeInfo.ElementOpenList);
|
||||
if (FXmlRangeInfoOpenPos < i) then begin
|
||||
if (FXmlRangeInfo.ElementOpenList[FXmlRangeInfoOpenPos] <> AName) then begin
|
||||
FXmlRangeInfo.ElementOpenList[FXmlRangeInfoOpenPos] := AName;
|
||||
FXmlRangeInfoChanged := true; // TODO:if this node closes on the same line, it may not be amodified ....
|
||||
end;
|
||||
end else begin // append - modified will be deteced by the new length
|
||||
SetLength(FXmlRangeInfo.ElementOpenList, FXmlRangeInfoOpenPos + 10);
|
||||
FXmlRangeInfo.ElementOpenList[FXmlRangeInfoOpenPos] := AName;
|
||||
end;
|
||||
end;
|
||||
inc(FXmlRangeInfoOpenPos);
|
||||
StartXmlCodeFoldBlock(ABlockType);
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.EndXmlCodeFoldBlock;
|
||||
begin
|
||||
EndCodeFoldBlock();
|
||||
end;
|
||||
|
||||
procedure TSynXMLSyn.EndXmlElemCodeFoldBlock(ClosePos: Integer = -1; AName: String = '');
|
||||
var
|
||||
cnt, i, k, lvl: Integer;
|
||||
LInfo: Array of String;
|
||||
begin
|
||||
if not (TopXmlCodeFoldBlockType = cfbtXmlElement) then debugln('---- XXXXX TSynXMLSyn.EndXmlElemCodeFoldBlock XXXXX');
|
||||
AName := LowerCase(AName);
|
||||
|
||||
cnt := 0;
|
||||
If IsScanning then begin
|
||||
if (AName = '') and (CodeFoldRange.CodeFoldStackSize > 0) then begin
|
||||
cnt := 1;
|
||||
end
|
||||
else begin
|
||||
cnt := 1;
|
||||
i := FXmlRangeInfoOpenPos;
|
||||
while i > 0 do begin
|
||||
if TopXmlCodeFoldBlockType(FXmlRangeInfoOpenPos - i) <> cfbtXmlElement then debugln('---- XXXXX TSynXMLSyn.EndXmlElemCodeFoldBlock XXXXX');
|
||||
if (FXmlRangeInfo.ElementOpenList[i-1] = AName) then
|
||||
break;
|
||||
dec(i);
|
||||
inc(cnt);
|
||||
end;
|
||||
|
||||
if i = 0 then begin
|
||||
i := LineIndex - 1;
|
||||
lvl := EndFoldLevel(i);
|
||||
while i >= 0 do begin
|
||||
if MinimumFoldLevel(i) < lvl then begin
|
||||
LInfo := TSynHighlighterXmlRangeList(CurrentRanges).XmlRangeInfo[i].ElementOpenList;
|
||||
k := length(LInfo) - Max(EndFoldLevel(i) - lvl, 0) - 1;
|
||||
while (k >= 0) do begin
|
||||
if (LInfo[k] = AName) then
|
||||
break;
|
||||
inc(cnt);
|
||||
dec(k);
|
||||
dec(lvl);
|
||||
end;
|
||||
if k >= 0 then break;
|
||||
end;
|
||||
dec(i);
|
||||
end;
|
||||
|
||||
if (i < 0) or (cnt > CodeFoldRange.CodeFoldStackSize ) then cnt := 0; // never opened, do not close
|
||||
end;
|
||||
end;
|
||||
|
||||
i := Length(FXmlRangeInfo.ElementCloseList);
|
||||
if (FXmlRangeInfoClosePos < i) then begin
|
||||
if (FXmlRangeInfo.ElementCloseList[FXmlRangeInfoClosePos] <> cnt) then begin
|
||||
FXmlRangeInfo.ElementCloseList[FXmlRangeInfoClosePos] := cnt;
|
||||
FXmlRangeInfoChanged := true;
|
||||
end;
|
||||
end else begin // append - modified will be deteced by the new length
|
||||
SetLength(FXmlRangeInfo.ElementCloseList, FXmlRangeInfoClosePos + 10);
|
||||
FXmlRangeInfo.ElementCloseList[FXmlRangeInfoClosePos] := cnt;
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
if FXmlRangeInfoClosePos < length(FXmlRangeInfo.ElementCloseList) then
|
||||
cnt := FXmlRangeInfo.ElementCloseList[FXmlRangeInfoClosePos]
|
||||
else
|
||||
cnt := 0;
|
||||
end;
|
||||
inc(FXmlRangeInfoClosePos);
|
||||
|
||||
for i := 1 to cnt do begin
|
||||
if FXmlRangeInfoOpenPos > 0 then
|
||||
dec(FXmlRangeInfoOpenPos);
|
||||
EndXmlCodeFoldBlock;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynXMLSyn.TopXmlCodeFoldBlockType(DownIndex: Integer): TXmlCodeFoldBlockType;
|
||||
begin
|
||||
Result := TXmlCodeFoldBlockType(PtrUInt(TopCodeFoldBlockType(DownIndex)));
|
||||
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] + inherited ItemSize)^);
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterXmlRangeList.SetXmlRangeInfo(Index: Integer;
|
||||
const AValue: TSynXmlRangeInfo);
|
||||
begin
|
||||
TSynXmlRangeInfo((ItemPointer[Index] + inherited ItemSize)^) := AValue;
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterXmlRangeList.SetCapacity(const AValue: Integer);
|
||||
var
|
||||
i: LongInt;
|
||||
begin
|
||||
for i := AValue to Capacity-1 do
|
||||
with TSynXmlRangeInfo((ItemPointer[i] + inherited ItemSize)^) do begin
|
||||
ElementOpenList := nil;
|
||||
ElementCloseList := nil;
|
||||
end;
|
||||
inherited SetCapacity(AValue);
|
||||
end;
|
||||
|
||||
function TSynHighlighterXmlRangeList.ItemSize: Integer;
|
||||
begin
|
||||
Result := inherited ItemSize + 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] + inherited ItemSize)^) do begin
|
||||
ElementOpenList := nil;
|
||||
ElementCloseList := nil;
|
||||
end
|
||||
else
|
||||
for i:= ATo to Min(ATo + ALen , AFrom) - 1 do // move backward
|
||||
with TSynXmlRangeInfo((ItemPointer[i] + inherited ItemSize)^) do begin
|
||||
ElementOpenList := nil;
|
||||
ElementCloseList := nil;
|
||||
end;
|
||||
inherited Move(AFrom, ATo, ALen);
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
{$IFNDEF SYN_CPPB_1}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user