SynEdit: Refactor TSynSelectedColorMergeResult - fix inheritance structure.

- This change affects compatibility for Highlighters: Code requiring the a tokens Attribute must now decide if it should call "GetTokenAttribute" / "GetEndOfLineAttribute" or "GetTokenAttributeEx" / "GetEndOfLineAttributeEx"
This commit is contained in:
Martin 2025-04-05 11:40:56 +02:00
parent 5abe12a280
commit 6690e16115
14 changed files with 100 additions and 60 deletions

View File

@ -25,6 +25,7 @@ uses
Classes, SysUtils, Graphics;
type
// TODO: TLazEditDisplayTokenBound is not yet supporting wrapped text - The Physical value may change
TLazEditDisplayTokenBound = record
Physical: Integer; // 1 based - May be in middle of char
Logical: Integer; // 1 based

View File

@ -34,7 +34,7 @@ interface
uses
Classes, SysUtils, Graphics, LCLProc, SynEditTypes, SynEditMiscProcs,
SynEditHighlighter, SynEditKeyCmds, SynEditTextBase;
SynEditHighlighter, SynEditKeyCmds, SynEditTextBase, LazEditTextAttributes;
type
TSynEditStrings = class;
@ -208,7 +208,7 @@ type
TLazSynDisplayTokenInfo = record
TokenStart: PChar;
TokenLength: integer;
TokenAttr: TSynHighlighterAttributes;
TokenAttr: TLazCustomEditTextAttribute;
TokenOrigin: TLazSynDisplayTokenOrigin;
end;

View File

@ -520,7 +520,7 @@ end;
function TLazSynPaintTokenBreaker.GetNextHighlighterTokenFromView(out
ATokenInfo: TLazSynDisplayTokenInfoEx; APhysEnd: Integer; ALogEnd: Integer): Boolean;
procedure InitSynAttr(var ATarget: TSynSelectedColorMergeResult; const ASource: TLazEditTextAttribute;
procedure InitSynAttr(var ATarget: TSynSelectedColorMergeResult; const ASource: TLazCustomEditTextAttribute;
const AnAttrStartX: TLazSynDisplayTokenBound);
const
NoEnd: TLazSynDisplayTokenBound = (Physical: -1; Logical: -1; Offset: 0);
@ -539,7 +539,6 @@ function TLazSynPaintTokenBreaker.GetNextHighlighterTokenFromView(out
ATarget.Style := []; // Font.Style; // currently always cleared
end;
// ATarget.MergeFinalStyle := True;
ATarget.StyleMask := [];
ATarget.StartX := AnAttrStartX;
ATarget.EndX := NoEnd;
end;

View File

@ -52,7 +52,7 @@ uses
SynEditHighlighter, SynEditTextBase, SynEditTextBuffer,
FileUtil, LazUTF8, FPCAdds, LCLType,
Graphics, Clipbrd,
SynEditMiscProcs, SynEditStrConst;
SynEditMiscProcs, SynEditStrConst, LazEditTextAttributes;
type
PSynReplaceCharsArray = ^TSynReplaceCharsArray;
@ -126,13 +126,13 @@ type
token into account }
procedure FormatBeforeFirstAttributeImmediate(BG, FG: TColor); virtual; abstract;
procedure FormatAfterLastAttributeImmediate; virtual; abstract;
procedure FormatAttributeInitImmediate(Attri: TSynHighlighterAttributes; IsSpace: Boolean); virtual; abstract;
procedure FormatAttributeDoneImmediate(Attri: TSynHighlighterAttributes; IsSpace: Boolean); virtual; abstract;
procedure FormatAttributeInitImmediate(Attri: TLazCustomEditTextAttribute; IsSpace: Boolean); virtual; abstract;
procedure FormatAttributeDoneImmediate(Attri: TLazCustomEditTextAttribute; IsSpace: Boolean); virtual; abstract;
{ Has to be overridden in descendant classes to add the formatted text of
the actual token text to the output buffer. }
procedure FormatToken(Token: string); virtual;
procedure FormatTokenImmediate(Token: String; Attri: TSynHighlighterAttributes; IsSpace: Boolean);
procedure FormatTokenImmediate(Token: String; Attri: TLazCustomEditTextAttribute; IsSpace: Boolean);
{ Has to be overridden in descendant classes to add a newline in the output
format to the output buffer. }
procedure FormatNewLine; virtual; abstract;
@ -166,7 +166,7 @@ type
of colors and font styles so the properties of the next token can be
added to the output buffer. }
procedure SetTokenAttribute(IsSpace: boolean;
Attri: TSynHighlighterAttributes); virtual;
Attri: TLazCustomEditTextAttribute); virtual;
function ValidatedColor(AColor, ADefColor: TColor): TColor;
public
{ Creates an instance of the exporter. }
@ -304,7 +304,7 @@ var
i, X, l: integer;
Token: string;
IsSpace: boolean;
Attri: TSynHighlighterAttributes;
Attri: TLazCustomEditTextAttribute;
TheLines: TSynEditStringsBase;
begin
// abort if not all necessary conditions are met
@ -344,7 +344,7 @@ begin
Highlighter.StartAtLineIndex(i - 1);
X := 1;
while not Highlighter.GetEOL do begin
Attri := Highlighter.GetTokenAttribute;
Attri := Highlighter.GetTokenAttributeEx;
Token := Highlighter.GetToken;
l := UTF8Length(Token);
@ -410,7 +410,7 @@ begin
end;
procedure TSynCustomExporter.FormatTokenImmediate(Token: String;
Attri: TSynHighlighterAttributes; IsSpace: Boolean);
Attri: TLazCustomEditTextAttribute; IsSpace: Boolean);
begin
{$ifdef debug_synexport}
debugln(['TSynCustomExporter.FormatTokenImmediate: Token = "', Token,'", IsSpace = ',IsSpace]);
@ -564,7 +564,7 @@ begin
end;
procedure TSynCustomExporter.SetTokenAttribute(IsSpace: boolean;
Attri: TSynHighlighterAttributes);
Attri: TLazCustomEditTextAttribute);
var
ChangedBG: boolean;
ChangedFG: boolean;

