mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-17 22:09:28 +02:00
SynEdit TSynMultiSyn: Fixed crash when deleting lines. Part of issue #0022519
git-svn-id: trunk@38150 -
This commit is contained in:
parent
7a161299ec
commit
242370b71e
@ -1557,7 +1557,9 @@ begin
|
||||
if AValue = FCurrentLines then
|
||||
exit;
|
||||
FCurrentLines := AValue;
|
||||
FCurrentRanges := TSynHighlighterRangeList(AValue.Ranges[GetRangeIdentifier]);
|
||||
if FCurrentLines <> nil
|
||||
then FCurrentRanges := TSynHighlighterRangeList(AValue.Ranges[GetRangeIdentifier])
|
||||
else FCurrentRanges := nil;
|
||||
end;
|
||||
|
||||
procedure TSynCustomHighlighter.AttachToLines(Lines: TSynEditStringsBase);
|
||||
@ -1581,6 +1583,8 @@ procedure TSynCustomHighlighter.DetachFromLines(Lines: TSynEditStringsBase);
|
||||
var
|
||||
r: TSynHighlighterRangeList;
|
||||
begin
|
||||
//if Lines = CurrentLines then
|
||||
// CurrentLines := nil;
|
||||
r := TSynHighlighterRangeList(Lines.Ranges[GetRangeIdentifier]);
|
||||
if not assigned(r) then exit;
|
||||
r.DecRefCount;
|
||||
|
@ -614,18 +614,18 @@ begin
|
||||
do
|
||||
FSectionList.Delete(FRegionScanRangeIndex);
|
||||
VDiff := 0;
|
||||
DebugLn(['***** ', FRegionScanStartRangeIndex, ' cnt ', Count]);
|
||||
//DebugLn(['***** ', FRegionScanStartRangeIndex, ' cnt ', Count]);
|
||||
if FRegionScanStartRangeIndex < Count then begin
|
||||
// fix virtual lines on sections
|
||||
if (FRegionScanStartRangeIndex > 0) then begin
|
||||
s := FSectionList.Sections[FRegionScanStartRangeIndex-1];
|
||||
NewVLine := s.VirtualLine + s.EndPos.y - s.StartPos.y;
|
||||
DebugLn(['A ', NewVLine]);
|
||||
//DebugLn(['A ', NewVLine]);
|
||||
LastEnd := s.EndPos.y;
|
||||
end
|
||||
else begin
|
||||
NewVLine := 0;
|
||||
DebugLn(['B ', NewVLine]);
|
||||
//DebugLn(['B ', NewVLine]);
|
||||
LastEnd := FSectionList.Sections[FRegionScanStartRangeIndex].StartPos.y;
|
||||
end;
|
||||
LastVline := NewVLine;
|
||||
@ -734,49 +734,74 @@ end;
|
||||
procedure TSynHLightMultiVirtualLines.RealLinesDeleted(AIndex, ACount: Integer);
|
||||
var
|
||||
i: Integer;
|
||||
PartCnt, VLineDiff: Integer;
|
||||
CountInSection, PrevEndVLine, FirstVLine, VLineCount: Integer;
|
||||
p: PSynHLightMultiVirtualSection;
|
||||
|
||||
procedure DelVLines;
|
||||
begin
|
||||
if VLineCount > 0 then begin
|
||||
FRangeList.ChildDeleteRows(FirstVLine, VLineCount);
|
||||
FRangeList.CallDeletedLines(FirstVLine, VLineCount);
|
||||
end;
|
||||
end;
|
||||
begin
|
||||
i := FSectionList.IndexOfFirstSectionAtLineIdx(AIndex, -1, True);
|
||||
if i = FSectionList.Count then exit;
|
||||
|
||||
VLineDiff := 0;
|
||||
p := FSectionList.PSections[i];
|
||||
VLineCount := 0; // Count of deleted virtual lines
|
||||
FirstVLine := p^.VirtualLine; // First deleted virtual line
|
||||
PrevEndVLine := -1; // Keep track of overlap, when next section starts on the same V-line as previous sectian ends
|
||||
if AIndex > p^.StartPos.y then begin
|
||||
PartCnt := p^.EndPos.y - AIndex + 1;
|
||||
FRangeList.ChildDeleteRows(p^.VirtualLine + AIndex - p^.StartPos.y, PartCnt);
|
||||
FRangeList.CallDeletedLines(p^.VirtualLine + AIndex - p^.StartPos.y, PartCnt);
|
||||
p^.EndPos.y := p^.EndPos.y - PartCnt;
|
||||
// Real-lines starting in the middle of the Section
|
||||
CountInSection := Min(AIndex + ACount, p^.EndPos.y + 1) - AIndex;
|
||||
FirstVLine := p^.VirtualLine + AIndex - p^.StartPos.y;
|
||||
PrevEndVLine := p^.VirtualLine + p^.EndPos.y - p^.EndPos.y;
|
||||
p^.EndPos.y := p^.EndPos.y - CountInSection;
|
||||
inc(i);
|
||||
if i = FSectionList.Count then begin
|
||||
DelVLines;
|
||||
exit;
|
||||
end;
|
||||
p := FSectionList.PSections[i];
|
||||
VLineDiff := PartCnt;
|
||||
VLineCount := CountInSection;
|
||||
end;
|
||||
while p^.EndPos.y < AIndex + ACount do begin
|
||||
VLineDiff := VLineDiff + p^.EndPos.y - p^.StartPos.y + 1;
|
||||
FRangeList.ChildDeleteRows(p^.VirtualLine, p^.EndPos.y - p^.StartPos.y + 1);
|
||||
FRangeList.CallDeletedLines(p^.VirtualLine, p^.EndPos.y - p^.StartPos.y + 1);
|
||||
// Completly delete node (All Real lines deleted)
|
||||
VLineCount := VLineCount + p^.EndPos.y - p^.StartPos.y + 1;
|
||||
if PrevEndVLine = p^.VirtualLine then
|
||||
dec(VLineCount);
|
||||
PrevEndVLine := p^.VirtualLine + p^.EndPos.y - p^.EndPos.y;
|
||||
FSectionList.Delete(i);
|
||||
if i = FSectionList.Count then
|
||||
if i = FSectionList.Count then begin
|
||||
DelVLines;
|
||||
exit;
|
||||
end;
|
||||
p := FSectionList.PSections[i];
|
||||
end;
|
||||
if AIndex + ACount > p^.StartPos.y then begin
|
||||
PartCnt := ACount - (p^.StartPos.y - AIndex);
|
||||
FRangeList.ChildDeleteRows(p^.VirtualLine, PartCnt);
|
||||
FRangeList.CallDeletedLines(p^.VirtualLine, PartCnt);
|
||||
p^.EndPos.y := p^.EndPos.y - PartCnt;
|
||||
p^.VirtualLine := p^.VirtualLine - VLineDiff;
|
||||
VLineDiff := VLineDiff + PartCnt;
|
||||
// Some real-lines at the start of section are deleted
|
||||
p^.VirtualLine := p^.VirtualLine - VLineCount;
|
||||
CountInSection := ACount - (p^.StartPos.y - AIndex);
|
||||
VLineCount := VLineCount + CountInSection;
|
||||
if PrevEndVLine = p^.VirtualLine then
|
||||
dec(VLineCount);
|
||||
p^.StartPos.y := p^.StartPos.y - (ACount - CountInSection);
|
||||
p^.EndPos.y := p^.EndPos.y - ACount;
|
||||
assert(p^.EndPos.y >= p^.StartPos.y, 'TSynHLightMultiVirtualLines.RealLinesDeleted: p^.EndPos.y >= p^.StartPos.y');
|
||||
inc(i);
|
||||
end;
|
||||
|
||||
// Adjust StartPos for all sections, after the deleted.
|
||||
while i < FSectionList.Count do begin
|
||||
p := FSectionList.PSections[i];
|
||||
p^.StartPos.y := p^.StartPos.y - ACount;
|
||||
p^.EndPos.y := p^.EndPos.y - ACount;
|
||||
p^.VirtualLine := p^.VirtualLine - VLineDiff;
|
||||
p^.VirtualLine := p^.VirtualLine - VLineCount;
|
||||
inc(i);
|
||||
end;
|
||||
|
||||
DelVLines;
|
||||
end;
|
||||
|
||||
procedure TSynHLightMultiVirtualLines.RealLinesChanged(AIndex, ACount: Integer);
|
||||
|
@ -17,14 +17,18 @@ type
|
||||
protected
|
||||
procedure SetRealLinesText;
|
||||
procedure SetRealLinesText2;
|
||||
procedure SetRealLinesText3;
|
||||
procedure DumpLines(ALines: TSynHLightMultiVirtualLines);
|
||||
procedure DumpSections(ASectList: TSynHLightMultiSectionList);
|
||||
procedure DumpRanges(ARangeList: TSynHighlighterRangeList);
|
||||
procedure DumpAll(Hl: TSynMultiSyn);
|
||||
procedure CheckTokensForLine(Name: String; HL: TSynCustomHighlighter;
|
||||
LineIdx: Integer; ExpAttr: Array of TSynHighlighterAttributes);
|
||||
published
|
||||
procedure TestSectionList;
|
||||
procedure TestVirtualLines;
|
||||
procedure TestMultiHL;
|
||||
procedure TestMultiHLEdit;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -62,6 +66,25 @@ begin
|
||||
]);
|
||||
end;
|
||||
|
||||
procedure TTestHighlightMulti.SetRealLinesText3;
|
||||
begin
|
||||
SetLines(['abc',
|
||||
'abc',
|
||||
'test<pas>unit a;',
|
||||
'//Comment',
|
||||
'//Comment',
|
||||
'uses Foo;',
|
||||
'//</pas><x>',
|
||||
'def',
|
||||
'def',
|
||||
'def',
|
||||
'x<pas>interface',
|
||||
'//Comment',
|
||||
'//</pas></x>',
|
||||
'abc'
|
||||
]);
|
||||
end;
|
||||
|
||||
procedure TTestHighlightMulti.DumpLines(ALines: TSynHLightMultiVirtualLines);
|
||||
var
|
||||
i: Integer;
|
||||
@ -92,16 +115,39 @@ procedure TTestHighlightMulti.DumpAll(Hl: TSynMultiSyn);
|
||||
var
|
||||
i: Integer;
|
||||
begin // ensure CurrentLines are set
|
||||
debugln(['--- Default']);
|
||||
DumpLines(hl.DefaultVirtualLines);
|
||||
DumpSections(hl.DefaultVirtualLines.SectionList);
|
||||
debugln(['-']);
|
||||
DumpRanges(TSynHighlighterRangeList(hl.CurrentLines.Ranges[hl]));
|
||||
for i := 0 to hl.Schemes.Count - 1 do begin
|
||||
debugln(['-- ',i,' ', dbgs(hl.Schemes[i].Highlighter)]);
|
||||
DumpLines(hl.Schemes[i].VirtualLines);
|
||||
DumpSections(hl.Schemes[i].VirtualLines.SectionList);
|
||||
DebugLnEnter(['>> --- Default / Lines']); DebugLnEnter;
|
||||
DumpLines(hl.DefaultVirtualLines);
|
||||
DebugLnExit; DebugLnEnter(['-- Sections']);
|
||||
DumpSections(hl.DefaultVirtualLines.SectionList);
|
||||
DebugLnExit; DebugLnEnter(['-- Ranges']);
|
||||
DumpRanges(TSynHighlighterRangeList(hl.CurrentLines.Ranges[hl]));
|
||||
for i := 0 to hl.Schemes.Count - 1 do begin
|
||||
DebugLnExit; DebugLnEnter(['-- Scheme=',i,' ', dbgs(hl.Schemes[i].Highlighter)]);
|
||||
DumpLines(hl.Schemes[i].VirtualLines);
|
||||
DumpSections(hl.Schemes[i].VirtualLines.SectionList);
|
||||
end;
|
||||
DebugLnExit;
|
||||
DebugLnExit('<<');
|
||||
end;
|
||||
|
||||
procedure TTestHighlightMulti.CheckTokensForLine(Name: String; HL: TSynCustomHighlighter;
|
||||
LineIdx: Integer; ExpAttr: array of TSynHighlighterAttributes);
|
||||
var
|
||||
c: Integer;
|
||||
begin
|
||||
HL.StartAtLineIndex(LineIdx);
|
||||
c := 0;
|
||||
while not HL.GetEol do begin
|
||||
//DebugLn([HL.GetToken,' (',HL.GetTokenID ,') at ', HL.GetTokenPos]);
|
||||
AssertTrue(Format('%s Attrib Line=%d pos=%d exp=%s got=%s',
|
||||
[Name, LineIdx, c, ExpAttr[c].StoredName, HL.GetTokenAttribute.StoredName]),
|
||||
ExpAttr[c] = HL.GetTokenAttribute);
|
||||
HL.Next;
|
||||
inc(c);
|
||||
if c >= length(ExpAttr) then
|
||||
break;
|
||||
end;
|
||||
AssertEquals(Name+ 'TokenId Line='+IntToStr(LineIdx)+' amount of tokens', length(ExpAttr), c );
|
||||
end;
|
||||
|
||||
procedure TTestHighlightMulti.TestSectionList;
|
||||
@ -759,6 +805,189 @@ begin
|
||||
RunXmlLfmPas('<dummy>foo<lfm>' + LineEnding);
|
||||
end;
|
||||
|
||||
procedure TTestHighlightMulti.TestMultiHLEdit;
|
||||
var
|
||||
MultiHl: TSynMultiSyn;
|
||||
XmlHl: TSynXMLSyn;
|
||||
EmptyScheme, PasScheme: TSynHighlighterMultiScheme;
|
||||
AttEl, AttSym: TSynHighlighterAttributes;
|
||||
PasHl: TSynPasSyn;
|
||||
|
||||
procedure InitMultiXmlPasHl;
|
||||
begin
|
||||
MultiHl := TSynMultiSyn.Create(Form);
|
||||
XmlHl := TSynXMLSyn.Create(Form);
|
||||
MultiHl.DefaultHighlighter := XmlHl;
|
||||
PasScheme := TSynHighlighterMultiScheme(MultiHl.Schemes.Add);
|
||||
PasScheme.CaseSensitive := False;
|
||||
PasScheme.StartExpr := '<pas>';
|
||||
PasScheme.EndExpr := '</pas>';
|
||||
PasHl := TSynPasSyn.Create(Form);
|
||||
PasScheme.Highlighter := PasHl;
|
||||
SynEdit.Highlighter := MultiHl;
|
||||
end;
|
||||
procedure FinishMultiXmlPasHl;
|
||||
begin
|
||||
SynEdit.Highlighter := nil;
|
||||
FreeAndNil(XmlHl);
|
||||
FreeAndNil(PasHl);
|
||||
FreeAndNil(MultiHl);
|
||||
end;
|
||||
begin
|
||||
{%region}
|
||||
// Issue 0022519
|
||||
MultiHl := TSynMultiSyn.Create(Form);
|
||||
XmlHl := TSynXMLSyn.Create(Form);
|
||||
MultiHl.DefaultHighlighter := XmlHl;
|
||||
EmptyScheme := TSynHighlighterMultiScheme(MultiHl.Schemes.Add);
|
||||
|
||||
AttEl := XmlHl.ElementAttri;
|
||||
AttSym := XmlHl.SymbolAttri;
|
||||
|
||||
SynEdit.Highlighter := MultiHl;
|
||||
|
||||
SynEdit.SetTextBetweenPoints(Point(1,1), Point(1,1), '<html>'+LineEnding);
|
||||
DumpAll(MultiHl);
|
||||
MultiHl.CurrentLines := SynEdit.TextBuffer;
|
||||
CheckTokensForLine('1st line=html', MultiHl, 0, [AttSym, AttEl, AttSym]);
|
||||
|
||||
SynEdit.SetTextBetweenPoints(Point(1,2), Point(1,2), '<a>'+LineEnding);
|
||||
DumpAll(MultiHl);
|
||||
SynEdit.SetTextBetweenPoints(Point(1,1), Point(1,1), ''+LineEnding);
|
||||
DumpAll(MultiHl);
|
||||
SynEdit.SetTextBetweenPoints(Point(1,1), Point(1,2), '');
|
||||
DumpAll(MultiHl);
|
||||
|
||||
SynEdit.Highlighter := nil;
|
||||
FreeAndNil(XmlHl);
|
||||
FreeAndNil(MultiHl);
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// multiple section (same scheme) on one line
|
||||
SynEdit.ClearAll;
|
||||
InitMultiXmlPasHl;
|
||||
|
||||
SynEdit.SetTextBetweenPoints(Point(1,1), Point(1,1),
|
||||
'abc'+LineEnding+
|
||||
'test<pas>unit a;</pas><x><pas>uses </pas></x><pas> Foo;</pas>a'+LineEnding+
|
||||
'abc'+LineEnding
|
||||
);
|
||||
DumpAll(MultiHl);
|
||||
//Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,1), Point(1,3), '');
|
||||
DumpAll(MultiHl);
|
||||
//Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at begin of section (no overlap / 1 line)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,3), Point(1,4), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at begin of section (no overlap / 2 line)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,3), Point(1,5), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at begin of section (overlap / 1 line of sect)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,2), Point(1,4), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at begin of section (overlap / 2 line of sect)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,2), Point(1,5), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at middle of section (1 line)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,4), Point(1,5), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at end of section (no overlap 1 line)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,7), Point(1,8), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at end of section (no overlap 2 line)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,6), Point(1,8), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
{%region}
|
||||
// longer section, delete part at end of section (overlap 1 line of sect)
|
||||
SetRealLinesText3;
|
||||
InitMultiXmlPasHl;
|
||||
SynEdit.SimulatePaintText;
|
||||
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
SynEdit.SetTextBetweenPoints(Point(1,7), Point(1,9), '');
|
||||
DumpAll(MultiHl); //Application.ProcessMessages; readln;
|
||||
|
||||
FinishMultiXmlPasHl;
|
||||
{%endregion}
|
||||
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
RegisterTest(TTestHighlightMulti);
|
||||
|
Loading…
Reference in New Issue
Block a user