diff --git a/components/lazedit/lazedit.lpk b/components/lazedit/lazedit.lpk index 3ea632d0e4..52c4e3b9cb 100644 --- a/components/lazedit/lazedit.lpk +++ b/components/lazedit/lazedit.lpk @@ -40,6 +40,10 @@ Additional licenses may be granted in each individual file. See the headers in e + + + + diff --git a/components/lazedit/lazedit.pas b/components/lazedit/lazedit.pas index 36ead4a199..2fd60301eb 100644 --- a/components/lazedit/lazedit.pas +++ b/components/lazedit/lazedit.pas @@ -8,7 +8,8 @@ unit LazEdit; interface uses - TextMateGrammar, xHyperLinksDecorator, xregexpr, xregexpr_unicodedata, LazEditMiscProcs; + TextMateGrammar, xHyperLinksDecorator, xregexpr, xregexpr_unicodedata, LazEditMiscProcs, + LazEditHighlighterUtils; implementation diff --git a/components/lazedit/lazedithighlighterutils.pas b/components/lazedit/lazedithighlighterutils.pas new file mode 100644 index 0000000000..0d87898bf8 --- /dev/null +++ b/components/lazedit/lazedithighlighterutils.pas @@ -0,0 +1,231 @@ +{ + ***************************************************************************** + This file is part of the LazEdit package from the Lazarus IDE. + + This content of this file is licensensed: Modified LGPL-2 + Or at the users choice: Modified LGPL-3 + See the file COPYING.modifiedLGPL.txt, included in the Lazarus distribution, + for details about the license. + + Alternatively, the contents of this file may be used under the terms of the + Mozilla Public License Version 1.1 http://www.mozilla.org/MPL/ + + A copy used under either License can have the other Licenses removed from this + header. A note should be added that the original file is available with the + above choice of License. + ***************************************************************************** +} +unit LazEditHighlighterUtils; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fgl, LazClasses, Generics.Collections, Generics.Defaults; + +type + + { TLazHighlighterRange } + + TLazHighlighterRange = class + protected + function DoCompare(Range: TLazHighlighterRange; ASize: integer): integer; inline; + function Compare(Range: TLazHighlighterRange): integer; virtual; + public + constructor Create(Template: TLazHighlighterRange); virtual; + procedure Assign(Src: TLazHighlighterRange); virtual; abstract; + end; + TLazHighlighterRangeClass = class of TLazHighlighterRange; + + { TLazHighlighterRanges } + + TLazHighlighterRanges = class(TRefCountedObject) + constructor Create; virtual; + destructor Destroy; override; + function GetEqual(ARange: TLazHighlighterRange): TLazHighlighterRange; virtual; abstract; + + procedure Allocate; deprecated 'use AddReference // will be removed in 5.99'; + procedure Release; deprecated 'use ReleaseReference // will be removed in 5.99'; + end; + TLazHighlighterRangesClass = class of TLazHighlighterRanges; + + { TLazHighlighterRangeForDictionary } + + TLazHighlighterRangeForDictionary = class(TLazHighlighterRange) + function GetHashCode(AnInitVal: UInt32 = 0): UInt32; reintroduce; virtual; + function GetHashCodeWithoutClass(AnInitVal: UInt32 = 0): UInt32; + end; + + { TLazHighlighterRangesDictionary } + + TLazHighlighterRangesDictionary = class(TLazHighlighterRanges) + private type + TLazHLrRangeDictionary = specialize TDictionary; + private + FRangeDict: TLazHLrRangeDictionary; + protected + procedure FreeItems; + public + constructor Create; override; + destructor Destroy; override; + function GetEqual(ARange: TLazHighlighterRange): TLazHighlighterRange; override; + end; + +function GetHighlighterRangesForHighlighter( + AnHighlighterClass: TClass {TSynCustomHighlighterClass}; + ANewClass: TLazHighlighterRangesClass + ): TLazHighlighterRanges; + +implementation + +type + TLazHighlighterRangesList = specialize TFPGMap; + + ILazHighlighterRangeEqualityComparer = specialize IEqualityComparer; + + { TLazHighlighterRangeEqualityComparer } + + TLazHighlighterRangeEqualityComparer = class(TInterfacedObject, ILazHighlighterRangeEqualityComparer) + public + function Equals(const ALeft, ARight: TLazHighlighterRangeForDictionary): Boolean; reintroduce; + function GetHashCode(const AValue: TLazHighlighterRangeForDictionary): UInt32; reintroduce; + end; + +var + LazHighlighterRangesList: TLazHighlighterRangesList; + +function GetHighlighterRangesForHighlighter(AnHighlighterClass: TClass; + ANewClass: TLazHighlighterRangesClass): TLazHighlighterRanges; +begin + if LazHighlighterRangesList = nil then + LazHighlighterRangesList := TLazHighlighterRangesList.Create; + + if not LazHighlighterRangesList.TryGetData(Pointer(AnHighlighterClass), Result) then begin + Result := ANewClass.Create; + LazHighlighterRangesList.Add(Pointer(AnHighlighterClass), Result); + end; +end; + +{ TLazHighlighterRangeEqualityComparer } + +function TLazHighlighterRangeEqualityComparer.Equals(const ALeft, + ARight: TLazHighlighterRangeForDictionary): Boolean; +begin + Result := ALeft.Compare(ARight) = 0; +end; + +function TLazHighlighterRangeEqualityComparer.GetHashCode( + const AValue: TLazHighlighterRangeForDictionary): UInt32; +begin + Result := AValue.GetHashCode; +end; + +{ TLazHighlighterRange } + +function TLazHighlighterRange.DoCompare(Range: TLazHighlighterRange; ASize: integer): integer; +begin + Result := InstanceSize - Range.InstanceSize; + if Result = 0 then + Result := CompareByte(Pointer(Self)^, Pointer(Range)^, ASize); +end; + +function TLazHighlighterRange.Compare(Range: TLazHighlighterRange): integer; +begin + Result := DoCompare(Range, InstanceSize); +end; + +constructor TLazHighlighterRange.Create(Template: TLazHighlighterRange); +begin + if (Template<>nil) and (ClassType<>Template.ClassType) then + raise Exception.Create('wrong tmpl class'); + if Template<>nil then + Assign(Template); +end; + +{ TLazHighlighterRanges } + +constructor TLazHighlighterRanges.Create; +begin + inherited Create; +end; + +destructor TLazHighlighterRanges.Destroy; +var + i: Integer; +begin + if LazHighlighterRangesList <> nil then begin + i := LazHighlighterRangesList.IndexOfData(Self); + assert(i>=0, 'TLazHighlighterRangesDictionary.Destroy: i>=0'); + LazHighlighterRangesList.Delete(i); + if LazHighlighterRangesList.Count = 0 then + FreeAndNil(LazHighlighterRangesList); + end; + inherited Destroy; +end; + +procedure TLazHighlighterRanges.Allocate; +begin + AddReference; +end; + +procedure TLazHighlighterRanges.Release; +begin + ReleaseReference; +end; + +{ TLazHighlighterRangeForDictionary } + +function TLazHighlighterRangeForDictionary.GetHashCode(AnInitVal: UInt32): UInt32; +begin + Result := TDefaultHashFactory.GetHashCode(Pointer(Self), InstanceSize, AnInitVal); +end; + +function TLazHighlighterRangeForDictionary.GetHashCodeWithoutClass(AnInitVal: UInt32): UInt32; +begin + Result := TDefaultHashFactory.GetHashCode(Pointer(Self) + SizeOf(Pointer), InstanceSize - SizeOf(Pointer), AnInitVal); +end; + +{ TLazHighlighterRangesDictionary } + +procedure TLazHighlighterRangesDictionary.FreeItems; +var + i: TLazHighlighterRangeForDictionary; +begin + for i in FRangeDict.Values do i.Free; + FRangeDict.Clear; +end; + +constructor TLazHighlighterRangesDictionary.Create; +begin + FRangeDict := TLazHLrRangeDictionary.Create(TLazHighlighterRangeEqualityComparer.Create); + inherited Create; +end; + +destructor TLazHighlighterRangesDictionary.Destroy; +begin + inherited Destroy; + FreeItems; + FRangeDict.Free; +end; + +function TLazHighlighterRangesDictionary.GetEqual(ARange: TLazHighlighterRange + ): TLazHighlighterRange; +var + DictRange: TLazHighlighterRangeForDictionary absolute ARange; + DictResult: TLazHighlighterRangeForDictionary absolute Result; +begin + Result := nil; + if ARange=nil then + exit; + + if not FRangeDict.TryGetValue(DictRange, DictResult) then begin + Result := TLazHighlighterRangeClass(DictRange.ClassType).Create(DictRange); + FRangeDict.Add(DictResult, DictResult); + end; +end; + +finalization + LazHighlighterRangesList.Free; +end. + diff --git a/components/synedit/synedithighlighterfoldbase.pas b/components/synedit/synedithighlighterfoldbase.pas index c0881a1394..c996304656 100644 --- a/components/synedit/synedithighlighterfoldbase.pas +++ b/components/synedit/synedithighlighterfoldbase.pas @@ -61,7 +61,7 @@ uses // LazUtils LazClasses, LazLoggerBase, LazTracer, // SynEdit - SynEditHighlighter, SynEditTypes, LazSynEditText; + SynEditHighlighter, SynEditTypes, LazSynEditText, LazEditHighlighterUtils; const NullRange = TSynEditRange(nil); @@ -366,7 +366,7 @@ type { TSynCustomHighlighterRange } - TSynCustomHighlighterRange = class + TSynCustomHighlighterRange = class(TLazHighlighterRangeForDictionary) private // TODO: either reduce to one level, or create subclass for 2nd level FCodeFoldStackSize: integer; // EndLevel @@ -376,15 +376,15 @@ type FRangeType: Pointer; FTop: TSynCustomCodeFoldBlock; public - constructor Create(Template: TSynCustomHighlighterRange); virtual; + constructor Create(Template: TLazHighlighterRange); override; destructor Destroy; override; - function Compare(Range: TSynCustomHighlighterRange): integer; virtual; + function Compare(Range: TLazHighlighterRange): integer; override; function Add(ABlockType: Pointer = nil; IncreaseLevel: Boolean = True): TSynCustomCodeFoldBlock; virtual; procedure Pop(DecreaseLevel: Boolean = True); virtual; function MaxFoldLevel: Integer; virtual; procedure Clear; virtual; - procedure Assign(Src: TSynCustomHighlighterRange); virtual; + procedure Assign(ASrc: TLazHighlighterRange); override; procedure WriteDebugReport; property FoldRoot: TSynCustomCodeFoldBlock read FTop write FTop; public @@ -397,9 +397,7 @@ type read FMinimumNestFoldBlockLevel; // write FMinimumNestFoldBlockLevel; property Top: TSynCustomCodeFoldBlock read FTop; end; - TSynCustomHighlighterRangeClass = class of TSynCustomHighlighterRange; - - TSynCustomHighlighterRanges = class; + TSynCustomHighlighterRangeClass = class of TSynCustomHighlighterRange deprecated 'use TLazHighlighterRangeClass // will be removed in 5.99'; { TSynCustomFoldHighlighter } @@ -419,14 +417,14 @@ type private FCodeFoldRange: TSynCustomHighlighterRange; FIsCollectingNodeInfo: boolean; - fRanges: TSynCustomHighlighterRanges; + fRanges: TLazHighlighterRangesDictionary; FRootCodeFoldBlock: TSynCustomCodeFoldBlock; FFoldNodeInfoList: TLazSynFoldNodeInfoList; FCollectingNodeInfoList: TLazSynFoldNodeInfoList; procedure ClearFoldNodeList; protected // "Range" - function GetRangeClass: TSynCustomHighlighterRangeClass; virtual; + function GetRangeClass: TLazHighlighterRangeClass; virtual; procedure CreateRootCodeFoldBlock; virtual; // set RootCodeFoldBlock property CodeFoldRange: TSynCustomHighlighterRange read FCodeFoldRange; function TopCodeFoldBlockType(DownIndex: Integer = 0): Pointer; @@ -536,27 +534,22 @@ type end; - { TSynCustomHighlighterRanges } + { TSynCustomHighlighterRangeTree } - TSynCustomHighlighterRanges = class + TSynCustomHighlighterRangeTree = class(TLazHighlighterRanges) private - FAllocatedCount: integer; - FHighlighterClass: TSynCustomHighlighterClass; FItems: TAvlTree; public - constructor Create(TheHighlighterClass: TSynCustomHighlighterClass); + constructor Create; override; destructor Destroy; override; - function GetEqual(Range: TSynCustomHighlighterRange - ): TSynCustomHighlighterRange; - procedure Allocate; - procedure Release; - property HighlighterClass: TSynCustomHighlighterClass read FHighlighterClass; - property AllocatedCount: integer read FAllocatedCount; - end; + function GetEqual(Range: TLazHighlighterRange + ): TLazHighlighterRange; override; + end experimental; // replaced by TLazHighlighterRangesDictionary function CompareSynHighlighterRanges(Data1, Data2: Pointer): integer; function AllocateHighlighterRanges( - HighlighterClass: TSynCustomHighlighterClass): TSynCustomHighlighterRanges; + HighlighterClass: TSynCustomHighlighterClass): TLazHighlighterRangesDictionary; + deprecated 'use GetHighlighterRangesForHighlighter // will be removed in 5.99'; function dbgs(AFoldActions: TSynFoldActions): String; overload; function dbgs(ANode: TSynFoldNodeInfo):string; overload; @@ -585,38 +578,11 @@ begin Result:=Range1.Compare(Range2); end; -var - HighlighterRanges: TFPList = nil; - -function IndexOfHighlighterRanges( - HighlighterClass: TSynCustomHighlighterClass): integer; -begin - if HighlighterRanges=nil then - Result:=-1 - else begin - Result:=HighlighterRanges.Count-1; - while (Result>=0) - and (TSynCustomHighlighterRanges(HighlighterRanges[Result]).HighlighterClass - <>HighlighterClass) - do - dec(Result); - end; -end; - function AllocateHighlighterRanges( - HighlighterClass: TSynCustomHighlighterClass): TSynCustomHighlighterRanges; -var - i: LongInt; + HighlighterClass: TSynCustomHighlighterClass): TLazHighlighterRangesDictionary; begin - if HighlighterRanges=nil then HighlighterRanges:=TFPList.Create; - i:=IndexOfHighlighterRanges(HighlighterClass); - if i>=0 then begin - Result:=TSynCustomHighlighterRanges(HighlighterRanges[i]); - Result.Allocate; - end else begin - Result:=TSynCustomHighlighterRanges.Create(HighlighterClass); - HighlighterRanges.Add(Result); - end; + Result := TLazHighlighterRangesDictionary(GetHighlighterRangesForHighlighter(HighlighterClass, TLazHighlighterRangesDictionary)); + Result.AddReference; end; function dbgs(AFoldActions: TSynFoldActions): String; @@ -1711,10 +1677,13 @@ constructor TSynCustomFoldHighlighter.Create(AOwner: TComponent); begin SetLength(FFoldConfig, GetFoldConfigInternalCount); InitFoldConfig; - fRanges:=AllocateHighlighterRanges(TSynCustomHighlighterClass(ClassType)); + fRanges := TLazHighlighterRangesDictionary( + GetHighlighterRangesForHighlighter(TSynCustomHighlighterClass(ClassType), TLazHighlighterRangesDictionary) + ); + fRanges.AddReference; CreateRootCodeFoldBlock; inherited Create(AOwner); - FCodeFoldRange:=GetRangeClass.Create(nil); + FCodeFoldRange:=TSynCustomHighlighterRange(GetRangeClass.Create(nil)); FCodeFoldRange.FoldRoot := FRootCodeFoldBlock; FFoldNodeInfoList := nil;; end; @@ -1726,7 +1695,7 @@ begin FreeAndNil(FCodeFoldRange); FreeAndNil(FRootCodeFoldBlock); ReleaseRefAndNil(FFoldNodeInfoList); - fRanges.Release; + fRanges.ReleaseReference; FFoldConfig := nil; end; @@ -2109,7 +2078,7 @@ begin Result := TLazSynFoldNodeInfoList.Create; end; -function TSynCustomFoldHighlighter.GetRangeClass: TSynCustomHighlighterRangeClass; +function TSynCustomFoldHighlighter.GetRangeClass: TLazHighlighterRangeClass; begin Result:=TSynCustomHighlighterRange; end; @@ -2474,7 +2443,7 @@ end; { TSynCustomHighlighterRange } constructor TSynCustomHighlighterRange.Create( - Template: TSynCustomHighlighterRange); + Template: TLazHighlighterRange); begin if (Template<>nil) and (ClassType<>Template.ClassType) then RaiseGDBException(''); @@ -2488,29 +2457,9 @@ begin inherited Destroy; end; -function TSynCustomHighlighterRange.Compare(Range: TSynCustomHighlighterRange - ): integer; +function TSynCustomHighlighterRange.Compare(Range: TLazHighlighterRange): integer; begin - if RangeType < Range.RangeType then - Result:=1 - else if RangeType > Range.RangeType then - Result:=-1 - else if Pointer(FTop) < Pointer(Range.FTop) then - Result:= -1 - else if Pointer(FTop) > Pointer(Range.FTop) then - Result:= 1 - else - Result := FMinimumNestFoldBlockLevel - Range.FMinimumNestFoldBlockLevel; - if Result <> 0 then - exit; - Result := FNestFoldStackSize - Range.FNestFoldStackSize; - if Result <> 0 then - exit; - - Result := FMinimumCodeFoldBlockLevel - Range.FMinimumCodeFoldBlockLevel; - if Result <> 0 then - exit; - Result := FCodeFoldStackSize - Range.FCodeFoldStackSize; + Result := DoCompare(Range, TSynCustomHighlighterRange.InstanceSize); end; function TSynCustomHighlighterRange.Add(ABlockType: Pointer; @@ -2563,7 +2512,8 @@ begin FTop:=nil; end; -procedure TSynCustomHighlighterRange.Assign(Src: TSynCustomHighlighterRange); +procedure TSynCustomHighlighterRange.Assign(ASrc: TLazHighlighterRange); +var Src: TSynCustomHighlighterRange absolute ASrc; begin if (Src<>nil) and (Src<>TSynCustomHighlighterRange(NullRange)) then begin FTop := Src.FTop; @@ -2591,29 +2541,22 @@ begin FTop.WriteDebugReport; end; -{ TSynCustomHighlighterRanges } +{ TSynCustomHighlighterRangeTree } -constructor TSynCustomHighlighterRanges.Create( - TheHighlighterClass: TSynCustomHighlighterClass); +constructor TSynCustomHighlighterRangeTree.Create; begin - Allocate; FItems:=TAvlTree.Create(@CompareSynHighlighterRanges); + inherited Create; end; -destructor TSynCustomHighlighterRanges.Destroy; +destructor TSynCustomHighlighterRangeTree.Destroy; begin - if HighlighterRanges<>nil then begin - HighlighterRanges.Remove(Self); - if HighlighterRanges.Count=0 then - FreeAndNil(HighlighterRanges); - end; FItems.FreeAndClear; FreeAndNil(FItems); inherited Destroy; end; -function TSynCustomHighlighterRanges.GetEqual(Range: TSynCustomHighlighterRange - ): TSynCustomHighlighterRange; +function TSynCustomHighlighterRangeTree.GetEqual(Range: TLazHighlighterRange): TLazHighlighterRange; var Node: TAvlTreeNode; begin @@ -2623,22 +2566,11 @@ begin Result:=TSynCustomHighlighterRange(Node.Data); end else begin // add a copy - Result:=TSynCustomHighlighterRangeClass(Range.ClassType).Create(Range); + Result:=TLazHighlighterRangeClass(Range.ClassType).Create(Range); FItems.Add(Result); //if FItems.Count mod 32 = 0 then debugln(['FOLDRANGE Count=', FItems.Count]); end; - //debugln('TSynCustomHighlighterRanges.GetEqual A ',dbgs(Node),' ',dbgs(Result.Compare(Range)),' ',dbgs(Result.CodeFoldStackSize)); -end; - -procedure TSynCustomHighlighterRanges.Allocate; -begin - inc(FAllocatedCount); -end; - -procedure TSynCustomHighlighterRanges.Release; -begin - dec(FAllocatedCount); - if FAllocatedCount=0 then Free; + //debugln('TSynCustomHighlighterRangeTree.GetEqual A ',dbgs(Node),' ',dbgs(Result.Compare(Range)),' ',dbgs(Result.CodeFoldStackSize)); end; { TSynCustomFoldConfig } diff --git a/components/synedit/synhighlighterpas.pp b/components/synedit/synhighlighterpas.pp index 705f3e6060..10746a6385 100644 --- a/components/synedit/synhighlighterpas.pp +++ b/components/synedit/synhighlighterpas.pp @@ -52,9 +52,9 @@ unit SynHighlighterPas; interface uses - SysUtils, Classes, fgl, Registry, Graphics, SynEditHighlighterFoldBase, + SysUtils, Classes, fgl, Registry, Graphics, Generics.Defaults, SynEditHighlighterFoldBase, SynEditMiscProcs, SynEditTypes, SynEditHighlighter, SynEditTextBase, - SynEditStrConst, SynEditMiscClasses, LazLoggerBase, LazEditMiscProcs; + SynEditStrConst, SynEditMiscClasses, LazLoggerBase, LazEditMiscProcs, LazEditHighlighterUtils; type TSynPasStringMode = (spsmDefault, spsmStringOnly, spsmNone); @@ -552,8 +552,8 @@ type procedure SetBracketNestLevel(AValue: integer); inline; public procedure Clear; override; - function Compare(Range: TSynCustomHighlighterRange): integer; override; - procedure Assign(Src: TSynCustomHighlighterRange); override; + function Compare(Range: TLazHighlighterRange): integer; override; + procedure Assign(Src: TLazHighlighterRange); override; function MaxFoldLevel: Integer; override; procedure ResetBracketNestLevel; procedure IncBracketNestLevel; @@ -870,7 +870,7 @@ type procedure EndStatementLastLine(ACurTfb: TPascalCodeFoldBlockType; ACloseFolds: TPascalCodeFoldBlockTypes); inline; // "Range" - function GetRangeClass: TSynCustomHighlighterRangeClass; override; + function GetRangeClass: TLazHighlighterRangeClass; override; procedure CreateRootCodeFoldBlock; override; function CreateRangeList(ALines: TSynEditStringsBase): TSynHighlighterRangeList; override; function UpdateRangeInfoAtLine(Index: Integer): Boolean; override; // Returns true if range changed @@ -7160,7 +7160,7 @@ begin - ord(low(TSynPasDividerDrawLocation)) + 1; end; -function TSynPasSyn.GetRangeClass: TSynCustomHighlighterRangeClass; +function TSynPasSyn.GetRangeClass: TLazHighlighterRangeClass; begin Result:=TSynPasSynRange; end; @@ -7463,27 +7463,12 @@ begin FTokenState := tsNone; end; -function TSynPasSynRange.Compare(Range: TSynCustomHighlighterRange): integer; +function TSynPasSynRange.Compare(Range: TLazHighlighterRange): integer; begin - Result:=inherited Compare(Range); - if Result<>0 then exit; - - Result:=ord(FTokenState)-ord(TSynPasSynRange(Range).FTokenState); - if Result<>0 then exit; - Result:=ord(FMode)-ord(TSynPasSynRange(Range).FMode); - if Result<>0 then exit; - Result:=Integer(FModeSwitches)-Integer(TSynPasSynRange(Range).FModeSwitches); - if Result<>0 then exit; - Result := FBracketNestLevel - TSynPasSynRange(Range).FBracketNestLevel; - if Result<>0 then exit; - Result := FRoundBracketNestLevel - TSynPasSynRange(Range).FRoundBracketNestLevel; - if Result<>0 then exit; - Result := FLastLineCodeFoldLevelFix - TSynPasSynRange(Range).FLastLineCodeFoldLevelFix; - if Result<>0 then exit; - Result := FPasFoldFixLevel - TSynPasSynRange(Range).FPasFoldFixLevel; + Result := DoCompare(Range, TSynPasSynRange.InstanceSize); end; -procedure TSynPasSynRange.Assign(Src: TSynCustomHighlighterRange); +procedure TSynPasSynRange.Assign(Src: TLazHighlighterRange); begin if (Src<>nil) and (Src<>TSynCustomHighlighterRange(NullRange)) then begin inherited Assign(Src);