View File

@ -54,7 +54,7 @@ uses
// SynEdit
LazSynEditText, SynEditTypes, SynEditMiscClasses, SynEditMiscProcs,
SynEditPointClasses, SynEditHighlighter, SynEditHighlighterFoldBase,
SynEditKeyCmds;
SynEditKeyCmds, LazEditTextAttributes;
type
@ -758,7 +758,7 @@ const
LSTATE_DOTS = 4; // In Dots
LSTATE_EOL = 5; // at start of EOL
var
EolAttr: TSynHighlighterAttributes;
EolAttr: TLazCustomEditTextAttribute;
MergeStartX, MergeEndX: TLazSynDisplayTokenBound;
begin
case FLineState of
@ -772,7 +772,7 @@ begin
ATokenInfo.TokenLength := 3;
ATokenInfo.TokenOrigin := dtoAfterText;
if Assigned(CurrentTokenHighlighter)
then EolAttr := CurrentTokenHighlighter.GetEndOfLineAttribute
then EolAttr := CurrentTokenHighlighter.GetEndOfLineAttributeEx
else EolAttr := nil;
if EolAttr <> nil then begin
FTokenAttr.Assign(EolAttr);

View File

@ -304,8 +304,15 @@ type
function GetRange: Pointer; virtual;
function GetToken: String; virtual; abstract;
procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); virtual; abstract;
(* GetTokenAttribute / GetEndOfLineAttribute
The base attribute
* GetTokenAttributeEx / GetEndOfLineAttributeEx
The final attribute with merged modifiers (if HL has modifiers)
*)
function GetEndOfLineAttribute: TSynHighlighterAttributes; virtual; // valid after line was scanned to EOL
function GetEndOfLineAttributeEx: TLazCustomEditTextAttribute; virtual; // valid after line was scanned to EOL
function GetTokenAttribute: TSynHighlighterAttributes; virtual; abstract;
function GetTokenAttributeEx: TLazCustomEditTextAttribute; virtual;
function GetTokenKind: integer; virtual; abstract;
function GetTokenPos: Integer; virtual; abstract; // 0-based
function GetTokenLen: Integer; virtual;
@ -1140,6 +1147,16 @@ begin
Result := nil;
end;
function TSynCustomHighlighter.GetEndOfLineAttributeEx: TLazCustomEditTextAttribute;
begin
Result := GetEndOfLineAttribute;
end;
function TSynCustomHighlighter.GetTokenAttributeEx: TLazCustomEditTextAttribute;
begin
Result := GetTokenAttribute;
end;
function TSynCustomHighlighter.GetTokenLen: Integer;
var
x: PChar;

