mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-04 20:20:23 +02:00
SynEdit, Refactor: Move more range scanning code to highlighter
git-svn-id: trunk@24477 -
This commit is contained in:
parent
02c12b2e82
commit
9a3a4acd60
@ -364,8 +364,8 @@ type
|
||||
fInserting: Boolean;
|
||||
fLastMouseCaret: TPoint; // Char; physical (screen)
|
||||
FLastMousePoint: TPoint; // Pixel
|
||||
fHighlighterNeedsUpdateStartLine: integer; // 1 based, 0 means invalid
|
||||
fHighlighterNeedsUpdateEndLine: integer; // 1 based, 0 means invalid
|
||||
FChangedLinesStart: integer; // 1 based, 0 means invalid
|
||||
FChangedLinesEnd: integer; // 1 based, 0 means invalid
|
||||
FBeautifier: TSynCustomBeautifier;
|
||||
FBeautifyStartLineIdx, FBeautifyEndLineIdx: Integer;
|
||||
|
||||
@ -524,7 +524,7 @@ type
|
||||
procedure MoveCaretVert(DY: integer);
|
||||
procedure PrimarySelectionRequest(const RequestedFormatID: TClipboardFormat;
|
||||
Data: TStream);
|
||||
function ScanFrom(var Index: integer; AtLeastTilIndex: integer = -1): integer; // Todo: move to line, currently scans twice or more, if SharedView is active
|
||||
procedure ScanRanges;
|
||||
procedure DoBlockSelectionChanged(Sender: TObject);
|
||||
procedure SetBlockBegin(Value: TPoint);
|
||||
procedure SetBlockEnd(Value: TPoint);
|
||||
@ -610,7 +610,6 @@ type
|
||||
procedure SetLines(Value: TStrings); override;
|
||||
function GetMarkupMgr: TObject; override;
|
||||
function GetCaretObj: TSynEditCaret; override;
|
||||
procedure ScanFromAfterLock;
|
||||
procedure DecPaintLock;
|
||||
procedure DestroyWnd; override;
|
||||
procedure DragOver(Source: TObject; X, Y: Integer;
|
||||
@ -632,6 +631,7 @@ type
|
||||
{$ENDIF}
|
||||
Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
||||
Procedure LineTextChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
||||
procedure DoHighlightChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
||||
procedure LinesChanging(Sender: TObject);
|
||||
procedure LinesChanged(Sender: TObject);
|
||||
procedure ListCleared(Sender: TObject);
|
||||
@ -1540,6 +1540,7 @@ begin
|
||||
with TSynEditStringList(fLines) do begin
|
||||
AddChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
|
||||
AddChangeHandler(senrLineChange, {$IFDEF FPC}@{$ENDIF}LineTextChanged);
|
||||
AddChangeHandler(senrHighlightChanged, {$IFDEF FPC}@{$ENDIF}DoHighlightChanged);
|
||||
AddNotifyHandler(senrBeginUpdate, {$IFDEF FPC}@{$ENDIF}LinesChanging);
|
||||
AddNotifyHandler(senrEndUpdate, {$IFDEF FPC}@{$ENDIF}LinesChanged);
|
||||
AddNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}ListCleared);
|
||||
@ -1709,35 +1710,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.ScanFromAfterLock;
|
||||
var
|
||||
LastLineChanged: LongInt;
|
||||
begin
|
||||
{$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- ScanFromAfterLock; fPaintLock:=', fPaintLock, ' fHighlighterNeedsUpdateStartLine=', fHighlighterNeedsUpdateStartLine,' fHighlighterNeedsUpdateEndLine=',fHighlighterNeedsUpdateEndLine]);{$ENDIF}
|
||||
if fHighlighterNeedsUpdateStartLine>0 then begin
|
||||
//DebugLn('TCustomSynEdit.DecPaintLock ',dbgs(fHighlighterNeedsUpdateStartLine),'-',dbgs(fHighlighterNeedsUpdateEndLine));
|
||||
if fHighlighterNeedsUpdateStartLine<=FTheLinesView.Count then begin
|
||||
if fHighlighterNeedsUpdateEndLine>FTheLinesView.Count then
|
||||
fHighlighterNeedsUpdateEndLine:=FTheLinesView.Count;
|
||||
// rescan all lines in range
|
||||
// Note: The highlighter range of the line can be invalid as well,
|
||||
// so start scan one line earlier
|
||||
dec(fHighlighterNeedsUpdateStartLine, 2);
|
||||
LastLineChanged:=ScanFrom(fHighlighterNeedsUpdateStartLine,
|
||||
fHighlighterNeedsUpdateEndLine-1);
|
||||
//DebugLn('TCustomSynEdit.DecPaintLock ',dbgs(fHighlighterNeedsUpdateStartLine),'-',dbgs(fHighlighterNeedsUpdateEndLine),' LastLineChanged=',dbgs(LastLineChanged));
|
||||
InvalidateLines(fHighlighterNeedsUpdateStartLine,LastLineChanged+1);
|
||||
InvalidateGutterLines(fHighlighterNeedsUpdateStartLine,LastLineChanged+1);
|
||||
end;
|
||||
fHighlighterNeedsUpdateStartLine:=0;
|
||||
fHighlighterNeedsUpdateEndLine:=0;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.DecPaintLock;
|
||||
begin
|
||||
if (fPaintLock=1) and HandleAllocated then begin
|
||||
ScanFromAfterLock;
|
||||
ScanRanges;
|
||||
FChangedLinesStart:=0;
|
||||
FChangedLinesEnd:=0;
|
||||
end;
|
||||
FCaret.Unlock; // Maybe after FFoldedLinesView
|
||||
FTrimmedLinesView.UnLock; // Must be unlocked after caret
|
||||
@ -3814,7 +3792,7 @@ begin
|
||||
if eoFoldedCopyPaste in fOptions2 then begin
|
||||
PTxt := ClipHelper.GetTagPointer(synClipTagFold);
|
||||
if PTxt <> nil then begin
|
||||
ScanFromAfterLock;
|
||||
ScanRanges;
|
||||
FFoldedLinesView.ApplyFoldDescription(InsStart.Y -1, InsStart.X,
|
||||
FInternalBlockSelection.StartLinePos-1, FInternalBlockSelection.StartBytePos,
|
||||
PTxt, ClipHelper.GetTagLen(synClipTagFold));
|
||||
@ -4541,28 +4519,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomSynEdit.ScanFrom(var Index: integer; AtLeastTilIndex: integer): integer;
|
||||
// Index and AtLeastTilIndex are 0 based
|
||||
procedure TCustomSynEdit.ScanRanges;
|
||||
begin
|
||||
{$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- ScanFrom Index=', Index, ' AtLeats=', AtLeastTilIndex]);{$ENDIF}
|
||||
if Index < 0 then Index := 0;
|
||||
Result := Max(Index, AtLeastTilIndex);
|
||||
if not assigned(fHighlighter) or (Index > FTheLinesView.Count - 1) then begin
|
||||
FFoldedLinesView.FixFoldingAtTextIndex(Index);
|
||||
fMarkupManager.TextChangedScreen(Max(RowToScreenRow(Index+1), 0), LinesInWindow+1);
|
||||
if not assigned(FHighlighter) then begin
|
||||
fMarkupManager.TextChanged(FChangedLinesStart, FChangedLinesEnd);
|
||||
Topline := TopLine;
|
||||
exit;
|
||||
end;
|
||||
fHighlighter.CurrentLines := FTheLinesView;
|
||||
Result := fHighlighter.ScanFrom(Index, AtLeastTilIndex);
|
||||
FHighlighter.CurrentLines := FTheLinesView;
|
||||
FHighlighter.ScanRanges;
|
||||
|
||||
FFoldedLinesView.FixFoldingAtTextIndex(Index, Result);
|
||||
fMarkupManager.TextChangedScreen(Max(RowToScreenRow(Index+1), 0),
|
||||
Min(RowToScreenRow(Result), LinesInWindow+1));
|
||||
fMarkupManager.TextChanged(FChangedLinesStart, FChangedLinesEnd);
|
||||
Topline := TopLine;
|
||||
if Index > 0 then dec(Index);
|
||||
Dec(Result);
|
||||
{$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- ScanFrom Result=', Result]);{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.LineCountChanged(Sender: TSynEditStrings;
|
||||
@ -4582,27 +4550,25 @@ begin
|
||||
if (FBeautifyEndLineIdx < AIndex) then
|
||||
FBeautifyEndLineIdx := AIndex;
|
||||
end;
|
||||
|
||||
if PaintLock>0 then begin
|
||||
if (fHighlighterNeedsUpdateStartLine<1)
|
||||
or (fHighlighterNeedsUpdateStartLine>AIndex+1) then
|
||||
fHighlighterNeedsUpdateStartLine:=AIndex+1;
|
||||
if (fHighlighterNeedsUpdateEndLine<1)
|
||||
or (fHighlighterNeedsUpdateEndLine<AIndex+1) then
|
||||
fHighlighterNeedsUpdateEndLine:=AIndex + 1 + MaX(ACount, 0)
|
||||
if (FChangedLinesStart<1)
|
||||
or (FChangedLinesStart>AIndex+1) then
|
||||
FChangedLinesStart:=AIndex+1;
|
||||
if (FChangedLinesEnd<1)
|
||||
or (FChangedLinesEnd<AIndex+1) then
|
||||
FChangedLinesEnd:=AIndex + 1 + MaX(ACount, 0)
|
||||
else
|
||||
fHighlighterNeedsUpdateEndLine := fHighlighterNeedsUpdateEndLine
|
||||
+ MaX(ACount, 0)
|
||||
end
|
||||
else
|
||||
ScanFrom(AIndex, Max(AIndex, AIndex + ACount));
|
||||
InvalidateLines(AIndex + 1, -1);
|
||||
InvalidateGutterLines(AIndex + 1, -1);
|
||||
FChangedLinesEnd := FChangedLinesEnd + MaX(ACount, 0);
|
||||
end else begin
|
||||
ScanRanges;
|
||||
InvalidateLines(AIndex + 1, -1);
|
||||
InvalidateGutterLines(AIndex + 1, -1);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.LineTextChanged(Sender: TSynEditStrings;
|
||||
AIndex, ACount: Integer);
|
||||
var
|
||||
EndIndex: Integer;
|
||||
begin
|
||||
{$IFDEF SYNFOLDDEBUG}debugln(['FOLD-- LineTextChanged Aindex', AIndex, ' ACount=', ACount]);{$ENDIF}
|
||||
IncreaseChangeStamp;
|
||||
@ -4610,18 +4576,27 @@ begin
|
||||
FBeautifyStartLineIdx := AIndex;
|
||||
if (AIndex + ACount - 1 > FBeautifyEndLineIdx) then
|
||||
FBeautifyEndLineIdx := AIndex + ACount - 1;
|
||||
|
||||
if PaintLock>0 then begin
|
||||
if (fHighlighterNeedsUpdateStartLine<1)
|
||||
or (fHighlighterNeedsUpdateStartLine>AIndex+1) then
|
||||
fHighlighterNeedsUpdateStartLine:=AIndex+1;
|
||||
if (fHighlighterNeedsUpdateEndLine<1)
|
||||
or (fHighlighterNeedsUpdateEndLine<AIndex+1) then
|
||||
fHighlighterNeedsUpdateEndLine:=AIndex + 1 + MaX(ACount, 0);
|
||||
exit;
|
||||
if (FChangedLinesStart<1)
|
||||
or (FChangedLinesStart>AIndex+1) then
|
||||
FChangedLinesStart:=AIndex+1;
|
||||
if (FChangedLinesEnd<1)
|
||||
or (FChangedLinesEnd<AIndex+1) then
|
||||
FChangedLinesEnd:=AIndex + 1 + MaX(ACount, 0);
|
||||
end else begin
|
||||
ScanRanges;
|
||||
InvalidateLines(AIndex + 1, AIndex + ACount);
|
||||
InvalidateGutterLines(AIndex + 1, AIndex + ACount);
|
||||
end;
|
||||
EndIndex := ScanFrom(AIndex, Max(AIndex, AIndex + ACount)) + 1;
|
||||
InvalidateLines(AIndex + 1, EndIndex);
|
||||
InvalidateGutterLines(AIndex + 1, EndIndex);
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.DoHighlightChanged(Sender: TSynEditStrings; AIndex,
|
||||
ACount: Integer);
|
||||
begin
|
||||
InvalidateLines(AIndex + 1, AIndex + 1 + ACount);
|
||||
InvalidateGutterLines(AIndex + 1, AIndex + 1 + ACount);
|
||||
FFoldedLinesView.FixFoldingAtTextIndex(AIndex, AIndex + ACount);
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.ListCleared(Sender: TObject);
|
||||
@ -5007,6 +4982,7 @@ begin
|
||||
if FHighlighter <> nil then
|
||||
FHighlighter.DetachFromLines(FLines);
|
||||
|
||||
// TextBuffer
|
||||
OldLines := TSynEditStringList(FLines);
|
||||
if AValue = nil then begin
|
||||
FLines := TSynEditStringList.Create;
|
||||
@ -5323,7 +5299,7 @@ begin
|
||||
BlockBegin := NewCaret;
|
||||
SetSelTextPrimitive(smNormal, PChar(DragDropText), true);
|
||||
if FoldInfo <> '' then begin
|
||||
ScanFromAfterLock;
|
||||
ScanRanges;
|
||||
FFoldedLinesView.ApplyFoldDescription(NewCaret.Y -1, NewCaret.X,
|
||||
FBlockSelection.StartLinePos-1, FBlockSelection.StartBytePos,
|
||||
PChar(FoldInfo), length(FoldInfo));
|
||||
@ -5424,8 +5400,6 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.SetHighlighter(const Value: TSynCustomHighlighter);
|
||||
var
|
||||
tmp: Integer;
|
||||
begin
|
||||
if Value <> fHighlighter then begin
|
||||
RemoveHooksFromHighlighter;
|
||||
@ -5451,8 +5425,7 @@ begin
|
||||
RecalcCharExtent;
|
||||
FTheLinesView.BeginUpdate;
|
||||
try
|
||||
tmp := 0;
|
||||
ScanFrom(tmp,FTheLinesView.Count-1);
|
||||
ScanRanges;
|
||||
finally
|
||||
FTheLinesView.EndUpdate;
|
||||
end;
|
||||
@ -6379,7 +6352,7 @@ procedure TCustomSynEdit.AfterLoadFromFile;
|
||||
begin
|
||||
if assigned(FFoldedLinesView) then begin
|
||||
// TODO: Maybe defer until after paintlock?
|
||||
ScanFromAfterLock;
|
||||
ScanRanges;
|
||||
FFoldedLinesView.UnfoldAll;
|
||||
FFoldedLinesView.CollapseDefaultFolds;
|
||||
TopLine := TopLine;
|
||||
@ -7207,15 +7180,16 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.HighlighterAttrChanged(Sender: TObject);
|
||||
var
|
||||
t: integer;
|
||||
begin
|
||||
RecalcCharExtent;
|
||||
SizeOrFontChanged(TRUE); //jr 2000-10-01
|
||||
Invalidate;
|
||||
t := 0;
|
||||
if fHighlighter.AttributeChangeNeedScan then
|
||||
ScanFrom(t, FLines.Count - 1);
|
||||
if fHighlighter.AttributeChangeNeedScan then begin
|
||||
FHighlighter.CurrentLines := FTheLinesView;
|
||||
FHighlighter.ScanAllRanges;
|
||||
fMarkupManager.TextChanged(0, FTheLinesView.Count - 1);
|
||||
TopLine := TopLine;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.StatusChanged(AChanges: TSynStatusChanges);
|
||||
|
@ -44,7 +44,7 @@ uses
|
||||
{$ENDIF}
|
||||
Registry, IniFiles,
|
||||
{$ENDIF}
|
||||
SynEditTypes, SynEditMiscClasses, SynEditTextBase;
|
||||
SynEditTypes, SynEditMiscClasses, SynEditTextBase, SynEditTextBuffer;
|
||||
|
||||
{$DEFINE _Gp_MustEnhanceRegistry}
|
||||
{$IFDEF SYN_COMPILER_4_UP}
|
||||
@ -59,19 +59,29 @@ type
|
||||
|
||||
{ TSynHighlighterRangeList }
|
||||
|
||||
TSynHighlighterRangeList = class(TSynEditStorageMem)
|
||||
TSynHighlighterRangeList = class(TSynManagedStorageMem)
|
||||
private
|
||||
FRefCount: Integer;
|
||||
FNeedsReScanStartIndex: Integer;
|
||||
FNeedsReScanEndIndex: Integer;
|
||||
function GetRange(Index: Integer): Pointer;
|
||||
procedure SetRange(Index: Integer; const AValue: Pointer);
|
||||
protected
|
||||
function ItemSize: Integer; override;
|
||||
protected
|
||||
procedure LineTextChanged(AIndex: Integer); override;
|
||||
procedure InsertedLines(AIndex, ACount: Integer); override;
|
||||
procedure DeletedLines(AIndex, ACount: Integer); override;
|
||||
public
|
||||
constructor Create;
|
||||
procedure ClearReScanNeeded;
|
||||
procedure InvalidateAll;
|
||||
procedure IncRefCount;
|
||||
procedure DecRefCount;
|
||||
property Range[Index: Integer]: Pointer read GetRange write SetRange; default;
|
||||
property RefCount: Integer read FRefCount;
|
||||
property NeedsReScanStartIndex: Integer read FNeedsReScanStartIndex;
|
||||
property NeedsReScanEndIndex: Integer read FNeedsReScanEndIndex;
|
||||
end;
|
||||
|
||||
{ TSynHighlighterAttributes }
|
||||
@ -287,7 +297,9 @@ type
|
||||
procedure StartAtLineIndex(LineNumber:Integer); virtual; // 0 based
|
||||
procedure ContinueNextLine; // To be called at EOL; does not read the range
|
||||
|
||||
function ScanFrom(Index: integer; AtLeastTilIndex: integer = -1): integer;
|
||||
function ScanFrom(Index: integer; AtLeastTilIndex: integer = -1): integer; deprecated;
|
||||
procedure ScanRanges;
|
||||
procedure ScanAllRanges;
|
||||
procedure SetRange(Value: Pointer); virtual;
|
||||
procedure ResetRange; virtual;
|
||||
procedure SetLine({$IFDEF FPC}const {$ENDIF}NewValue: String;
|
||||
@ -1248,6 +1260,40 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynCustomHighlighter.ScanRanges;
|
||||
var
|
||||
StartIndex, EndIndex, CurrentIndex, c: Integer;
|
||||
begin
|
||||
StartIndex := CurrentRanges.NeedsReScanStartIndex;
|
||||
if (StartIndex < 0) or (StartIndex >= CurrentRanges.Count) then exit;
|
||||
EndIndex := CurrentRanges.NeedsReScanEndIndex + 1;
|
||||
CurrentIndex := StartIndex;
|
||||
c := CurrentLines.Count;
|
||||
FIsScanning := True;
|
||||
try
|
||||
StartAtLineIndex(CurrentIndex);
|
||||
NextToEol;
|
||||
while UpdateRangeInfoAtLine(CurrentIndex) or
|
||||
(CurrentIndex <= EndIndex)
|
||||
do begin
|
||||
inc(CurrentIndex);
|
||||
if CurrentIndex = c then
|
||||
break;
|
||||
ContinueNextLine;
|
||||
NextToEol;
|
||||
end;
|
||||
finally
|
||||
FIsScanning := False;
|
||||
end;
|
||||
CurrentLines.SendHighlightChanged(StartIndex, CurrentIndex);
|
||||
end;
|
||||
|
||||
procedure TSynCustomHighlighter.ScanAllRanges;
|
||||
begin
|
||||
CurrentRanges.InvalidateAll;
|
||||
ScanRanges;
|
||||
end;
|
||||
|
||||
procedure TSynCustomHighlighter.SetEnabled(const Value: boolean);
|
||||
begin
|
||||
if fEnabled <> Value then
|
||||
@ -1275,8 +1321,11 @@ begin
|
||||
r := TSynHighlighterRangeList(Lines.Ranges[ClassType]);
|
||||
if assigned(r) then
|
||||
r.IncRefCount
|
||||
else
|
||||
Lines.Ranges[ClassType] := CreateRangeList;
|
||||
else begin
|
||||
r := CreateRangeList;
|
||||
Lines.Ranges[ClassType] := r;
|
||||
r.InvalidateAll;
|
||||
end;
|
||||
FCurrentLines := nil;
|
||||
end;
|
||||
|
||||
@ -1288,8 +1337,8 @@ begin
|
||||
if not assigned(r) then exit;
|
||||
r.DecRefCount;
|
||||
if r.RefCount = 0 then begin
|
||||
r.Free;
|
||||
Lines.Ranges[ClassType] := nil;
|
||||
r.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1332,10 +1381,55 @@ begin
|
||||
Result := SizeOf(Pointer);
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.LineTextChanged(AIndex: Integer);
|
||||
begin
|
||||
if FNeedsReScanStartIndex < 0 then begin
|
||||
FNeedsReScanStartIndex := AIndex;
|
||||
FNeedsReScanEndIndex := AIndex;
|
||||
end
|
||||
else if AIndex < FNeedsReScanStartIndex then
|
||||
FNeedsReScanStartIndex := AIndex
|
||||
else if AIndex > FNeedsReScanEndIndex then
|
||||
FNeedsReScanEndIndex := AIndex;
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.InsertedLines(AIndex, ACount: Integer);
|
||||
begin
|
||||
if (FNeedsReScanStartIndex < 0) or (AIndex < FNeedsReScanStartIndex) then
|
||||
FNeedsReScanStartIndex := AIndex;
|
||||
|
||||
if (FNeedsReScanEndIndex < 0) or (FNeedsReScanEndIndex < AIndex) then
|
||||
FNeedsReScanEndIndex := AIndex + ACount
|
||||
else
|
||||
FNeedsReScanEndIndex := FNeedsReScanEndIndex + ACount
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.DeletedLines(AIndex, ACount: Integer);
|
||||
begin
|
||||
if AIndex >= Count then exit;
|
||||
if (FNeedsReScanStartIndex < 0) or (AIndex < FNeedsReScanStartIndex) then
|
||||
FNeedsReScanStartIndex := AIndex;
|
||||
if (FNeedsReScanEndIndex < 0) or (FNeedsReScanEndIndex < AIndex) then
|
||||
FNeedsReScanEndIndex := AIndex;
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.ClearReScanNeeded;
|
||||
begin
|
||||
FNeedsReScanStartIndex := -1;
|
||||
FNeedsReScanEndIndex := -1;
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.InvalidateAll;
|
||||
begin
|
||||
FNeedsReScanStartIndex := 0;
|
||||
FNeedsReScanEndIndex := Count - 1;
|
||||
end;
|
||||
|
||||
constructor TSynHighlighterRangeList.Create;
|
||||
begin
|
||||
Inherited;
|
||||
FRefCount := 1;
|
||||
ClearReScanNeeded;
|
||||
end;
|
||||
|
||||
procedure TSynHighlighterRangeList.IncRefCount;
|
||||
|
@ -145,7 +145,6 @@ type
|
||||
Function GetNextMarkupColAfterRowCol(const aRow, aCol : Integer) : Integer; override;
|
||||
|
||||
// Notifications about Changes to the text
|
||||
Procedure TextChangedScreen(aFirstCodeLine, aLastCodeLine: Integer);
|
||||
Procedure TextChanged(aFirstCodeLine, aLastCodeLine: Integer); override;
|
||||
end;
|
||||
|
||||
@ -485,11 +484,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupManager.TextChangedScreen(aFirstCodeLine, aLastCodeLine: Integer);
|
||||
begin
|
||||
TextChanged(ScreenRowToRow(aFirstCodeLine), ScreenRowToRow(aLastCodeLine));
|
||||
end;
|
||||
|
||||
procedure TSynEditMarkupManager.TextChanged(aFirstCodeLine, aLastCodeLine: Integer);
|
||||
var
|
||||
i : integer;
|
||||
|
@ -39,6 +39,7 @@ type
|
||||
|
||||
TSynEditNotifyReason = ( // TStringListLineCountEvent
|
||||
senrLineCount, senrLineChange, senrEditAction,
|
||||
senrHighlightChanged, // used by Highlighter
|
||||
// TStringListLineEditEvent
|
||||
senrTextEdit,
|
||||
// TNotifyEvent
|
||||
@ -65,13 +66,15 @@ type
|
||||
procedure SetCapacity(const AValue: Integer); virtual;
|
||||
procedure SetCount(const AValue: Integer); virtual;
|
||||
function ItemSize: Integer; virtual; abstract;
|
||||
procedure Move(AFrom, ATo, ALen: Integer); virtual;
|
||||
|
||||
property Mem: PByte read FMem;
|
||||
property ItemPointer[Index: Integer]: Pointer read GetItemPointer;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Move(AFrom, ATo, ALen: Integer); virtual;
|
||||
procedure InsertRows(AIndex, ACount: Integer); virtual;
|
||||
procedure DeleteRows(AIndex, ACount: Integer); virtual;
|
||||
property Capacity: Integer read FCapacity write SetCapacity;
|
||||
// Count must be maintained by owner
|
||||
property Count: Integer read FCount write SetCount;
|
||||
@ -159,6 +162,7 @@ type
|
||||
property IsUndoing: Boolean read GetIsUndoing write SetIsUndoing;
|
||||
property IsRedoing: Boolean read GetIsRedoing write SetIsRedoing;
|
||||
procedure IncreaseTextChangeStamp;
|
||||
procedure SendHighlightChanged(aIndex, aCount: Integer);
|
||||
public
|
||||
property ExpandedStrings[Index: integer]: string read GetExpandedString;
|
||||
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
||||
@ -343,8 +347,25 @@ type
|
||||
write SetCurrentReason;
|
||||
end;
|
||||
|
||||
ESynEditStorageMem = class(Exception);
|
||||
|
||||
implementation
|
||||
|
||||
{$IFNDEF FPC}
|
||||
{$IFDEF SYN_COMPILER_3_UP}
|
||||
resourcestring
|
||||
{$ELSE}
|
||||
const
|
||||
{$ENDIF}
|
||||
{$ELSE}
|
||||
const
|
||||
{$ENDIF}
|
||||
SListIndexOutOfBounds = 'Invalid stringlist index %d';
|
||||
|
||||
procedure ListIndexOutOfBounds(Index: integer);
|
||||
begin
|
||||
raise ESynEditStorageMem.CreateFmt(SListIndexOutOfBounds, [Index]);
|
||||
end;
|
||||
|
||||
{ TSynEditStrings }
|
||||
|
||||
@ -514,6 +535,11 @@ begin
|
||||
inc(fTextChangeStamp);
|
||||
end;
|
||||
|
||||
procedure TSynEditStrings.SendHighlightChanged(aIndex, aCount: Integer);
|
||||
begin
|
||||
SendNotification(senrHighlightChanged, Self, aIndex, aCount);
|
||||
end;
|
||||
|
||||
{ TSynEditStringsLinked }
|
||||
|
||||
constructor TSynEditStringsLinked.Create(ASynStringSource: TSynEditStrings);
|
||||
@ -1186,6 +1212,29 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TSynEditStorageMem.InsertRows(AIndex, ACount: Integer);
|
||||
begin
|
||||
if (AIndex < 0) or (AIndex > Count) then
|
||||
ListIndexOutOfBounds(AIndex);
|
||||
if Capacity < Count + ACount then
|
||||
SetCapacity(Count + ACount);
|
||||
if AIndex < Count then
|
||||
Move(AIndex, AIndex + ACount, Count - AIndex);
|
||||
Count := Count + ACount;
|
||||
end;
|
||||
|
||||
procedure TSynEditStorageMem.DeleteRows(AIndex, ACount: Integer);
|
||||
var
|
||||
LinesAfter: Integer;
|
||||
begin
|
||||
if (AIndex < 0) or (AIndex + ACount > Count) then
|
||||
ListIndexOutOfBounds(AIndex);
|
||||
LinesAfter := Count - (AIndex + ACount);
|
||||
if LinesAfter > 0 then
|
||||
Move(AIndex + ACount, AIndex, LinesAfter);
|
||||
Count := Count - ACount;
|
||||
end;
|
||||
|
||||
procedure TSynEditStorageMem.Move(AFrom, ATo, ALen: Integer);
|
||||
var
|
||||
len: Integer;
|
||||
|
@ -82,42 +82,53 @@ type
|
||||
aLinePos, aBytePos, aCount, aLineBrkCnt: Integer; aText: String);
|
||||
end;
|
||||
|
||||
{ TSynEditStringMemory }
|
||||
{ TSynManagedStorageMem }
|
||||
|
||||
TSynManagedStorageMem = class(TSynEditStorageMem)
|
||||
protected
|
||||
procedure LineTextChanged(AIndex: Integer); virtual;
|
||||
procedure InsertedLines(AIndex, ACount: Integer); virtual;
|
||||
procedure DeletedLines(AIndex, ACount: Integer); virtual;
|
||||
end;
|
||||
|
||||
{ TSynEditStringMemory }
|
||||
TSynEditStringRangeEntry = record
|
||||
Index: TClass;
|
||||
Data: TSynEditStorageMem;
|
||||
Data: TSynManagedStorageMem;
|
||||
end;
|
||||
|
||||
TSynEditStringMemory = class(TSynEditStorageMem)
|
||||
private
|
||||
FAttributeSize: Integer;
|
||||
FRangeList: Array of TSynEditStringRangeEntry;
|
||||
FRangeListLock: Integer;
|
||||
function GetAttribute(Index: Integer; Pos: Integer; Size: Word): Pointer;
|
||||
function GetAttributeSize: Integer;
|
||||
function GetObject(Index: Integer): TObject;
|
||||
function GetRange(Index: TClass): TSynEditStorageMem;
|
||||
function GetRange(Index: TClass): TSynManagedStorageMem;
|
||||
function GetString(Index: Integer): String;
|
||||
procedure SetAttribute(Index: Integer; Pos: Integer; Size: Word; const AValue: Pointer);
|
||||
procedure SetAttributeSize(const AValue: Integer);
|
||||
procedure SetObject(Index: Integer; const AValue: TObject);
|
||||
procedure SetRange(Index: TClass; const AValue: TSynEditStorageMem);
|
||||
procedure SetRange(Index: TClass; const AValue: TSynManagedStorageMem);
|
||||
procedure SetString(Index: Integer; const AValue: String);
|
||||
protected
|
||||
procedure Move(AFrom, ATo, ALen: Integer); override;
|
||||
procedure SetCount(const AValue: Integer); override;
|
||||
function ItemSize: Integer; override;
|
||||
procedure SetCapacity(const AValue: Integer); override;
|
||||
public
|
||||
constructor Create;
|
||||
procedure Move(AFrom, ATo, ALen: Integer); override;
|
||||
|
||||
procedure InsertRows(AIndex, ACount: Integer); override;
|
||||
procedure DeleteRows(AIndex, ACount: Integer); override;
|
||||
property Strings[Index: Integer]: String read GetString write SetString; default;
|
||||
property Objects[Index: Integer]: TObject read GetObject write SetObject;
|
||||
property Attribute[Index: Integer; Pos: Integer; Size: Word]: Pointer
|
||||
read GetAttribute write SetAttribute;
|
||||
property AttributeSize: Integer read GetAttributeSize write SetAttributeSize;
|
||||
|
||||
property RangeList[Index: TClass]: TSynEditStorageMem read GetRange write SetRange;
|
||||
property RangeList[Index: TClass]: TSynManagedStorageMem read GetRange write SetRange;
|
||||
end;
|
||||
|
||||
{ TSynEditStringList }
|
||||
@ -129,6 +140,7 @@ type
|
||||
|
||||
FLineRangeNotificationList: TLineRangeNotificationList; // LineCount
|
||||
FLineChangeNotificationList: TLineRangeNotificationList; // ContentChange (not called on add...)
|
||||
FLineInvalidateNotificationList: TLineRangeNotificationList; // senrHighlightChanged
|
||||
FLineEditNotificationList: TLineEditNotificationList;
|
||||
FRefCount: integer;
|
||||
FUndoRedoAddedNotificationList: TSynMethodList;
|
||||
@ -424,6 +436,7 @@ begin
|
||||
|
||||
FLineRangeNotificationList := TLineRangeNotificationList.Create;
|
||||
FLineChangeNotificationList := TLineRangeNotificationList.Create;
|
||||
FLineInvalidateNotificationList := TLineRangeNotificationList.Create;
|
||||
FLineEditNotificationList := TLineEditNotificationList.Create;
|
||||
FUndoRedoAddedNotificationList := TLineEditNotificationList.Create;
|
||||
FOnChangeList := TSynMethodList.Create;
|
||||
@ -449,6 +462,7 @@ begin
|
||||
SetCapacity(0);
|
||||
FreeAndNil(FLineRangeNotificationList);
|
||||
FreeAndNil(FLineChangeNotificationList);
|
||||
FreeAndNil(FLineInvalidateNotificationList);
|
||||
FreeAndNil(FLineEditNotificationList);
|
||||
FreeAndNil(FUndoRedoAddedNotificationList);
|
||||
FreeAndNil(FOnChangeList);
|
||||
@ -516,37 +530,26 @@ end;
|
||||
|
||||
procedure TSynEditStringList.Delete(Index: integer);
|
||||
begin
|
||||
if (Index < 0) or (Index > Count) then
|
||||
// Ensure correct index, so DeleteLines will not throw exception
|
||||
if (Index < 0) or (Index >= Count) then
|
||||
ListIndexOutOfBounds(Index);
|
||||
BeginUpdate;
|
||||
if Index < Count-1 then
|
||||
fList.Move(Index + 1, Index, Count-Index-1);
|
||||
SetCount(Count - 1);
|
||||
FList.DeleteRows(Index, 1);
|
||||
fIndexOfLongestLine := -1;
|
||||
FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, -1);
|
||||
EndUpdate;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringList.DeleteLines(Index, NumLines: Integer);
|
||||
var
|
||||
LinesAfter: integer;
|
||||
begin
|
||||
if NumLines > 0 then begin
|
||||
if (Index < 0) or (Index >= Count) then
|
||||
// Ensure correct index, so DeleteLines will not throw exception
|
||||
if (Index < 0) or (Index + NumLines > Count) then
|
||||
ListIndexOutOfBounds(Index);
|
||||
LinesAfter := Count - (Index + NumLines);
|
||||
if LinesAfter < 0 then
|
||||
NumLines := Count - Index;
|
||||
if LinesAfter > 0 then begin
|
||||
BeginUpdate;
|
||||
try
|
||||
fList.Move(Index + NumLines, Index, LinesAfter);
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
end;
|
||||
SetCount(Count - NumLines);
|
||||
BeginUpdate;
|
||||
FList.DeleteRows(Index, NumLines);
|
||||
FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, -NumLines);
|
||||
EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -717,13 +720,14 @@ end;
|
||||
|
||||
procedure TSynEditStringList.InsertItem(Index: integer; const S: string);
|
||||
begin
|
||||
// Ensure correct index, so DeleteLines will not throw exception
|
||||
if (Index < 0) or (Index > Count) then
|
||||
ListIndexOutOfBounds(Index);
|
||||
BeginUpdate;
|
||||
if Count = Capacity then
|
||||
Grow;
|
||||
if Index < Count then
|
||||
FList.Move(Index, Index+1, Count - Index);
|
||||
FList.InsertRows(Index, 1);
|
||||
fIndexOfLongestLine := -1; //mh 2000-10-19
|
||||
SetCount(Count + 1);
|
||||
fList[Index] := S;
|
||||
FList.Objects[Index] := nil;
|
||||
Flags[Index] := [];
|
||||
@ -734,13 +738,14 @@ end;
|
||||
procedure TSynEditStringList.InsertLines(Index, NumLines: integer);
|
||||
begin
|
||||
if NumLines > 0 then begin
|
||||
// Ensure correct index, so DeleteLines will not throw exception
|
||||
if (Index < 0) or (Index > Count) then
|
||||
ListIndexOutOfBounds(Index);
|
||||
BeginUpdate;
|
||||
try
|
||||
if Capacity<Count + NumLines then
|
||||
SetCapacity(Count + NumLines);
|
||||
if Index < Count then
|
||||
FList.Move(Index, Index + NumLines, Count-Index);
|
||||
SetCount(Count + NumLines);
|
||||
FList.InsertRows(Index, NumLines);
|
||||
FLineRangeNotificationList.CallRangeNotifyEvents(self, Index, NumLines);
|
||||
finally
|
||||
EndUpdate;
|
||||
@ -795,7 +800,7 @@ end;
|
||||
|
||||
procedure TSynEditStringList.PutRange(Index: TClass; const ARange: TSynEditStorageMem);
|
||||
begin
|
||||
FList.RangeList[Index] := ARange;
|
||||
FList.RangeList[Index] := ARange as TSynManagedStorageMem;
|
||||
end;
|
||||
|
||||
function TSynEditStringList.GetAttribute(const Owner: TClass; const Index: Integer): Pointer;
|
||||
@ -907,6 +912,7 @@ begin
|
||||
senrLineChange : FLineChangeNotificationList.Add(AHandler);
|
||||
senrLineCount : FLineRangeNotificationList.Add(AHandler);
|
||||
senrTextEdit: FLineEditNotificationList.Add(TMethod(AHandler));
|
||||
senrHighlightChanged: FLineInvalidateNotificationList.Add(TMethod(AHandler));
|
||||
senrBeginUpdate : FOnChangingList.Add(AHandler);
|
||||
senrEndUpdate : FOnChangeList.Add(AHandler);
|
||||
senrCleared : FOnClearedList.Add(AHandler);
|
||||
@ -920,6 +926,7 @@ begin
|
||||
senrLineChange : FLineChangeNotificationList.Remove(AHandler);
|
||||
senrLineCount : FLineRangeNotificationList.Remove(AHandler);
|
||||
senrTextEdit: FLineEditNotificationList.Remove(TMethod(AHandler));
|
||||
senrHighlightChanged: FLineInvalidateNotificationList.Remove(TMethod(AHandler));
|
||||
senrBeginUpdate : FOnChangingList.Remove(AHandler);
|
||||
senrEndUpdate : FOnChangeList.Remove(AHandler);
|
||||
senrCleared : FOnClearedList.Remove(AHandler);
|
||||
@ -933,6 +940,7 @@ begin
|
||||
FLineRangeNotificationList.AddCopyFrom(OtherLines.FLineRangeNotificationList, AOwner);
|
||||
FLineChangeNotificationList.AddCopyFrom(OtherLines.FLineChangeNotificationList, AOwner);
|
||||
FLineEditNotificationList.AddCopyFrom(OtherLines.FLineEditNotificationList, AOwner);
|
||||
FLineInvalidateNotificationList.AddCopyFrom(OtherLines.FLineInvalidateNotificationList, AOwner);
|
||||
FUndoRedoAddedNotificationList.AddCopyFrom(OtherLines.FUndoRedoAddedNotificationList, AOwner);
|
||||
FOnChangeList.AddCopyFrom(OtherLines.FOnChangeList, AOwner);
|
||||
FOnChangingList.AddCopyFrom(OtherLines.FOnChangingList, AOwner);
|
||||
@ -944,6 +952,7 @@ begin
|
||||
FLineRangeNotificationList.RemoveAllMethodsOfObject(AOwner);
|
||||
FLineChangeNotificationList.RemoveAllMethodsOfObject(AOwner);
|
||||
FLineEditNotificationList.RemoveAllMethodsOfObject(AOwner);
|
||||
FLineInvalidateNotificationList.RemoveAllMethodsOfObject(AOwner);
|
||||
FUndoRedoAddedNotificationList.RemoveAllMethodsOfObject(AOwner);
|
||||
FOnChangeList.RemoveAllMethodsOfObject(AOwner);
|
||||
FOnChangingList.RemoveAllMethodsOfObject(AOwner);
|
||||
@ -1085,6 +1094,8 @@ begin
|
||||
senrEditAction:
|
||||
FLineEditNotificationList.CallRangeNotifyEvents(ASender, aIndex, // aindex is mis-named (linepos) for edit action
|
||||
aBytePos, aLen, aCount, aTxt);
|
||||
senrHighlightChanged:
|
||||
FLineInvalidateNotificationList.CallRangeNotifyEvents(ASender, aIndex, aCount);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1108,10 +1119,35 @@ const
|
||||
constructor TSynEditStringMemory.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FRangeListLock := 0;
|
||||
AttributeSize := 0;
|
||||
FRangeList := nil;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringMemory.InsertRows(AIndex, ACount: Integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// Managed lists to get Mave, Count, instead of InsertRows
|
||||
inc(FRangeListLock);
|
||||
inherited InsertRows(AIndex, ACount);
|
||||
dec(FRangeListLock);
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.InsertedLines(AIndex, ACount);
|
||||
end;
|
||||
|
||||
procedure TSynEditStringMemory.DeleteRows(AIndex, ACount: Integer);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// Managed lists to get Mave, Count, instead of InsertRows
|
||||
inc(FRangeListLock);
|
||||
inherited DeleteRows(AIndex, ACount);
|
||||
dec(FRangeListLock);
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.DeletedLines(AIndex, ACount);
|
||||
end;
|
||||
|
||||
procedure TSynEditStringMemory.Move(AFrom, ATo, ALen: Integer);
|
||||
var
|
||||
Len, i: Integer;
|
||||
@ -1130,13 +1166,24 @@ end;
|
||||
|
||||
procedure TSynEditStringMemory.SetCount(const AValue: Integer);
|
||||
var
|
||||
i : Integer;
|
||||
OldCount, i : Integer;
|
||||
begin
|
||||
If Count = AValue then exit;
|
||||
for i:= AValue to Count-1 do Strings[i]:='';
|
||||
for i:= AValue to Count-1 do
|
||||
Strings[i]:='';
|
||||
OldCount := Count;
|
||||
inherited SetCount(AValue);
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.Count := AValue;
|
||||
if FRangeListLock = 0 then begin
|
||||
if OldCount > Count then begin
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.DeletedLines(Count, OldCount - Count);
|
||||
end else begin
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.InsertedLines(OldCount, Count - OldCount);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynEditStringMemory.GetAttributeSize: Integer;
|
||||
@ -1161,8 +1208,12 @@ begin
|
||||
end;
|
||||
|
||||
procedure TSynEditStringMemory.SetString(Index: Integer; const AValue: String);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
(PString(Mem + Index * FAttributeSize))^ := AValue;
|
||||
for i := 0 to length(FRangeList) - 1 do
|
||||
FRangeList[i].Data.LineTextChanged(Index);
|
||||
end;
|
||||
|
||||
function TSynEditStringMemory.ItemSize: Integer;
|
||||
@ -1184,7 +1235,7 @@ begin
|
||||
Result := (PObject(Mem + Index * FAttributeSize + SizeOf(String)))^;
|
||||
end;
|
||||
|
||||
function TSynEditStringMemory.GetRange(Index: TClass): TSynEditStorageMem;
|
||||
function TSynEditStringMemory.GetRange(Index: TClass): TSynManagedStorageMem;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@ -1199,7 +1250,7 @@ begin
|
||||
(PObject(Mem + Index * FAttributeSize + SizeOf(String)))^ := AValue;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringMemory.SetRange(Index: TClass; const AValue: TSynEditStorageMem);
|
||||
procedure TSynEditStringMemory.SetRange(Index: TClass; const AValue: TSynManagedStorageMem);
|
||||
var
|
||||
i, j: Integer;
|
||||
begin
|
||||
@ -1208,23 +1259,30 @@ begin
|
||||
dec(i);
|
||||
|
||||
if i < 0 then begin
|
||||
i := length(FRangeList);
|
||||
SetLength(FRangeList, i + 1);
|
||||
FRangeList[i].Index := Index;
|
||||
if AValue = nil then begin
|
||||
debugln('Removing none existent range');
|
||||
exit;
|
||||
end;
|
||||
j := length(FRangeList);
|
||||
SetLength(FRangeList, j + 1);
|
||||
FRangeList[j].Data := AValue;
|
||||
FRangeList[j].Index := Index;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if AValue <> nil then
|
||||
DebugLn(['TSynEditStringMemory.SetRange - Overwriting old range at index=', i, ' index=', dbgs(Index)]);
|
||||
|
||||
FRangeList[i].Data := AValue;
|
||||
FRangeList[i].Data := AValue;
|
||||
if AValue = nil then begin
|
||||
for j := i to length(FRangeList) - 2 do
|
||||
FRangeList[j] := FRangeList[j+1];
|
||||
SetLength(FRangeList, length(FRangeList) - 1);
|
||||
end;
|
||||
end;
|
||||
|
||||
if AValue <> nil then begin
|
||||
AValue.Capacity := Capacity;
|
||||
AValue.Count := Count;
|
||||
end else begin
|
||||
for j := i to length(FRangeList) - 2 do
|
||||
FRangeList[j] := FRangeList[j+1];
|
||||
SetLength(FRangeList, length(FRangeList) - 1);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -1272,5 +1330,19 @@ begin
|
||||
aLineBrkCnt, aText);
|
||||
end;
|
||||
|
||||
{ TSynManagedStorageMem }
|
||||
|
||||
procedure TSynManagedStorageMem.LineTextChanged(AIndex: Integer);
|
||||
begin // empty base class
|
||||
end;
|
||||
|
||||
procedure TSynManagedStorageMem.InsertedLines(AIndex, ACount: Integer);
|
||||
begin // empty base class
|
||||
end;
|
||||
|
||||
procedure TSynManagedStorageMem.DeletedLines(AIndex, ACount: Integer);
|
||||
begin // empty base class
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user