1018 lines
26 KiB
ObjectPascal
1018 lines
26 KiB
ObjectPascal
unit ATSynEdit_Adapter_EControl;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Graphics, ExtCtrls, ComCtrls,
|
|
Forms, Dialogs,
|
|
ATSynEdit,
|
|
ATSynEdit_CanvasProc,
|
|
ATSynEdit_Adapters,
|
|
ATSynEdit_Carets,
|
|
ATStringProc,
|
|
ATStringProc_TextBuffer,
|
|
ATStrings,
|
|
ecSyntAnal;
|
|
|
|
var
|
|
cAdapterTimerInterval: integer = 200;
|
|
|
|
type
|
|
{ TATRangeColored }
|
|
|
|
TATRangeColored = class
|
|
public
|
|
Pos1, Pos2: integer;
|
|
Token1, Token2: integer;
|
|
Color: TColor;
|
|
Rule: TecTagBlockCondition;
|
|
Active: array[0..Pred(cMaxStringsClients)] of boolean;
|
|
constructor Create(APos1, APos2, AToken1, AToken2: integer; AColor: TColor; ARule: TecTagBlockCondition);
|
|
end;
|
|
|
|
TATRangeCond = (cCondInside, cCondAtBound, cCondOutside);
|
|
|
|
type
|
|
{ TATAdapterEControl }
|
|
|
|
TATAdapterEControl = class(TATAdapterHilite)
|
|
private
|
|
EdList: TList;
|
|
AnClient: TecClientSyntAnalyzer;
|
|
Buffer: TATStringBuffer;
|
|
ListColors: TList;
|
|
Timer: TTimer;
|
|
FDynEnabled: boolean;
|
|
FBusy: boolean;
|
|
FOnLexerChange: TNotifyEvent;
|
|
FOnParseBegin: TNotifyEvent;
|
|
FOnParseDone: TNotifyEvent;
|
|
procedure DoAnalize(AEdit: TATSynEdit);
|
|
procedure DoFindTokenOverrideStyle(var ATokenStyle: TecSyntaxFormat;
|
|
ATokenIndex, AEditorIndex: integer);
|
|
procedure DoFoldAdd(AX, AY, AY2: integer; AStaple: boolean; const AHint: string);
|
|
procedure DoCalcParts(var AParts: TATLineParts; ALine, AX, ALen: integer;
|
|
AColorFont, AColorBG: TColor; var AColorAfter: TColor; AEditorIndex: integer);
|
|
procedure DoClearRanges;
|
|
function DoFindToken(APos: integer): integer;
|
|
procedure DoFoldFromLinesHidden;
|
|
procedure DoChangeLog(Sender: TObject; ALine, ACount: integer);
|
|
function GetRangeParent(R: TecTextRange): TecTextRange;
|
|
procedure GetTokenProps(token: TecSyntToken; out APntFrom, APntTo: TPoint; out
|
|
ATokenString, ATokenStyle: string);
|
|
function IsCaretInRange(AEdit: TATSynEdit; APos1, APos2: integer; ACond: TATRangeCond): boolean;
|
|
procedure SetPartStyleFromEcStyle(var part: TATLinePart; st: TecSyntaxFormat);
|
|
procedure UpdateEds;
|
|
function GetTokenColorBG(APos: integer; ADefColor: TColor; AEditorIndex: integer): TColor;
|
|
procedure TimerTimer(Sender: TObject);
|
|
procedure UpdateRanges;
|
|
procedure UpdateRangesActive(AEdit: TATSynEdit);
|
|
procedure UpdateSeps;
|
|
procedure UpdateRangesSublex;
|
|
procedure UpdateData;
|
|
procedure UpdateRangesFold;
|
|
function GetLexer: TecSyntAnalyzer;
|
|
procedure SetLexer(AAnalizer: TecSyntAnalyzer);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure AddEditor(AEdit: TATSynEdit);
|
|
property Lexer: TecSyntAnalyzer read GetLexer write SetLexer;
|
|
function LexerAtPos(Pnt: TPoint): TecSyntAnalyzer;
|
|
property DynamicHiliteEnabled: boolean read FDynEnabled write FDynEnabled;
|
|
//tokens
|
|
procedure GetTokenWithIndex(AIndex: integer; out APntFrom, APntTo: TPoint; out
|
|
ATokenString, ATokenStyle: string);
|
|
procedure GetTokenAtPos(Pnt: TPoint; out APntFrom, APntTo: TPoint; out
|
|
ATokenString, ATokenStyle: string);
|
|
//support for syntax-tree
|
|
property TreeBusy: boolean read FBusy;
|
|
procedure TreeFill(ATree: TTreeView);
|
|
procedure TreeShowItemForCaret(Tree: TTreeView; P: TPoint);
|
|
function TreeGetPositionOfRange(R: TecTextRange): TPoint;
|
|
function TreeGetRangeOfPosition(P: TPoint): TecTextRange;
|
|
public
|
|
procedure OnEditorCaretMove(Sender: TObject); override;
|
|
procedure OnEditorChange(Sender: TObject); override;
|
|
procedure OnEditorCalcHilite(Sender: TObject;
|
|
var AParts: TATLineParts;
|
|
ALineIndex, ACharIndex, ALineLen: integer;
|
|
var AColorAfterEol: TColor); override;
|
|
procedure OnEditorCalcPosColor(Sender: TObject;
|
|
AX, AY: integer; var AColor: TColor); override;
|
|
published
|
|
property OnLexerChange: TNotifyEvent read FOnLexerChange write FOnLexerChange;
|
|
property OnParseBegin: TNotifyEvent read FOnParseBegin write FOnParseBegin;
|
|
property OnParseDone: TNotifyEvent read FOnParseDone write FOnParseDone;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses Math;
|
|
|
|
const
|
|
cBorderEc: array[TecBorderLineType] of TATLineStyle = (
|
|
cLineStyleNone,
|
|
cLineStyleSolid,
|
|
cLineStyleDash,
|
|
cLineStyleDash,
|
|
cLineStyleDash,
|
|
cLineStyleDash,
|
|
cLineStyleSolid2px,
|
|
cLineStyleSolid2px,
|
|
cLineStyleWave,
|
|
cLineStyleDotted
|
|
);
|
|
|
|
{ TATRangeColored }
|
|
|
|
constructor TATRangeColored.Create(APos1, APos2, AToken1, AToken2: integer;
|
|
AColor: TColor; ARule: TecTagBlockCondition);
|
|
begin
|
|
Pos1:= APos1;
|
|
Pos2:= APos2;
|
|
Token1:= AToken1;
|
|
Token2:= AToken2;
|
|
Color:= AColor;
|
|
Rule:= ARule;
|
|
FillChar(Active, Sizeof(Active), 0);
|
|
end;
|
|
|
|
{ TATAdapterEControl }
|
|
|
|
procedure TATAdapterEControl.OnEditorCalcHilite(Sender: TObject;
|
|
var AParts: TATLineParts; ALineIndex, ACharIndex, ALineLen: integer;
|
|
var AColorAfterEol: TColor);
|
|
var
|
|
Ed: TATSynEdit;
|
|
Str: atString;
|
|
begin
|
|
Ed:= Sender as TATSynEdit;
|
|
AddEditor(Ed);
|
|
if not Assigned(AnClient) then Exit;
|
|
|
|
Str:= Copy(Ed.Strings.Lines[ALineIndex], ACharIndex, ALineLen);
|
|
ALineLen:= Length(Str);
|
|
|
|
AColorAfterEol:= clNone;
|
|
DoCalcParts(AParts, ALineIndex, ACharIndex-1, ALineLen,
|
|
Ed.Colors.TextFont,
|
|
clNone,
|
|
AColorAfterEol,
|
|
Ed.EditorIndex);
|
|
end;
|
|
|
|
procedure TATAdapterEControl.OnEditorCalcPosColor(Sender: TObject; AX,
|
|
AY: integer; var AColor: TColor);
|
|
var
|
|
Ed: TATSynEdit;
|
|
Pos: integer;
|
|
begin
|
|
Ed:= Sender as TATSynEdit;
|
|
Pos:= Buffer.CaretToStr(Point(AX, AY));
|
|
AColor:= GetTokenColorBG(Pos, AColor, Ed.EditorIndex);
|
|
end;
|
|
|
|
function TATAdapterEControl.IsCaretInRange(AEdit: TATSynEdit; APos1,
|
|
APos2: integer; ACond: TATRangeCond): boolean;
|
|
var
|
|
Caret: TATCaretItem;
|
|
Pos: integer;
|
|
i: integer;
|
|
ok: boolean;
|
|
begin
|
|
Result:= false;
|
|
if not FDynEnabled then Exit;
|
|
|
|
for i:= 0 to AEdit.Carets.Count-1 do
|
|
begin
|
|
Caret:= AEdit.Carets[i];
|
|
Pos:= Buffer.CaretToStr(Point(Caret.PosX, Caret.PosY));
|
|
|
|
case ACond of
|
|
cCondInside:
|
|
ok:= (Pos>=APos1) and (Pos<APos2);
|
|
cCondOutside:
|
|
ok:= (Pos<APos1) or (Pos>=APos2);
|
|
cCondAtBound:
|
|
ok:= (Pos=APos1) or (Pos=APos2);
|
|
else
|
|
ok:= false;
|
|
end;
|
|
|
|
if ok then
|
|
begin
|
|
Result:= true;
|
|
Exit
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TATAdapterEControl.GetTokenColorBG(APos: integer; ADefColor: TColor; AEditorIndex: integer): TColor;
|
|
var
|
|
Rng: TATRangeColored;
|
|
i: integer;
|
|
begin
|
|
Result:= ADefColor;
|
|
for i:= ListColors.Count-1 downto 0 do
|
|
begin
|
|
Rng:= TATRangeColored(ListColors[i]);
|
|
if not Rng.Active[AEditorIndex] then Continue;
|
|
if Rng.Rule<>nil then
|
|
if not (Rng.Rule.DynHighlight in [dhRange, dhRangeNoBound]) then
|
|
Continue;
|
|
|
|
if (APos>=Rng.Pos1) and (APos<Rng.Pos2) then
|
|
begin
|
|
Result:= Rng.Color;
|
|
Exit
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateRangesActive(AEdit: TATSynEdit);
|
|
var
|
|
Rng, RngOut: TATRangeColored;
|
|
i, j: integer;
|
|
act: boolean;
|
|
begin
|
|
for i:= 0 to ListColors.Count-1 do
|
|
begin
|
|
Rng:= TATRangeColored(ListColors[i]);
|
|
if Rng.Rule=nil then
|
|
begin
|
|
act:= true;
|
|
end
|
|
else
|
|
begin
|
|
if not (Rng.Rule.DynHighlight in [dhRange, dhRangeNoBound, dhBound]) then Continue;
|
|
case Rng.Rule.HighlightPos of
|
|
cpAny:
|
|
act:= true;
|
|
cpBound:
|
|
act:= IsCaretInRange(AEdit, Rng.Pos1, Rng.Pos2, cCondAtBound);
|
|
cpBoundTag:
|
|
act:= false;//todo
|
|
cpRange:
|
|
act:= IsCaretInRange(AEdit, Rng.Pos1, Rng.Pos2, cCondInside);
|
|
cpBoundTagBegin:
|
|
act:= false;//todo
|
|
cpOutOfRange:
|
|
act:= IsCaretInRange(AEdit, Rng.Pos1, Rng.Pos2, cCondOutside);
|
|
else
|
|
act:= false;
|
|
end;
|
|
end;
|
|
Rng.Active[AEdit.EditorIndex]:= act;
|
|
end;
|
|
|
|
//deactivate ranges by DynSelectMin
|
|
//cycle back, to see first nested ranges
|
|
for i:= ListColors.Count-1 downto 0 do
|
|
begin
|
|
Rng:= TATRangeColored(ListColors[i]);
|
|
if not Rng.Active[AEdit.EditorIndex] then Continue;
|
|
if Rng.Rule=nil then Continue;
|
|
if not Rng.Rule.DynSelectMin then Continue;
|
|
if Rng.Rule.DynHighlight<>dhBound then Continue;
|
|
//take prev ranges which contain this range
|
|
for j:= i-1 downto 0 do
|
|
begin
|
|
RngOut:= TATRangeColored(ListColors[j]);
|
|
if RngOut.Rule=Rng.Rule then
|
|
if RngOut.Active[AEdit.EditorIndex] then
|
|
if (RngOut.Pos1<=Rng.Pos1) and (RngOut.Pos2>=Rng.Pos2) then
|
|
RngOut.Active[AEdit.EditorIndex]:= false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.DoCalcParts(var AParts: TATLineParts; ALine, AX,
|
|
ALen: integer; AColorFont, AColorBG: TColor; var AColorAfter: TColor; AEditorIndex: integer);
|
|
var
|
|
partindex: integer;
|
|
//
|
|
procedure AddMissingPart(AOffset, ALen: integer);
|
|
var
|
|
part: TATLinePart;
|
|
strpos: integer;
|
|
begin
|
|
if ALen<=0 then Exit;
|
|
strpos:= Buffer.CaretToStr(Point(AX+AOffset, ALine));
|
|
FillChar(part{%H-}, SizeOf(part), 0);
|
|
part.Offset:= AOffset;
|
|
part.Len:= ALen;
|
|
part.ColorFont:= AColorFont;
|
|
part.ColorBG:= GetTokenColorBG(strpos, AColorBG, AEditorIndex);
|
|
AParts[partindex]:= part;
|
|
Inc(partindex);
|
|
end;
|
|
//
|
|
var
|
|
tokenStart, tokenEnd: TPoint;
|
|
mustOffset, startindex, lineoffset: integer;
|
|
token: TecSyntToken;
|
|
tokenStyle: TecSyntaxFormat;
|
|
part: TATLinePart;
|
|
nColor: TColor;
|
|
i: integer;
|
|
begin
|
|
partindex:= 0;
|
|
FillChar(part{%H-}, SizeOf(part), 0);
|
|
|
|
lineoffset:= Buffer.CaretToStr(Point(0, ALine));
|
|
startindex:= DoFindToken(lineoffset);
|
|
if startindex<0 then
|
|
startindex:= 0;
|
|
|
|
for i:= startindex to AnClient.TagCount-1 do
|
|
begin
|
|
token:= AnClient.Tags[i];
|
|
tokenStart:= Buffer.StrToCaret(token.StartPos);
|
|
tokenEnd:= Buffer.StrToCaret(token.EndPos);
|
|
|
|
Dec(tokenStart.x, AX);
|
|
Dec(tokenEnd.x, AX);
|
|
|
|
if (tokenStart.y>ALine) then Break;
|
|
if (tokenStart.y>ALine) or (tokenEnd.y<ALine) then Continue;
|
|
if (tokenEnd.y<=ALine) and (tokenEnd.x<0) then Continue;
|
|
if (tokenStart.y>=ALine) and (tokenStart.x>=ALen) then Continue;
|
|
|
|
FillChar(part{%H-}, SizeOf(part), 0);
|
|
if (tokenStart.y<ALine) or (tokenStart.x<0) then
|
|
part.Offset:= 0
|
|
else
|
|
part.Offset:= tokenStart.X;
|
|
|
|
if (tokenEnd.y>ALine) or (tokenEnd.x>=ALen) then
|
|
part.Len:= ALen-part.Offset
|
|
else
|
|
part.Len:= tokenEnd.X-part.Offset;
|
|
|
|
part.ColorFont:= AColorFont;
|
|
part.ColorBG:= GetTokenColorBG(token.StartPos, AColorBG, AEditorIndex);
|
|
|
|
tokenStyle:= token.Style;
|
|
DoFindTokenOverrideStyle(tokenStyle, i, AEditorIndex);
|
|
if tokenStyle<>nil then
|
|
SetPartStyleFromEcStyle(part, tokenStyle);
|
|
|
|
//add missing part
|
|
if partindex=0 then
|
|
mustOffset:= 0
|
|
else
|
|
with AParts[partindex-1] do
|
|
mustOffset:= Offset+Len;
|
|
|
|
if part.Offset>mustOffset then
|
|
begin
|
|
AddMissingPart(mustOffset, part.Offset-mustOffset);
|
|
if partindex>=High(AParts) then Exit;
|
|
end;
|
|
|
|
//add calculated part
|
|
if part.Len>0 then
|
|
begin
|
|
AParts[partindex]:= part;
|
|
Inc(partindex);
|
|
if partindex>=High(AParts) then Exit;
|
|
end;
|
|
end;
|
|
|
|
//application.MainForm.Caption:= 'startindex '+inttostr(startindex)+' count-tokens '+inttostr(count);
|
|
|
|
//add ending missing part
|
|
//(not only if part.Len>0)
|
|
mustOffset:= part.Offset+part.Len;
|
|
if mustOffset<ALen then
|
|
AddMissingPart(mustOffset, ALen-mustOffset);
|
|
|
|
//calc AColorAfter
|
|
mustOffset:= Buffer.CaretToStr(Point(AX+ALen, ALine));
|
|
nColor:= GetTokenColorBG(mustOffset, clNone, AEditorIndex);
|
|
if (nColor=clNone) and (ALen>0) then
|
|
nColor:= GetTokenColorBG(mustOffset-1, clNone, AEditorIndex);
|
|
if (nColor=clNone) then
|
|
nColor:= AColorAfter;
|
|
AColorAfter:= nColor;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.DoClearRanges;
|
|
var
|
|
j: integer;
|
|
begin
|
|
ListColors.Clear;
|
|
for j:= 0 to EdList.Count-1 do
|
|
TATSynEdit(EdList[j]).Fold.Clear;
|
|
end;
|
|
|
|
constructor TATAdapterEControl.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
|
|
EdList:= TList.Create;
|
|
AnClient:= nil;
|
|
Buffer:= TATStringBuffer.Create;
|
|
ListColors:= TList.Create;
|
|
FDynEnabled:= true;
|
|
|
|
Timer:= TTimer.Create(Self);
|
|
Timer.Enabled:= false;
|
|
Timer.Interval:= cAdapterTimerInterval;
|
|
Timer.OnTimer:= @TimerTimer;
|
|
end;
|
|
|
|
destructor TATAdapterEControl.Destroy;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:= ListColors.Count-1 downto 0 do
|
|
TObject(ListColors[i]).Free;
|
|
FreeAndNil(ListColors);
|
|
|
|
FreeAndNil(Buffer);
|
|
if Assigned(AnClient) then
|
|
FreeAndNil(AnClient);
|
|
FreeAndNil(EdList);
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.AddEditor(AEdit: TATSynEdit);
|
|
begin
|
|
if AEdit=nil then
|
|
EdList.Clear
|
|
else
|
|
begin
|
|
if EdList.IndexOf(AEdit)<0 then
|
|
EdList.Add(AEdit);
|
|
AEdit.Strings.OnLog:= @DoChangeLog;
|
|
end;
|
|
end;
|
|
|
|
function TATAdapterEControl.LexerAtPos(Pnt: TPoint): TecSyntAnalyzer;
|
|
begin
|
|
Result:= nil;
|
|
if AnClient<>nil then
|
|
Result:= AnClient.AnalyzerAtPos(Buffer.CaretToStr(Pnt));
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.GetTokenProps(token: TecSyntToken;
|
|
out APntFrom, APntTo: TPoint; out ATokenString, ATokenStyle: string);
|
|
begin
|
|
APntFrom:= Buffer.StrToCaret(token.StartPos);
|
|
APntTo:= Buffer.StrToCaret(token.EndPos);
|
|
ATokenString:= Utf8Encode(Buffer.SubString(token.StartPos+1, token.EndPos-token.StartPos));
|
|
if Assigned(token.Style) then
|
|
ATokenStyle:= token.Style.DisplayName
|
|
else
|
|
ATokenStyle:= '';
|
|
end;
|
|
|
|
procedure TATAdapterEControl.GetTokenWithIndex(AIndex: integer;
|
|
out APntFrom, APntTo: TPoint; out ATokenString, ATokenStyle: string);
|
|
begin
|
|
APntFrom:= Point(-1, -1);
|
|
APntTo:= Point(-1, -1);
|
|
ATokenString:= '';
|
|
ATokenStyle:= '';
|
|
|
|
if AnClient=nil then exit;
|
|
if Buffer=nil then exit;
|
|
|
|
if (AIndex>=0) and (AIndex<AnClient.TagCount) then
|
|
GetTokenProps(AnClient.Tags[AIndex], APntFrom, APntTo, ATokenString, ATokenStyle);
|
|
end;
|
|
|
|
procedure TATAdapterEControl.GetTokenAtPos(Pnt: TPoint;
|
|
out APntFrom, APntTo: TPoint;
|
|
out ATokenString, ATokenStyle: string);
|
|
var
|
|
token: TecSyntToken;
|
|
offset, i: integer;
|
|
begin
|
|
APntFrom:= Point(-1, -1);
|
|
APntTo:= Point(-1, -1);
|
|
ATokenString:= '';
|
|
ATokenStyle:= '';
|
|
|
|
if AnClient=nil then exit;
|
|
if Buffer=nil then exit;
|
|
offset:= Buffer.CaretToStr(Pnt);
|
|
|
|
for i:= 0 to AnClient.TagCount-1 do
|
|
begin
|
|
token:= AnClient.Tags[i];
|
|
if (offset>=token.StartPos) and (offset<token.EndPos) then
|
|
begin
|
|
GetTokenProps(token, APntFrom, APntTo, ATokenString, ATokenStyle);
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TATAdapterEControl.GetRangeParent(R: TecTextRange): TecTextRange;
|
|
//cannot use R.Parent!
|
|
var
|
|
RTest: TecTextRange;
|
|
i: integer;
|
|
begin
|
|
Result:= nil;
|
|
for i:= R.Index-1 downto 0 do
|
|
begin
|
|
RTest:= AnClient.Ranges[i];
|
|
if (RTest.StartIdx<=R.StartIdx) and
|
|
(RTest.EndIdx>=R.EndIdx) and
|
|
(RTest.Level<R.Level) then
|
|
begin
|
|
Result:= RTest;
|
|
Exit
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TreeFindNode(ATree: TTreeView; ANode: TTreeNode; const ANodeText: string): TTreeNode;
|
|
var
|
|
N: TTreeNode;
|
|
begin
|
|
Result:= nil;
|
|
if ATree.Items.Count=0 then exit;
|
|
if ANode<>nil then
|
|
N:= ANode.GetFirstChild
|
|
else
|
|
N:= ATree.Items[0];
|
|
repeat
|
|
if N=nil then exit;
|
|
if N.Text=ANodeText then begin Result:= N; exit; end;
|
|
N:= N.GetNextSibling;
|
|
until false;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.TreeFill(ATree: TTreeView);
|
|
var
|
|
R, RangeParent: TecTextRange;
|
|
NodeParent, NodeGroup: TTreeNode;
|
|
NodeText, NodeTextGroup, SItem: string;
|
|
NodeData: pointer;
|
|
i: integer;
|
|
begin
|
|
FBusy:= true;
|
|
//ATree.Items.BeginUpdate;
|
|
try
|
|
ATree.Items.Clear;
|
|
if AnClient=nil then exit;
|
|
|
|
for i:= 0 to AnClient.RangeCount-1 do
|
|
begin
|
|
R:= AnClient.Ranges[i];
|
|
if R.Rule=nil then Continue;
|
|
if not R.Rule.DisplayInTree then Continue;
|
|
|
|
NodeText:= Trim(Utf8Encode(AnClient.GetRangeName(R)));
|
|
NodeTextGroup:= Trim(Utf8Encode(AnClient.GetRangeGroup(R)));
|
|
NodeData:= R;
|
|
NodeParent:= nil;
|
|
NodeGroup:= nil;
|
|
|
|
RangeParent:= GetRangeParent(R);
|
|
while (RangeParent<>nil) and (not RangeParent.Rule.DisplayInTree) do
|
|
RangeParent:= GetRangeParent(RangeParent);
|
|
if RangeParent<>nil then
|
|
NodeParent:= ATree.Items.FindNodeWithData(RangeParent);
|
|
|
|
if NodeTextGroup<>'' then
|
|
repeat
|
|
SItem:= SGetItem(NodeTextGroup, '\');
|
|
if (SItem='') and (NodeTextGroup='') then Break;
|
|
|
|
if SItem='' then
|
|
NodeGroup:= nil
|
|
else
|
|
begin
|
|
NodeGroup:= TreeFindNode(ATree, NodeParent, SItem);
|
|
if NodeGroup=nil then
|
|
begin
|
|
NodeGroup:= ATree.Items.AddChild(NodeParent, SItem);
|
|
NodeGroup.ImageIndex:= R.Rule.TreeGroupImage;
|
|
NodeGroup.SelectedIndex:= NodeGroup.ImageIndex;
|
|
end;
|
|
end;
|
|
NodeParent:= NodeGroup;
|
|
until false;
|
|
|
|
NodeParent:= ATree.Items.AddChildObject(NodeParent, NodeText, NodeData);
|
|
NodeParent.ImageIndex:= R.Rule.TreeItemImage;
|
|
NodeParent.SelectedIndex:= NodeParent.ImageIndex;
|
|
end;
|
|
finally
|
|
//ATree.Items.EndUpdate;
|
|
ATree.Invalidate;
|
|
FBusy:= false;
|
|
end;
|
|
end;
|
|
|
|
function TATAdapterEControl.TreeGetPositionOfRange(R: TecTextRange): TPoint;
|
|
begin
|
|
Result:= Point(0, 0);
|
|
if AnClient=nil then exit;
|
|
Result:= Buffer.StrToCaret(R.StartPos);
|
|
end;
|
|
|
|
function TATAdapterEControl.TreeGetRangeOfPosition(P: TPoint): TecTextRange;
|
|
var
|
|
i: integer;
|
|
R: TecTextRange;
|
|
NPos, NToken: integer;
|
|
begin
|
|
Result:= nil;
|
|
if AnClient=nil then exit;
|
|
|
|
NPos:= Buffer.CaretToStr(P);
|
|
NToken:= AnClient.NextTokenAt(NPos);
|
|
if NToken<0 then exit;
|
|
|
|
for i:= AnClient.RangeCount-1 downto 0 do
|
|
begin
|
|
R:= AnClient.Ranges[i];
|
|
if not R.Rule.DisplayInTree then Continue;
|
|
if (R.StartPos<=NPos) and (R.EndIdx>=NToken) then
|
|
begin Result:= R; Break; end;
|
|
end;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.TreeShowItemForCaret(Tree: TTreeView; P: TPoint);
|
|
var
|
|
R: TecTextRange;
|
|
Node: TTreeNode;
|
|
begin
|
|
if Tree.Items.Count=0 then exit;
|
|
R:= TreeGetRangeOfPosition(P);
|
|
if R=nil then begin {showmessage('r=nil');} exit; end;
|
|
Node:= Tree.Items.FindNodeWithData(R);
|
|
if Node=nil then begin {showmessage('node=nil');} exit; end;
|
|
Node.MakeVisible;
|
|
Tree.Selected:= Node;
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.OnEditorCaretMove(Sender: TObject);
|
|
begin
|
|
UpdateRangesActive(Sender as TATSynEdit);
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.SetLexer(AAnalizer: TecSyntAnalyzer);
|
|
begin
|
|
DoClearRanges;
|
|
if Assigned(AnClient) then
|
|
FreeAndNil(AnClient);
|
|
|
|
if Assigned(FOnParseBegin) then
|
|
FOnParseBegin(Self);
|
|
|
|
if Assigned(AAnalizer) then
|
|
begin
|
|
AnClient:= TecClientSyntAnalyzer.Create(AAnalizer, Buffer, nil);
|
|
UpdateData;
|
|
end;
|
|
|
|
if Assigned(FOnLexerChange) then
|
|
FOnLexerChange(Self);
|
|
end;
|
|
|
|
procedure TATAdapterEControl.OnEditorChange(Sender: TObject);
|
|
begin
|
|
AddEditor(Sender as TATSynEdit);
|
|
UpdateData;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateData;
|
|
var
|
|
Ed: TATSynEdit;
|
|
Lens: TList;
|
|
i: integer;
|
|
begin
|
|
if EdList.Count=0 then Exit;
|
|
if not Assigned(AnClient) then Exit;
|
|
Ed:= TATSynEdit(EdList[0]);
|
|
|
|
Lens:= TList.Create;
|
|
try
|
|
Lens.Clear;
|
|
for i:= 0 to Ed.Strings.Count-1 do
|
|
Lens.Add(pointer(Length(Ed.Strings.Lines[i])));
|
|
Buffer.Setup(Ed.Strings.TextString, Lens, 1);
|
|
finally
|
|
FreeAndNil(Lens);
|
|
end;
|
|
|
|
DoAnalize(Ed);
|
|
UpdateRanges;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateRanges;
|
|
var
|
|
i: integer;
|
|
begin
|
|
DoClearRanges;
|
|
UpdateRangesFold;
|
|
UpdateRangesSublex; //sublexer ranges last
|
|
UpdateSeps;
|
|
|
|
if EdList.Count>0 then
|
|
for i:= 0 to EdList.Count-1 do
|
|
UpdateRangesActive(TATSynEdit(EdList[i]));
|
|
end;
|
|
|
|
procedure TATAdapterEControl.DoAnalize(AEdit: TATSynEdit);
|
|
var
|
|
NLine, NPos: integer;
|
|
begin
|
|
if Assigned(FOnParseBegin) then
|
|
FOnParseBegin(Self);
|
|
|
|
NLine:= Min(AEdit.LineBottom+1, Buffer.Count-1);
|
|
NPos:= Buffer.CaretToStr(Point(0, NLine));
|
|
|
|
AnClient.AppendToPos(NPos);
|
|
AnClient.IdleAppend;
|
|
if AnClient.IsFinished then
|
|
begin
|
|
UpdateEds;
|
|
if Assigned(FOnParseDone) then
|
|
FOnParseDone(Self);
|
|
end
|
|
else
|
|
Timer.Enabled:= true;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.DoFoldAdd(AX, AY, AY2: integer; AStaple: boolean; const AHint: string);
|
|
var
|
|
j: integer;
|
|
begin
|
|
if EdList.Count>0 then
|
|
for j:= 0 to EdList.Count-1 do
|
|
TATSynEdit(EdList[j]).Fold.Add(AX, AY, AY2, AStaple, AHint);
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateEds;
|
|
var
|
|
j: integer;
|
|
begin
|
|
for j:= 0 to EdList.Count-1 do
|
|
TATSynEdit(EdList[j]).Update;
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.DoFoldFromLinesHidden;
|
|
var
|
|
j: integer;
|
|
begin
|
|
for j:= 0 to EdList.Count-1 do
|
|
TATSynEdit(EdList[j]).UpdateFoldedFromLinesHidden;
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.UpdateSeps;
|
|
var
|
|
Ed: TATSynEdit;
|
|
Break: TecLineBreak;
|
|
Sep: TATLineSeparator;
|
|
i, j: integer;
|
|
begin
|
|
if EdList.Count=0 then Exit;
|
|
Ed:= TATSynEdit(EdList[0]);
|
|
|
|
for i:= 0 to Ed.Strings.Count-1 do
|
|
Ed.Strings.LinesSeparator[i]:= cLineSepNone;
|
|
|
|
if AnClient.LineBreaks.Count>0 then
|
|
begin
|
|
Break:= TecLineBreak(AnClient.LineBreaks[0]);
|
|
for j:= 0 to EdList.Count-1 do
|
|
TATSynEdit(EdList[j]).Colors.BlockSepLine:= Break.Rule.Style.BgColor;
|
|
|
|
for i:= 0 to AnClient.LineBreaks.Count-1 do
|
|
begin
|
|
Break:= TecLineBreak(AnClient.LineBreaks[i]);
|
|
if Break.Rule.LinePos=lbTop then
|
|
Sep:= cLineSepTop
|
|
else
|
|
Sep:= cLineSepBottom;
|
|
|
|
if Ed.Strings.IsIndexValid(Break.Line) then
|
|
Ed.Strings.LinesSeparator[Break.Line]:= Sep;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateRangesFold;
|
|
var
|
|
R: TecTextRange;
|
|
Pnt1, Pnt2: TPoint;
|
|
Pos1, Pos2: integer;
|
|
Style: TecSyntaxFormat;
|
|
SHint: string;
|
|
tokenStart, tokenEnd: TecSyntToken;
|
|
i: integer;
|
|
begin
|
|
if not Assigned(AnClient) then Exit;
|
|
|
|
for i:= 0 to AnClient.RangeCount-1 do
|
|
begin
|
|
R:= AnClient.Ranges[i];
|
|
if R.Rule.BlockType<>btRangeStart then Continue;
|
|
|
|
/////issue: rules in C# with 'parent' set give wrong ranges;
|
|
//rule "function begin", "prop begin";
|
|
//e.g. range from } bracket to some token before "else"
|
|
//temp workard: skip rule with 'parent'
|
|
{$ifdef skip_some_rules}
|
|
if R.Rule.NotParent then Continue;
|
|
{$endif}
|
|
|
|
if R.StartIdx<0 then Continue;
|
|
if R.EndIdx<0 then Continue;
|
|
|
|
tokenStart:= AnClient.Tags[R.StartIdx];
|
|
tokenEnd:= AnClient.Tags[R.EndIdx];
|
|
Pos1:= tokenStart.StartPos;
|
|
Pos2:= tokenEnd.EndPos;
|
|
Pnt1:= Buffer.StrToCaret(Pos1);
|
|
Pnt2:= Buffer.StrToCaret(Pos2);
|
|
if Pnt1.Y<0 then Continue;
|
|
if Pnt2.Y<0 then Continue;
|
|
|
|
if not R.Rule.NotCollapsed then
|
|
begin
|
|
SHint:= AnClient.GetCollapsedText(R); //+'/'+R.Rule.GetNamePath;
|
|
DoFoldAdd(Pnt1.X+1, Pnt1.Y, Pnt2.Y, R.Rule.DrawStaple, SHint);
|
|
end;
|
|
|
|
if R.Rule.DynHighlight<>dhNone then
|
|
begin
|
|
Style:= R.Rule.Style;
|
|
if Style<>nil then
|
|
if Style.BgColor<>clNone then
|
|
ListColors.Add(TATRangeColored.Create(Pos1, Pos2, R.StartIdx, R.EndIdx, Style.BgColor, R.Rule));
|
|
end;
|
|
end;
|
|
|
|
//keep folded blks that were folded
|
|
DoFoldFromLinesHidden;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.UpdateRangesSublex;
|
|
var
|
|
R: TecSubLexerRange;
|
|
Style: TecSyntaxFormat;
|
|
i: integer;
|
|
begin
|
|
for i:= 0 to AnClient.SubLexerRangeCount-1 do
|
|
begin
|
|
R:= AnClient.SubLexerRanges[i];
|
|
if R.Rule=nil then Continue;
|
|
if R.StartPos<0 then Continue;
|
|
if R.EndPos<0 then Continue;
|
|
|
|
Style:= R.Rule.Style;
|
|
if Style=nil then Continue;
|
|
if Style.BgColor<>clNone then
|
|
ListColors.Add(TATRangeColored.Create(R.StartPos, R.EndPos, -1, -1, Style.BgColor, nil));
|
|
end;
|
|
end;
|
|
|
|
function TATAdapterEControl.DoFindToken(APos: integer): integer;
|
|
var
|
|
a, b, m, dif: integer;
|
|
begin
|
|
Result:= -1;
|
|
|
|
a:= 0;
|
|
b:= AnClient.TagCount-1;
|
|
if b<0 then Exit;
|
|
|
|
repeat
|
|
dif:= AnClient.Tags[a].StartPos-APos;
|
|
if dif=0 then
|
|
begin Result:= a; Exit end;
|
|
|
|
//middle, which is near b if not exact middle
|
|
m:= (a+b+1) div 2;
|
|
|
|
dif:= AnClient.Tags[m].StartPos-APos;
|
|
if dif=0 then
|
|
begin Result:= m; Exit end;
|
|
|
|
if Abs(a-b)<=1 then Break;
|
|
if dif>0 then b:= m else a:= m;
|
|
until false;
|
|
|
|
if m=0 then
|
|
Result:= 0
|
|
else
|
|
Result:= m-1;
|
|
end;
|
|
|
|
function TATAdapterEControl.GetLexer: TecSyntAnalyzer;
|
|
begin
|
|
if Assigned(AnClient) then
|
|
Result:= AnClient.Owner
|
|
else
|
|
Result:= nil;
|
|
end;
|
|
|
|
procedure TATAdapterEControl.DoChangeLog(Sender: TObject; ALine, ACount: integer);
|
|
var
|
|
Pos: integer;
|
|
begin
|
|
if not Assigned(AnClient) then Exit;
|
|
|
|
//clear?
|
|
if ALine=-1 then
|
|
begin
|
|
AnClient.TextChanged(-1, 0);
|
|
Exit
|
|
end;
|
|
|
|
//Count>0: add EolLen=1
|
|
//Count<0 means delete: minus EolLen
|
|
if ACount>0 then Inc(ACount) else
|
|
if ACount<0 then Dec(ACount);
|
|
|
|
if ALine>=Buffer.Count then
|
|
Pos:= Buffer.TextLength
|
|
else
|
|
Pos:= Buffer.CaretToStr(Point(0, ALine));
|
|
|
|
AnClient.TextChanged(Pos, ACount);
|
|
end;
|
|
|
|
procedure TATAdapterEControl.TimerTimer(Sender: TObject);
|
|
begin
|
|
if not Assigned(AnClient) then Exit;
|
|
if AnClient.IsFinished then
|
|
begin
|
|
Timer.Enabled:= false;
|
|
UpdateRanges;
|
|
UpdateEds;
|
|
if Assigned(FOnParseDone) then
|
|
FOnParseDone(Self);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TATAdapterEControl.SetPartStyleFromEcStyle(var part: TATLinePart; st: TecSyntaxFormat);
|
|
begin
|
|
if st.FormatType in [ftCustomFont, ftFontAttr, ftColor] then
|
|
begin
|
|
if st.Font.Color<>clNone then
|
|
part.ColorFont:= st.Font.Color;
|
|
end;
|
|
if st.FormatType in [ftCustomFont, ftFontAttr, ftColor, ftBackGround] then
|
|
begin
|
|
if st.BgColor<>clNone then
|
|
part.ColorBG:= st.BgColor;
|
|
end;
|
|
if st.FormatType in [ftCustomFont, ftFontAttr] then
|
|
begin
|
|
part.FontBold:= fsBold in st.Font.Style;
|
|
part.FontItalic:= fsItalic in st.Font.Style;
|
|
part.FontStrikeOut:= fsStrikeOut in st.Font.Style;
|
|
end;
|
|
part.ColorBorder:= st.BorderColorBottom;
|
|
part.BorderUp:= cBorderEc[st.BorderTypeTop];
|
|
part.BorderDown:= cBorderEc[st.BorderTypeBottom];
|
|
part.BorderLeft:= cBorderEc[st.BorderTypeLeft];
|
|
part.BorderRight:= cBorderEc[st.BorderTypeRight];
|
|
end;
|
|
|
|
procedure TATAdapterEControl.DoFindTokenOverrideStyle(var ATokenStyle: TecSyntaxFormat;
|
|
ATokenIndex, AEditorIndex: integer);
|
|
var
|
|
Rng: TATRangeColored;
|
|
i: integer;
|
|
begin
|
|
for i:= 0 to ListColors.Count-1 do
|
|
begin
|
|
Rng:= TATRangeColored(ListColors[i]);
|
|
if Rng.Active[AEditorIndex] then
|
|
if Rng.Rule<>nil then
|
|
if Rng.Rule.DynHighlight=dhBound then
|
|
if (Rng.Token1=ATokenIndex) or (Rng.Token2=ATokenIndex) then
|
|
begin
|
|
ATokenStyle:= Rng.Rule.Style;
|
|
Exit
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|