View File

@ -499,7 +499,7 @@ type
{ TSynSelectedColorMergeResult }
TSynSelectedColorMergeResult = class(TSynSelectedColor)
TSynSelectedColorMergeResult = class(TLazCustomEditTextAttribute)
private
// TSynSelectedColor.Style and StyleMask describe how to modify a style,
// but PaintLines creates an instance that contains an actual style (without mask)
@ -536,6 +536,7 @@ type
ANoneColor: TColor; IsFrame: Boolean = False): TColor;
property FrameSideOrigin[Side: TLazSynBorderSide]: TSynFrameEdges read GetFrameSideOrigin;
public
constructor Create(ACaption: PString; AStoredName: String = ''); overload; deprecated 'use Create without name // To be removed in 5.99';
destructor Destroy; override;
// boundaries for current paint
@ -1305,6 +1306,11 @@ begin
end;
end;
constructor TSynSelectedColorMergeResult.Create(ACaption: PString; AStoredName: String);
begin
Create;
end;
destructor TSynSelectedColorMergeResult.Destroy;
begin
CleanupMergeInfo;

View File

@ -423,14 +423,14 @@ begin
if not Result then begin
ATokenInfo.TokenStart := nil;
ATokenInfo.TokenLength := 0;
ATokenInfo.TokenAttr := CurrentTokenHighlighter.GetEndOfLineAttribute;
ATokenInfo.TokenAttr := CurrentTokenHighlighter.GetEndOfLineAttributeEx;
ATokenInfo.TokenOrigin := dtoAfterText;
Result := ATokenInfo.TokenAttr <> nil;
exit;
end;
CurrentTokenHighlighter.GetTokenEx(ATokenInfo.TokenStart, ATokenInfo.TokenLength);
ATokenInfo.TokenAttr := CurrentTokenHighlighter.GetTokenAttribute;
ATokenInfo.TokenAttr := CurrentTokenHighlighter.GetTokenAttributeEx;
ATokenInfo.TokenOrigin := dtoVirtualText;
CurrentTokenHighlighter.Next;
end;

View File

@ -47,7 +47,7 @@ interface
uses
Classes, SysUtils,
LCLIntf, LCLType, Graphics, ClipBrd,
SynEditHighlighter, SynEditExport, LazUtf8, SynEditStrConst;
SynEditHighlighter, SynEditExport, LazUtf8, SynEditStrConst, LazEditTextAttributes;
type
THTMLFontSize = (fs01, fs02, fs03, fs04, fs05, fs06, fs07, fsDefault); //eb 2000-10-12
@ -84,8 +84,8 @@ type
{end} //mh 2000-10-10
procedure FormatBeforeFirstAttributeImmediate(BG, FG: TColor); override;
procedure FormatAfterLastAttributeImmediate; override;
procedure FormatAttributeInitImmediate(Attri: TSynHighlighterAttributes; IsSpace: Boolean); override;
procedure FormatAttributeDoneImmediate(Attri: TSynHighlighterAttributes; IsSpace: Boolean); override;
procedure FormatAttributeInitImmediate(Attri: TLazCustomEditTextAttribute; IsSpace: Boolean); override;
procedure FormatAttributeDoneImmediate(Attri: TLazCustomEditTextAttribute; IsSpace: Boolean); override;
procedure FormatNewLine; override;
function GetFooter: string; override;
@ -404,7 +404,7 @@ begin
end;
procedure TSynExporterHTML.FormatAttributeInitImmediate(
Attri: TSynHighlighterAttributes; IsSpace: Boolean);
Attri: TLazCustomEditTextAttribute; IsSpace: Boolean);
var
Span, StyleStr: String;
FG, BG: TColor;
@ -428,7 +428,7 @@ begin
end;
procedure TSynExporterHTML.FormatAttributeDoneImmediate(
Attri: TSynHighlighterAttributes; IsSpace: Boolean);
Attri: TLazCustomEditTextAttribute; IsSpace: Boolean);
var
FG, BG: TColor;
StyleStr: String;

