diff --git a/components/lazedit/textmategrammar.pas b/components/lazedit/textmategrammar.pas index c2801722ee..bb324772b6 100644 --- a/components/lazedit/textmategrammar.pas +++ b/components/lazedit/textmategrammar.pas @@ -413,6 +413,10 @@ type FSampleTextFile: String; FLangName: string; + FRegExMatchFoldBegin, FRegExMatchFoldEnd: TRegExpr; + MatchFoldBegin, MatchFoldEnd: String; + + FMainPatternCount: integer; FMainPatternList: TTextMatePatternList; FPatternRepo: TTextMatePatternMap; @@ -463,6 +467,8 @@ type procedure Next; function IsAtEol: boolean; procedure NextToEol; + function IsFoldBegin: boolean; + function IsFoldEnd: boolean; property CurrentTokenPos: integer read FCurrentTokenPos; property NextTokenPos: integer read FNextTokenPos; @@ -2339,6 +2345,8 @@ begin FPatternRepo.Free; FTheEmptyPattern.Free; FOtherGrammars.Free; + FRegExMatchFoldBegin.Free; + FRegExMatchFoldEnd.Free; end; procedure TTextMateGrammar.ParseGrammar(AGrammarDef: String); @@ -2369,6 +2377,14 @@ begin FRootPattern.FName := jsKeyAsString(JSonDef, 'name'); FRootPattern.ScopeName := jsKeyAsString(JSonDef, 'scopeName'); + + MatchFoldBegin := jsKeyAsString(JSonDef, 'foldingStartMarker'); + MatchFoldEnd := jsKeyAsString(JSonDef, 'foldingStopMarker'); + if MatchFoldBegin <> '' then + FRootPattern.DoInitRegex(FRegExMatchFoldBegin, MatchFoldBegin, 'foldingStartMarker'); + if MatchFoldEnd <> '' then + FRootPattern.DoInitRegex(FRegExMatchFoldEnd, MatchFoldEnd, 'foldingStopMarker'); + // language file? if JSonDef.IndexOfName('contributes') >= 0 then begin try @@ -2625,5 +2641,29 @@ begin FCurrentTokenPos := Length(FLineText) + 1; end; +function TTextMateGrammar.IsFoldBegin: boolean; +begin + if MatchFoldBegin = '' then + exit(false); + try + FRegExMatchFoldBegin.InputString := FLineText; + Result := FRegExMatchFoldBegin.Exec; + except + Result := False; + end; +end; + +function TTextMateGrammar.IsFoldEnd: boolean; +begin + if MatchFoldEnd = '' then + exit(false); + try + FRegExMatchFoldEnd.InputString := FLineText; + Result := FRegExMatchFoldEnd.Exec; + except + Result := False; + end; +end; + end. diff --git a/components/synedit/syntextmatesyn.pas b/components/synedit/syntextmatesyn.pas index 30bcfe9894..3e1a63e234 100644 --- a/components/synedit/syntextmatesyn.pas +++ b/components/synedit/syntextmatesyn.pas @@ -13,13 +13,29 @@ uses // LazEdit TextMateGrammar, // SynEdit - SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes; + SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes, SynEditTextBase; type TNameAttributesMap = specialize TFPGMapObject; TGrammarLoadEvent = procedure(AGrammarFile, AGrammarPath: String; out AGrammarDef: String); + TSynTextMateRangeInfo = record + FoldLevel: Smallint; + end; + + { TSynHighlighterTextMateRangeList } + + TSynHighlighterTextMateRangeList = class(TSynHighlighterRangeList) + private + FItemOffset: integer; + function GetRangeInfo(Index: Integer): TSynTextMateRangeInfo; + procedure SetRangeInfo(Index: Integer; AValue: TSynTextMateRangeInfo); + public + constructor Create; + property RangeInfo[Index: Integer]: TSynTextMateRangeInfo read GetRangeInfo write SetRangeInfo; + end; + { TSynTextMateSyn } TSynTextMateSyn = class(TSynCustomFoldHighlighter) @@ -41,6 +57,7 @@ type const AnAttribInfo: TSynAttributeInfo; out AnUseId, AnUseObject: Boolean); private FCurrentRange: Integer; + FRangeInfo: TSynTextMateRangeInfo; FCurrentTokenPos, FCurrentTokenLen: Integer; FCurrentTokenKind: integer; FCurrentAttrib: TSynHighlighterAttributes; @@ -48,6 +65,8 @@ type protected function GetInstanceLanguageName: string; override; + function CreateRangeList(ALines: TSynEditStringsBase): TSynHighlighterRangeList; override; + function UpdateRangeInfoAtLine(Index: Integer): Boolean; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; @@ -70,13 +89,8 @@ type procedure ResetRange; override; function GetRange: Pointer; override; - - function FoldBlockOpeningCount(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload; - function FoldBlockClosingCount(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload; function FoldBlockEndLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload; function FoldBlockMinLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; override; overload; - function FoldBlockNestedTypes(ALineIndex: TLineIdx; ANestIndex: Integer; - out AType: Pointer; const AFilter: TSynFoldBlockFilter): boolean; override; overload; property OnLoadGrammarFile: TGrammarLoadEvent read FOnLoadGrammarFile write FOnLoadGrammarFile; property GrammarPath: String read FGrammarPath write SetGrammarPath; @@ -86,6 +100,30 @@ type implementation +{ TSynHighlighterTextMateRangeList } + +function TSynHighlighterTextMateRangeList.GetRangeInfo(Index: Integer + ): TSynTextMateRangeInfo; +begin + if (Index < 0) or (Index >= Count) then + Result := Default(TSynTextMateRangeInfo) + else + Result := TSynTextMateRangeInfo((ItemPointer[Index] + FItemOffset)^); +end; + +procedure TSynHighlighterTextMateRangeList.SetRangeInfo(Index: Integer; + AValue: TSynTextMateRangeInfo); +begin + TSynTextMateRangeInfo((ItemPointer[Index] + FItemOffset)^) := AValue; +end; + +constructor TSynHighlighterTextMateRangeList.Create; +begin + inherited; + FItemOffset := ItemSize; + ItemSize := FItemOffset + SizeOf(TSynTextMateRangeInfo); +end; + { TSynTextMateSyn } function TSynTextMateSyn.LoadFile(AGrammarFile: String): String; @@ -133,6 +171,23 @@ begin Result := FTextMateGrammar.LanguageName; end; +function TSynTextMateSyn.CreateRangeList(ALines: TSynEditStringsBase + ): TSynHighlighterRangeList; +begin + Result := TSynHighlighterTextMateRangeList.Create; +end; + +function TSynTextMateSyn.UpdateRangeInfoAtLine(Index: Integer): Boolean; +var + r: TSynTextMateRangeInfo; +begin + Result := inherited; + r := TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[Index]; + Result := Result + or (FRangeInfo.FoldLevel <> r.FoldLevel); + TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[Index] := FRangeInfo; +end; + procedure TSynTextMateSyn.DoPopulateAttributeInfo( Sender: TTextMateGrammar; APattern: TTextMatePattern; AContextName: String; var AnAttribInfo: TSynAttributeInfo); @@ -191,6 +246,8 @@ end; procedure TSynTextMateSyn.SetLine(const NewValue: String; LineNumber: Integer); +var + nd: TSynFoldNodeInfo; begin inherited SetLine(NewValue, LineNumber); @@ -201,6 +258,38 @@ begin FTextMateGrammar.SetLine(CurrentLineText, FCurrentRange); FCurrentRange := -2; + if FTextMateGrammar.IsFoldBegin then begin + if not FTextMateGrammar.IsFoldEnd then begin + inc(FRangeInfo.FoldLevel); + if IsCollectingNodeInfo then begin + nd := Default(TSynFoldNodeInfo); + nd.LineIndex := LineIndex; + nd.FoldGroup := 1; + nd.FoldLvlStart := FRangeInfo.FoldLevel - 1; + nd.FoldLvlEnd := FRangeInfo.FoldLevel; + nd.NestLvlStart := FRangeInfo.FoldLevel - 1; + nd.NestLvlEnd := FRangeInfo.FoldLevel; + nd.FoldAction := [sfaFold, sfaFoldFold, sfaOpen, sfaOpenFold]; + CollectingNodeInfoList.Add(nd); + end; + end; + end + else + if FTextMateGrammar.IsFoldEnd and (FRangeInfo.FoldLevel > 0) then begin + dec(FRangeInfo.FoldLevel); + if IsCollectingNodeInfo then begin + nd := Default(TSynFoldNodeInfo); + nd.LineIndex := LineIndex; + nd.FoldGroup := 1; + nd.FoldLvlStart := FRangeInfo.FoldLevel + 1; + nd.FoldLvlEnd := FRangeInfo.FoldLevel; + nd.NestLvlStart := FRangeInfo.FoldLevel + 1; + nd.NestLvlEnd := FRangeInfo.FoldLevel; + nd.FoldAction := [sfaFold, sfaFoldFold, sfaClose, sfaCloseFold]; + CollectingNodeInfoList.Add(nd); + end; + end; + if IsScanning then begin FTextMateGrammar.NextToEol; end @@ -266,11 +355,13 @@ end; procedure TSynTextMateSyn.SetRange(Value: Pointer); begin FCurrentRange := PtrUInt(Value); + FRangeInfo := TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[LineIndex-1]; end; procedure TSynTextMateSyn.ResetRange; begin FCurrentRange := -1; + FRangeInfo := Default(TSynTextMateRangeInfo); end; function TSynTextMateSyn.GetRange: Pointer; @@ -279,35 +370,25 @@ begin Result := Pointer(PtrUInt(FCurrentRange)); end; -function TSynTextMateSyn.FoldBlockOpeningCount(ALineIndex: TLineIdx; - const AFilter: TSynFoldBlockFilter): integer; -begin - Result := 0; -end; - -function TSynTextMateSyn.FoldBlockClosingCount(ALineIndex: TLineIdx; - const AFilter: TSynFoldBlockFilter): integer; -begin - Result := 0; -end; - function TSynTextMateSyn.FoldBlockEndLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; +var + RangeInfo: TSynTextMateRangeInfo; begin - Result := 0; + RangeInfo := TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[ALineIndex]; + Result := RangeInfo.FoldLevel; end; function TSynTextMateSyn.FoldBlockMinLevel(ALineIndex: TLineIdx; const AFilter: TSynFoldBlockFilter): integer; +var + RangeInfo: TSynTextMateRangeInfo; begin - Result := 0; -end; - -function TSynTextMateSyn.FoldBlockNestedTypes(ALineIndex: TLineIdx; - ANestIndex: Integer; out AType: Pointer; const AFilter: TSynFoldBlockFilter - ): boolean; -begin - Result := False; + RangeInfo := TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[ALineIndex-1]; + Result := RangeInfo.FoldLevel; + RangeInfo := TSynHighlighterTextMateRangeList(CurrentRanges).RangeInfo[ALineIndex]; + if Result > RangeInfo.FoldLevel then + Result := RangeInfo.FoldLevel; end; end. diff --git a/ide/editoroptions.pp b/ide/editoroptions.pp index e778c1bb1d..f9e338cd3c 100644 --- a/ide/editoroptions.pp +++ b/ide/editoroptions.pp @@ -3741,7 +3741,7 @@ begin CaretXY := Point(1,1); MappedAttributes := TStringList.Create; for j := 0 to tmlHighlighter.AttrCount - 1 do begin - n := tmlHighlighter.Attribute[j].StoredName; + n := tmlHighlighter.Attribute[j].StoredName+'.'; if strlicomp(pchar(n), pchar('comment.'), 8) = 0 then MappedAttributes.Add(n+'=Comment'); if strlicomp(pchar(n), pchar('string.'), 7) = 0 then MappedAttributes.Add(n+'=String'); if strlicomp(pchar(n), pchar('constant.numeric.'), 17) = 0 then MappedAttributes.Add(n+'=Number'); @@ -3750,8 +3750,6 @@ begin if strlicomp(pchar(n), pchar('key.'), 4) = 0 then MappedAttributes.Add(n+'=Reserved word'); if strlicomp(pchar(n), pchar('entity.name.'), 12) = 0 then MappedAttributes.Add(n+'=Identifier'); if strlicomp(pchar(n), pchar('identifier.'), 11) = 0 then MappedAttributes.Add(n+'=Identifier'); - - if strlicomp(pchar(n), pchar('comment.'), 8) = 0 then MappedAttributes.Add(n+'=Comment'); end; end; Add(NewInfo);