View File

@ -53,7 +53,7 @@ interface
uses
Classes, Graphics, SysUtils, Math, RegExpr,
SynEditStrConst, SynEditTypes, SynEditTextBase,
SynEditHighlighter,
SynEditHighlighter, LazEditTextAttributes,
{$IFDEF SynDebugMultiHL}LazLoggerBase{$ELSE}LazLoggerDummy{$ENDIF}, LazUTF8
;
@ -289,6 +289,7 @@ type
FTokenPos: integer;
FTokenKind: integer;
FTokenAttr: TSynHighlighterAttributes;
FTokenAttrEx: TLazCustomEditTextAttribute;
FRun: Integer;
FRunSectionInfo: Array of TRunSectionInfo;
FSampleSource: string;
@ -322,6 +323,7 @@ type
function GetToken: string; override;
procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
function GetTokenAttribute: TSynHighlighterAttributes; override;
function GetTokenAttributeEx: TLazCustomEditTextAttribute; override;
function GetTokenKind: integer; override;
function GetTokenPos: Integer; override; // 0-based
procedure SetLine(const NewValue: string; LineNumber: Integer); override;
@ -1356,6 +1358,11 @@ begin
Result := FTokenAttr;
end;
function TSynMultiSyn.GetTokenAttributeEx: TLazCustomEditTextAttribute;
begin
Result := FTokenAttrEx;
end;
function TSynMultiSyn.GetTokenKind: integer;
begin
Result := FTokenKind;
@ -1430,6 +1437,7 @@ begin
//debugln(['--- Next at ',FRun]);
FTokenPos := FRun;
FTokenAttr := nil;
FTokenAttrEx := nil;
FTokenKind := 0;
if FRun > FLineLen then
exit;
@ -1445,8 +1453,6 @@ begin
if idx < 0 then begin
//debugln(['*** XXXXX No section found XXXXX ***']);
FRun := FLineLen + 1;
FTokenAttr := nil;
FTokenKind := 0;
exit;
end;
@ -1455,19 +1461,19 @@ begin
if RSect.SectionIdx < 0 then begin
//debugln(['*** XXXXX section missing XXXXX ***']);
FRun := FLineLen + 1;
FTokenAttr := nil;
FTokenKind := 0;
exit;
end;
if (idx > 0) and (FRun < RSect.FirstChar) then begin
FTokenAttr := Schemes[idx-1].FMarkerAttri;
FTokenAttrEx := FTokenAttr;
FTokenKind := 1;
FRun := RSect.FirstChar;
//debugln([' start-token ', FRun]);
end
else if (idx > 0) and (FRun > RSect.LastChar) then begin
FTokenAttr := Schemes[idx-1].FMarkerAttri;
FTokenAttrEx := FTokenAttr;
FTokenKind := 1;
FRun := RSect.TokenLastChar + 1;
//debugln([' end-token ', FRun]);
@ -1490,6 +1496,7 @@ begin
until HL.GetEol;
if not HL.GetEol then begin
FTokenAttr := HL.GetTokenAttribute;
FTokenAttrEx := HL.GetTokenAttributeEx;
FTokenKind := idx * TokenKindPerHighlighter + HL.GetTokenKind;
FRun := Min(tkpos - RSect.VirtualStartPos + RSect.FirstChar + tklen,
RSect.LastChar + 1);
@ -1501,6 +1508,7 @@ begin
if (HL = nil) then begin
FTokenAttr := nil;
FTokenAttrEx := nil;
FTokenKind := 0;
FRun := RSect.LastChar + 1;
//debugln([' no HL ', FRun]);
@ -1673,6 +1681,7 @@ begin
fRun := 1;
FTokenPos := 1;
FTokenAttr := nil;
FTokenAttrEx := nil;
FTokenKind := 0;
//debugln(['>>>>> Setting Line ',FCurLineIndex,' = ',FLine]);
for i := 0 to high(FRunSectionInfo) do

View File

@ -53,8 +53,9 @@ interface
uses
SysUtils, Classes, fgl, Registry, Graphics, Generics.Defaults, SynEditHighlighterFoldBase,
SynEditMiscProcs, SynEditTypes, SynEditHighlighter, SynEditTextBase,
SynEditStrConst, SynEditMiscClasses, LazLoggerBase, LazEditMiscProcs, LazEditHighlighterUtils;
SynEditMiscProcs, SynEditTypes, SynEditHighlighter, SynEditTextBase, SynEditStrConst,
SynEditMiscClasses, LazLoggerBase, LazEditMiscProcs, LazEditHighlighterUtils,
LazEditTextAttributes;
type
TSynPasStringMode = (spsmDefault, spsmStringOnly, spsmNone);
@ -950,6 +951,7 @@ type
function GetToken: string; override;
procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
function GetTokenAttribute: TSynHighlighterAttributes; override;
function GetTokenAttributeEx: TLazCustomEditTextAttribute; override;
function GetTokenID: TtkTokenKind;
function GetTokenKind: integer; override;
function GetTokenPos: Integer; override;
@ -3950,10 +3952,7 @@ begin
AddAttribute(FCommentSlashAttri);
FIDEDirectiveAttri := TSynHighlighterAttributesModifier.Create(@SYNS_AttrIDEDirective, SYNS_XML_AttrIDEDirective);
AddAttribute(FIDEDirectiveAttri);
// FCurIDEDirectiveAttri, FCurCaseLabelAttri, FCurProcTypeDeclExtraAttr
// They are not available through the "Attribute" property (not added via AddAttribute
// But they are returned via GetTokenAttribute, so they should have a name.
FCurIDEDirectiveAttri := TSynSelectedColorMergeResult.Create(@SYNS_AttrIDEDirective, SYNS_XML_AttrIDEDirective);
FCurIDEDirectiveAttri := TSynSelectedColorMergeResult.Create;
fIdentifierAttri := TSynHighlighterAttributes.Create(@SYNS_AttrIdentifier, SYNS_XML_AttrIdentifier);
AddAttribute(fIdentifierAttri);
fKeyAttri := TSynHighlighterAttributes.Create(@SYNS_AttrReservedWord, SYNS_XML_AttrReservedWord);
@ -5720,21 +5719,13 @@ begin
Result := fTokenId;
end;
function TSynPasSyn.GetTokenAttribute: TSynHighlighterAttributes;
var
tid: TtkTokenKind;
i: Integer;
attr: TSynHighlighterAttributesModifier;
begin
tid := GetTokenID;
case tid of
case GetTokenID of
tkAsm: Result := fAsmAttri;
tkComment: Result := fCommentAttri;
tkIDEDirective: begin
FCurIDEDirectiveAttri.Assign(FCommentAttri);
FCurIDEDirectiveAttri.Merge(FIDEDirectiveAttri);
Result := FCurIDEDirectiveAttri;
end;
tkIDEDirective, tkComment:
Result := fCommentAttri;
tkIdentifier: begin
if eaGotoLabel in FTokenExtraAttribs then
Result := FGotoLabelAttr
@ -5751,9 +5742,25 @@ begin
tkUnknown: Result := fSymbolAttri;
else
Result := nil;
exit; // can't merge
end;
end;
function TSynPasSyn.GetTokenAttributeEx: TLazCustomEditTextAttribute;
var
tid: TtkTokenKind;
i: Integer;
attr: TSynHighlighterAttributesModifier;
begin
Result := GetTokenAttribute;
if Result = nil then
exit;
tid := GetTokenID;
if tid = tkIDEDirective then begin
FCurIDEDirectiveAttri.Assign(FCommentAttri);
FCurIDEDirectiveAttri.Merge(FIDEDirectiveAttri);
Result := FCurIDEDirectiveAttri;
end;
if FTokenIsCaseLabel and
( (tid in [tkIdentifier, tkNumber, tkString]) or

View File

@ -6,7 +6,7 @@ interface
uses
SysUtils, TestBase, SynEdit, SynEditHighlighterFoldBase, SynEditHighlighter,
SynEditMiscClasses, LazLoggerBase;
SynEditMiscClasses, LazLoggerBase, LazEditTextAttributes;
type
@ -198,7 +198,7 @@ end;
procedure TTestBaseHighlighterFoldBase.CheckTokensForLine(Name: String;
LineIdx: Integer; ExpTokens: array of TExpTokenInfo);
function AttrVal(a: TSynHighlighterAttributes): Integer;
function AttrVal(a: TLazCustomEditTextAttribute): Integer;
begin
if a = nil then exit(-1);
if a is TSynSelectedColorMergeResult then
@ -208,7 +208,7 @@ procedure TTestBaseHighlighterFoldBase.CheckTokensForLine(Name: String;
var
c: Integer;
e: TExpTokenInfo;
GotAttr: TSynHighlighterAttributes;
GotAttr: TLazCustomEditTextAttribute;
begin
FTheHighLighter.StartAtLineIndex(LineIdx);
c := 0;
@ -224,7 +224,7 @@ begin
AssertEquals(Name + ' ASSERT token-kind @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c)+' Src='+FTheHighLighter.GetToken+' @'+IntToStr(FTheHighLighter.GetTokenPos),
e.ExpKind, FTheHighLighter.GetTokenKind);
GotAttr := FTheHighLighter.GetTokenAttribute;
GotAttr := FTheHighLighter.GetTokenAttributeEx;
if etiAttr in e.Flags then
AssertEquals(Name + ' Attr @ TokenId Line='+IntToStr(LineIdx)+' pos='+IntToStr(c)+' Src='+FTheHighLighter.GetToken+' @'+IntToStr(FTheHighLighter.GetTokenPos),
AttrVal(e.ExpAttr), AttrVal(GotAttr))

View File

@ -7,7 +7,7 @@ interface
uses
Classes, SysUtils, Math, testregistry, TestBase, Forms, SynEditHighlighter,
SynHighlighterMulti, SynHighlighterLFM, SynHighlighterXML, SynHighlighterPas, SynEditKeyCmds,
LazSynEditText, SynEditTextBuffer, SynEditTypes, LazLoggerBase;
LazSynEditText, SynEditTextBuffer, SynEditTypes, LazLoggerBase, LazEditTextAttributes;
type
@ -264,7 +264,7 @@ procedure TTestHighlightMulti.CheckTokensForLine(Name: String; HL: TSynCustomHig
LineIdx: Integer; ExpAttr: array of TSynHighlighterAttributes);
var
c: Integer;
tk: TSynHighlighterAttributes;
tk: TLazCustomEditTextAttribute;
tkName: String;
begin
HL.StartAtLineIndex(LineIdx);
@ -275,9 +275,9 @@ begin
break;
end;
//DebugLn([HL.GetToken,' (',HL.GetTokenID ,') at ', HL.GetTokenPos]);
tk := HL.GetTokenAttribute;
if tk <> nil
then tkName := tk.StoredName
tk := HL.GetTokenAttributeEx;
if (tk <> nil) and (tk is TSynHighlighterAttributes)
then tkName := TSynHighlighterAttributes(tk).StoredName
else tkName := '<nil>';
AssertTrue(Format('%s Attrib Line=%d pos=%d exp=%s got=%s',
[Name, LineIdx, c, ExpAttr[c].StoredName, tkName]),

View File

@ -50,7 +50,8 @@ uses
// IdeIntf
LazIDEIntf, IDEImagesIntf, TextTools, IDETextConverter,
// IDE
DialogProcs, EditorOptions, CodeToolsOptions, SourceSynEditor, SourceMarks;
DialogProcs, EditorOptions, CodeToolsOptions, SourceSynEditor, SourceMarks,
LazEditTextAttributes;
type
@ -276,7 +277,7 @@ var
var
sToken: PChar;
nTokenLen: integer;
Attr: TSynHighlightElement;
Attr: TLazCustomEditTextAttribute;
CurForeground: TColor;
LeftText: string;
begin
@ -293,7 +294,7 @@ var
SetLength(s,nTokenLen);
if nTokenLen>0 then begin
System.Move(sToken^,s[1],nTokenLen);
attr := Highlighter.GetTokenAttribute;
attr := Highlighter.GetTokenAttributeEx;
CurForeground:=Attr.Foreground;
if CurForeground=clNone then
CurForeground:=TColor(ForegroundColor);