mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-15 20:19:24 +02:00
SynEdit: Start paint-token-breaker for future bidi support
git-svn-id: trunk@38950 -
This commit is contained in:
parent
f50a958fad
commit
5f293d23ae
@ -1,6 +1,7 @@
|
|||||||
unit LazSynTextArea;
|
unit LazSynTextArea;
|
||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
{x $INLINE OFF}
|
||||||
|
|
||||||
{off $DEFINE SynUseOldDrawer}
|
{off $DEFINE SynUseOldDrawer}
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ type
|
|||||||
ExpandedExtraBytes: Integer; // tab and space expansion
|
ExpandedExtraBytes: Integer; // tab and space expansion
|
||||||
HasDoubleWidth: Boolean;
|
HasDoubleWidth: Boolean;
|
||||||
Attr: TSynSelectedColor;
|
Attr: TSynSelectedColor;
|
||||||
|
NextPhysicalStart: Integer; // 1 based - Next toxen, may be BIDI
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TLazSynPaintTokenBreaker }
|
{ TLazSynPaintTokenBreaker }
|
||||||
@ -32,20 +34,26 @@ type
|
|||||||
TLazSynPaintTokenBreaker = class
|
TLazSynPaintTokenBreaker = class
|
||||||
private
|
private
|
||||||
FBackgroundColor: TColor;
|
FBackgroundColor: TColor;
|
||||||
FDisplayView: TLazSynDisplayView;
|
|
||||||
FForegroundColor: TColor;
|
FForegroundColor: TColor;
|
||||||
|
FSpaceExtraByteCount: Integer;
|
||||||
|
FTabExtraByteCount: Integer;
|
||||||
|
FFirstCol, FLastCol: integer; // Physical
|
||||||
|
|
||||||
|
FDisplayView: TLazSynDisplayView;
|
||||||
FLinesView: TSynEditStrings;
|
FLinesView: TSynEditStrings;
|
||||||
FMarkupManager: TSynEditMarkupManager;
|
FMarkupManager: TSynEditMarkupManager;
|
||||||
|
|
||||||
FCharWidths: TPhysicalCharWidths;
|
FCharWidths: TPhysicalCharWidths;
|
||||||
FFirstCol, FLastCol: integer;
|
FCharWidthsLen: Integer;
|
||||||
FCurTxtLineIdx : Integer;
|
FCurTxtLineIdx : Integer;
|
||||||
|
|
||||||
FCurViewToken: TLazSynDisplayTokenInfoEx;
|
FCurViewToken: TLazSynDisplayTokenInfoEx;
|
||||||
|
FCurViewinRTL: Boolean;
|
||||||
|
FCurViewRtlPhysEnd: integer;
|
||||||
|
FCurViewRtlLogEnd: integer;
|
||||||
|
|
||||||
FCurMarkupPhysPos, FNextMarkupPhysPos: Integer; // 1, -1
|
FCurMarkupPhysPos, FNextMarkupPhysPos: Integer; // 1, -1
|
||||||
FMarkupTokenAttr: TSynSelectedColor;
|
FMarkupTokenAttr: TSynSelectedColor;
|
||||||
FSpaceExtraByteCount: Integer;
|
|
||||||
FTabExtraByteCount: Integer;
|
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -55,7 +63,7 @@ type
|
|||||||
);
|
);
|
||||||
procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx);
|
procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx);
|
||||||
function GetNextHighlighterTokenFromView(out ATokenInfo: TLazSynDisplayTokenInfoEx;
|
function GetNextHighlighterTokenFromView(out ATokenInfo: TLazSynDisplayTokenInfoEx;
|
||||||
AMaxPhysEnd: Integer
|
APhysEnd: Integer
|
||||||
): Boolean;
|
): Boolean;
|
||||||
function GetNextHighlighterTokenEx(out ATokenInfo: TLazSynDisplayTokenInfoEx): Boolean;
|
function GetNextHighlighterTokenEx(out ATokenInfo: TLazSynDisplayTokenInfoEx): Boolean;
|
||||||
property CharWidths: TPhysicalCharWidths read FCharWidths;
|
property CharWidths: TPhysicalCharWidths read FCharWidths;
|
||||||
@ -244,11 +252,14 @@ procedure TLazSynPaintTokenBreaker.SetHighlighterTokensLine(ALine: TLineIdx; out
|
|||||||
begin
|
begin
|
||||||
FDisplayView.SetHighlighterTokensLine(ALine, ARealLine);
|
FDisplayView.SetHighlighterTokensLine(ALine, ARealLine);
|
||||||
FCharWidths := FLinesView.GetPhysicalCharWidths(ARealLine);
|
FCharWidths := FLinesView.GetPhysicalCharWidths(ARealLine);
|
||||||
|
FCharWidthsLen := Length(FCharWidths);
|
||||||
|
|
||||||
FCurViewToken.Tk.TokenLength := 0;
|
FCurViewToken.Tk.TokenLength := 0;
|
||||||
FCurViewToken.LogicalStart := 1;
|
FCurViewToken.LogicalStart := 1;
|
||||||
FCurViewToken.PhysicalStart := 1;
|
FCurViewToken.PhysicalStart := 1;
|
||||||
|
FCurViewToken.NextPhysicalStart := 1;
|
||||||
FCurViewToken.PhysicalPaintStart := FFirstCol;
|
FCurViewToken.PhysicalPaintStart := FFirstCol;
|
||||||
|
FCurViewinRTL := False;
|
||||||
|
|
||||||
FCurMarkupPhysPos := FFirstCol;
|
FCurMarkupPhysPos := FFirstCol;
|
||||||
FNextMarkupPhysPos := -1;
|
FNextMarkupPhysPos := -1;
|
||||||
@ -288,7 +299,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TLazSynPaintTokenBreaker.GetNextHighlighterTokenFromView(out
|
function TLazSynPaintTokenBreaker.GetNextHighlighterTokenFromView(out
|
||||||
ATokenInfo: TLazSynDisplayTokenInfoEx; AMaxPhysEnd: Integer): Boolean;
|
ATokenInfo: TLazSynDisplayTokenInfoEx; APhysEnd: Integer): Boolean;
|
||||||
|
|
||||||
procedure InitSynAttr(var ATarget: TSynSelectedColor; ASource: TSynHighlighterAttributes;
|
procedure InitSynAttr(var ATarget: TSynSelectedColor; ASource: TSynHighlighterAttributes;
|
||||||
AnAttrStartX: Integer);
|
AnAttrStartX: Integer);
|
||||||
@ -312,119 +323,363 @@ function TLazSynPaintTokenBreaker.GetNextHighlighterTokenFromView(out
|
|||||||
ATarget.EndX := -1; //PhysicalStartPos + TokenCharLen - 1;
|
ATarget.EndX := -1; //PhysicalStartPos + TokenCharLen - 1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function MaybeFetchToken: Boolean; inline;
|
||||||
|
begin
|
||||||
|
Result := FCurViewToken.Tk.TokenLength > 0;
|
||||||
|
if Result or (FCurViewToken.Tk.TokenLength < 0) then exit;
|
||||||
|
while FCurViewToken.Tk.TokenLength = 0 do begin // Todo: is SyncroEd-test a zero size token is returned
|
||||||
|
Result := FDisplayView.GetNextHighlighterToken(FCurViewToken.Tk);
|
||||||
|
if not Result then begin
|
||||||
|
FCurViewToken.Tk.TokenLength := -1;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
// Todo: concatenate with next token, if possible (only, if reaching token end)
|
||||||
|
end;
|
||||||
|
// TODO: wait with attr, if skipping none painted
|
||||||
|
InitSynAttr(FCurViewToken.Attr, FCurViewToken.Tk.TokenAttr, FCurViewToken.PhysicalStart);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetCharWidthData(AIdx: Integer): TPhysicalCharWidth; inline;
|
||||||
|
begin
|
||||||
|
if AIdx >= FCharWidthsLen
|
||||||
|
then Result := 1
|
||||||
|
else Result := FCharWidths[AIdx];
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure AdjustCurTokenLogStart(ANewLogStart: Integer); inline;
|
||||||
|
// ANewLogStart = 1 based
|
||||||
|
var
|
||||||
|
j: integer;
|
||||||
|
begin
|
||||||
|
j := (ANewLogStart - FCurViewToken.LogicalStart);
|
||||||
|
FCurViewToken.Tk.TokenLength := FCurViewToken.Tk.TokenLength - j;
|
||||||
|
FCurViewToken.Tk.TokenStart := FCurViewToken.Tk.TokenStart + j;
|
||||||
|
FCurViewToken.LogicalStart := ANewLogStart;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SkipLtrBeforeFirstCol(var ALogicIdx: integer; ALogicEnd: Integer); inline;
|
||||||
|
var
|
||||||
|
j: Integer;
|
||||||
|
pcw: TPhysicalCharWidth;
|
||||||
|
begin
|
||||||
|
if (FCurViewToken.PhysicalStart >= FFirstCol) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
if (pcw and PCWFlagRTL <> 0) then exit;
|
||||||
|
|
||||||
|
j := (pcw and PCWMask);
|
||||||
|
while (ALogicIdx < ALogicEnd) and (FCurViewToken.PhysicalStart + j <= FFirstCol) and
|
||||||
|
(pcw and PCWFlagRTL = 0)
|
||||||
|
do begin
|
||||||
|
inc(FCurViewToken.PhysicalStart, j);
|
||||||
|
repeat
|
||||||
|
inc(ALogicIdx);
|
||||||
|
until (ALogicIdx >= ALogicEnd) or
|
||||||
|
(ALogicIdx >= FCharWidthsLen) or ((FCharWidths[ALogicIdx] and PCWMask) <> 0);
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
j := pcw and PCWMask;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ALogicIdx <> FCurViewToken.LogicalStart - 1 then begin
|
||||||
|
AdjustCurTokenLogStart(ALogicIdx + 1);
|
||||||
|
assert(FCurViewToken.Tk.TokenLength >= 0, 'FCurViewToken.Tk.TokenLength > 0');
|
||||||
|
end;
|
||||||
|
if FCurViewToken.PhysicalPaintStart < FFirstCol then
|
||||||
|
FCurViewToken.PhysicalPaintStart := FFirstCol;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SkipRtlOffScreen(var ALogicIdx: integer; ALogicEnd: Integer); inline;
|
||||||
|
var
|
||||||
|
j: Integer;
|
||||||
|
pcw: TPhysicalCharWidth;
|
||||||
|
begin
|
||||||
|
if (FCurViewToken.PhysicalStart <= FFirstCol) then begin
|
||||||
|
// TODO: end, if FCurViewRtlPhysEnd >= FLastCol;
|
||||||
|
if ALogicIdx + FCurViewToken.Tk.TokenLength < FCurViewRtlLogEnd then begin
|
||||||
|
FCurViewToken.LogicalStart := FCurViewToken.LogicalStart + FCurViewToken.Tk.TokenLength;
|
||||||
|
FCurViewToken.Tk.TokenLength := 0;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
j := FCurViewRtlLogEnd - ALogicIdx;
|
||||||
|
FCurViewToken.LogicalStart := FCurViewToken.LogicalStart + j;
|
||||||
|
FCurViewToken.Tk.TokenStart := FCurViewToken.Tk.TokenStart + j;
|
||||||
|
FCurViewToken.Tk.TokenLength := FCurViewToken.Tk.TokenLength - j;
|
||||||
|
ALogicIdx := ALogicIdx + j;
|
||||||
|
FCurViewToken.PhysicalStart := FCurViewRtlPhysEnd;
|
||||||
|
FCurViewToken.PhysicalPaintStart := FCurViewRtlPhysEnd;
|
||||||
|
assert(FCurViewToken.LogicalStart - 1 = FCurViewRtlLogEnd, 'SkipRtlOffScreen: FCurViewToken.LogicalStart = FCurViewRtlLogEnd');
|
||||||
|
end;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (FCurViewToken.PhysicalStart <= FLastCol) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
if (pcw and PCWFlagRTL = 0) then exit;
|
||||||
|
|
||||||
|
j := (pcw and PCWMask);
|
||||||
|
while (ALogicIdx < ALogicEnd) and (FCurViewToken.PhysicalStart - j >= FLastCol) and
|
||||||
|
(pcw and PCWFlagRTL <> 0)
|
||||||
|
do begin
|
||||||
|
dec(FCurViewToken.PhysicalStart, j);
|
||||||
|
repeat
|
||||||
|
inc(ALogicIdx);
|
||||||
|
until (ALogicIdx >= ALogicEnd) or
|
||||||
|
(ALogicIdx >= FCharWidthsLen) or ((FCharWidths[ALogicIdx] and PCWMask) <> 0);
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
j := pcw and PCWMask;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ALogicIdx <> FCurViewToken.LogicalStart - 1 then begin
|
||||||
|
AdjustCurTokenLogStart(ALogicIdx + 1);
|
||||||
|
assert(FCurViewToken.Tk.TokenLength >= 0, 'FCurViewToken.Tk.TokenLength > 0');
|
||||||
|
end;
|
||||||
|
if FCurViewToken.PhysicalPaintStart > FLastCol then
|
||||||
|
FCurViewToken.PhysicalPaintStart := FLastCol;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeToRtl(ALogicIdx, ALogicEnd: Integer);
|
||||||
|
var
|
||||||
|
RtlRunPhysWidth, j: Integer;
|
||||||
|
pcw: TPhysicalCharWidth;
|
||||||
|
begin
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
|
||||||
|
RtlRunPhysWidth := 0;
|
||||||
|
j := (pcw and PCWMask);
|
||||||
|
while (ALogicIdx < ALogicEnd) and (pcw and PCWFlagRTL <> 0) do begin
|
||||||
|
inc(RtlRunPhysWidth, j);
|
||||||
|
repeat
|
||||||
|
inc(ALogicIdx);
|
||||||
|
until (ALogicIdx >= ALogicEnd) or
|
||||||
|
(ALogicIdx >= FCharWidthsLen) or ((FCharWidths[ALogicIdx] and PCWMask) <> 0);
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(ALogicIdx);
|
||||||
|
j := pcw and PCWMask;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FCurViewinRTL := True;
|
||||||
|
FCurViewRTLLogEnd := ALogicIdx;
|
||||||
|
FCurViewRtlPhysEnd := FCurViewToken.PhysicalStart + RtlRunPhysWidth;
|
||||||
|
FCurViewToken.PhysicalStart := FCurViewRtlPhysEnd;
|
||||||
|
FCurViewToken.PhysicalPaintStart := FCurViewRtlPhysEnd;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MaybeChangeToRtl(ALogicIdx, ALogicEnd: Integer): boolean; inline;
|
||||||
|
begin
|
||||||
|
Result := (GetCharWidthData(ALogicIdx) and PCWFlagRTL) <> 0;
|
||||||
|
if Result then
|
||||||
|
ChangeToRtl(ALogicIdx, ALogicEnd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ChangeToLtr(ALogicIdx, ALogicEnd: Integer);
|
||||||
|
begin
|
||||||
|
FCurViewinRTL := False;
|
||||||
|
FCurViewToken.PhysicalStart := FCurViewRtlPhysEnd;
|
||||||
|
FCurViewToken.PhysicalPaintStart := FCurViewRtlPhysEnd;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function MaybeChangeToLtr(ALogicIdx, ALogicEnd: Integer): boolean; inline;
|
||||||
|
begin
|
||||||
|
Result := (GetCharWidthData(ALogicIdx) and PCWFlagRTL) = 0;
|
||||||
|
if Result then
|
||||||
|
ChangeToLtr(ALogicIdx, ALogicEnd);
|
||||||
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
i, j, CharWidthsLen: Integer;
|
i, j: Integer;
|
||||||
|
pcw: TPhysicalCharWidth;
|
||||||
c: Char;
|
c: Char;
|
||||||
LogicIdx, LogicEnd, PhysPos: Integer;
|
LogicIdx, LogicEnd, PhysPos: Integer;
|
||||||
PrevLogicIdx, PrevPhysPos: Integer;
|
PrevLogicIdx, PrevPhysPos: Integer;
|
||||||
|
PhysTokenStop: Integer;
|
||||||
TabExtra: Integer;
|
TabExtra: Integer;
|
||||||
HasDouble: Boolean;
|
HasDouble: Boolean;
|
||||||
begin
|
begin
|
||||||
if (AMaxPhysEnd > FLastCol) or (AMaxPhysEnd < 0) then
|
|
||||||
AMaxPhysEnd := FLastCol;
|
|
||||||
|
|
||||||
Result := AMaxPhysEnd > FCurViewToken.PhysicalPaintStart;
|
|
||||||
if not Result then exit;
|
|
||||||
|
|
||||||
while True do begin
|
while True do begin
|
||||||
if FCurViewToken.Tk.TokenLength = 0 then begin
|
Result := MaybeFetchToken; // Get token from View/Highlighter
|
||||||
Result := FDisplayView.GetNextHighlighterToken(FCurViewToken.Tk);
|
if not Result then exit;
|
||||||
if not Result then exit;
|
|
||||||
if FCurViewToken.Tk.TokenLength = 0 then continue; // // Todo: is SyncroEd-test a zero size token is returned
|
|
||||||
InitSynAttr(FCurViewToken.Attr, FCurViewToken.Tk.TokenAttr, FCurViewToken.PhysicalStart);
|
|
||||||
// Todo: concatenate with next token, if possible
|
|
||||||
end;
|
|
||||||
|
|
||||||
CharWidthsLen := Length(FCharWidths);
|
LogicIdx := FCurViewToken.LogicalStart - 1;
|
||||||
LogicIdx := FCurViewToken.LogicalStart - 1;
|
|
||||||
LogicEnd := LogicIdx + FCurViewToken.Tk.TokenLength;
|
LogicEnd := LogicIdx + FCurViewToken.Tk.TokenLength;
|
||||||
|
assert(GetCharWidthData(LogicIdx)<>0, 'GetNextHighlighterTokenFromView: Token starts with char');
|
||||||
|
|
||||||
// SKip out of screen
|
case FCurViewinRTL of
|
||||||
while (LogicIdx < LogicEnd) and (FCurViewToken.PhysicalStart < FFirstCol) do begin
|
False: // Left To Right
|
||||||
if LogicIdx >= CharWidthsLen
|
begin
|
||||||
then j := 1
|
SkipLtrBeforeFirstCol(LogicIdx, LogicEnd); // Skip out of screen
|
||||||
else j := (FCharWidths[LogicIdx] and PCWMask);
|
if FCurViewToken.Tk.TokenLength = 0 then
|
||||||
|
continue; // Get NEXT token
|
||||||
|
|
||||||
if FCurViewToken.PhysicalStart + j > FFirstCol then break;
|
if MaybeChangeToRtl(LogicIdx, LogicEnd) then
|
||||||
|
continue;
|
||||||
|
|
||||||
inc(FCurViewToken.PhysicalStart, j);
|
if APhysEnd > 0
|
||||||
repeat
|
then PhysTokenStop := Min(FLastCol, APhysEnd)
|
||||||
inc(LogicIdx);
|
else PhysTokenStop := FLastCol;
|
||||||
until (LogicIdx >= CharWidthsLen) or ((FCharWidths[LogicIdx] and PCWMask) <> 0);
|
// TODO: APhysEnd should always allow some data. Compare with FLastCol? Assert for APhysEnd
|
||||||
|
Result := PhysTokenStop > FCurViewToken.PhysicalPaintStart;
|
||||||
|
if not Result then exit;
|
||||||
|
|
||||||
|
// Find end according to PhysTokenStop
|
||||||
|
PhysPos := FCurViewToken.PhysicalStart;
|
||||||
|
PrevLogicIdx := LogicIdx;
|
||||||
|
PrevPhysPos := PhysPos;
|
||||||
|
HasDouble := False;
|
||||||
|
TabExtra := 0; // Extra bytes needed for expanded Tab/Space(utf8 visible space/dot)
|
||||||
|
i := 0;
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(LogicIdx);
|
||||||
|
while (LogicIdx < LogicEnd) and (PhysPos < PhysTokenStop) and
|
||||||
|
(pcw and PCWFlagRTL = 0)
|
||||||
|
do begin
|
||||||
|
j := pcw and PCWMask;
|
||||||
|
|
||||||
|
PrevLogicIdx := LogicIdx;
|
||||||
|
PrevPhysPos := PhysPos;
|
||||||
|
inc(PhysPos, j);
|
||||||
|
if j <> 0 then begin
|
||||||
|
c := (FCurViewToken.Tk.TokenStart + i)^;
|
||||||
|
if c = #9 then
|
||||||
|
inc(TabExtra, j-1 + FTabExtraByteCount)
|
||||||
|
else
|
||||||
|
if j > 1 then
|
||||||
|
HasDouble := True;
|
||||||
|
if c = ' ' then
|
||||||
|
inc(TabExtra, FSpaceExtraByteCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
repeat
|
||||||
|
inc(LogicIdx);
|
||||||
|
inc(i);
|
||||||
|
until (LogicIdx >= FCharWidthsLen) or
|
||||||
|
(LogicIdx >= LogicEnd) or ((FCharWidths[LogicIdx] and PCWMask) <> 0);
|
||||||
|
pcw := GetCharWidthData(LogicIdx);
|
||||||
|
end;
|
||||||
|
Assert(PhysPos > FCurViewToken.PhysicalStart, 'PhysPos > FCurViewToken.PhysicalStart');
|
||||||
|
|
||||||
|
ATokenInfo := FCurViewToken;
|
||||||
|
ATokenInfo.Tk.TokenLength := LogicIdx + 1 - ATokenInfo.LogicalStart;
|
||||||
|
ATokenInfo.LogicalEnd := LogicIdx + 1;
|
||||||
|
ATokenInfo.PhysicalEnd := PhysPos;
|
||||||
|
ATokenInfo.PhysicalPaintEnd := Min(PhysPos, PhysTokenStop);
|
||||||
|
ATokenInfo.ExpandedExtraBytes := TabExtra;
|
||||||
|
ATokenInfo.HasDoubleWidth := HasDouble;
|
||||||
|
|
||||||
|
if PhysPos > PhysTokenStop then begin // Last char goes over paint boundary
|
||||||
|
LogicIdx := PrevLogicIdx;
|
||||||
|
PhysPos := PrevPhysPos;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
PhysTokenStop := PhysPos;
|
||||||
|
AdjustCurTokenLogStart(LogicIdx + 1);
|
||||||
|
FCurViewToken.PhysicalStart := PhysPos;
|
||||||
|
FCurViewToken.PhysicalPaintStart := PhysTokenStop;
|
||||||
|
|
||||||
|
assert(FCurViewToken.Tk.TokenLength >= 0, 'FCurViewToken.Tk.TokenLength >= 0');
|
||||||
|
if FCurViewToken.Tk.TokenLength = 0 then
|
||||||
|
ATokenInfo.Attr.EndX := PhysPos-1;
|
||||||
|
|
||||||
|
//MaybeFetchToken;
|
||||||
|
MaybeChangeToRtl(LogicIdx, LogicEnd); // get NextTokenPhysStart
|
||||||
|
|
||||||
|
ATokenInfo.NextPhysicalStart := FCurViewToken.PhysicalStart;
|
||||||
|
|
||||||
|
break;
|
||||||
|
end; // case FCurViewinRTL = False;
|
||||||
|
True: // Right To Left
|
||||||
|
begin
|
||||||
|
SkipRtlOffScreen(LogicIdx, LogicEnd);
|
||||||
|
if FCurViewToken.Tk.TokenLength = 0 then
|
||||||
|
continue; // Get NEXT token
|
||||||
|
|
||||||
|
if MaybeChangeToLtr(LogicIdx, LogicEnd) then
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if APhysEnd >= FCurViewRtlPhysEnd
|
||||||
|
then PhysTokenStop := FFirstCol
|
||||||
|
else PhysTokenStop := Max(FFirstCol, APhysEnd);
|
||||||
|
// TODO: APhysEnd should always allow some data. Assert for APhysEnd
|
||||||
|
// FFirstCol must be less PPS. Otherwise it would have gone LTR
|
||||||
|
// Result := PhysTokenStop < FCurViewToken.PhysicalPaintStart;
|
||||||
|
// if not Result then exit;
|
||||||
|
|
||||||
|
// Find end according to PhysTokenStop
|
||||||
|
PhysPos := FCurViewToken.PhysicalStart;
|
||||||
|
PrevLogicIdx := LogicIdx;
|
||||||
|
PrevPhysPos := PhysPos;
|
||||||
|
HasDouble := False;
|
||||||
|
TabExtra := 0; // Extra bytes needed for expanded Tab/Space(utf8 visible space/dot)
|
||||||
|
i := 0;
|
||||||
|
|
||||||
|
pcw := GetCharWidthData(LogicIdx);
|
||||||
|
while (LogicIdx < LogicEnd) and (PhysPos > PhysTokenStop) and
|
||||||
|
(pcw and PCWFlagRTL <> 0)
|
||||||
|
do begin
|
||||||
|
j := pcw and PCWMask;
|
||||||
|
|
||||||
|
PrevLogicIdx := LogicIdx;
|
||||||
|
PrevPhysPos := PhysPos;
|
||||||
|
dec(PhysPos, j);
|
||||||
|
if j <> 0 then begin
|
||||||
|
c := (FCurViewToken.Tk.TokenStart + i)^;
|
||||||
|
if c = #9 then
|
||||||
|
inc(TabExtra, j-1 + FTabExtraByteCount)
|
||||||
|
else
|
||||||
|
if j > 1 then
|
||||||
|
HasDouble := True;
|
||||||
|
if c = ' ' then
|
||||||
|
inc(TabExtra, FSpaceExtraByteCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
repeat
|
||||||
|
inc(LogicIdx);
|
||||||
|
inc(i);
|
||||||
|
until (LogicIdx >= FCharWidthsLen) or
|
||||||
|
(LogicIdx >= LogicEnd) or ((FCharWidths[LogicIdx] and PCWMask) <> 0);
|
||||||
|
pcw := GetCharWidthData(LogicIdx);
|
||||||
|
end;
|
||||||
|
Assert(PhysPos < FCurViewToken.PhysicalStart, 'PhysPos > FCurViewToken.PhysicalStart');
|
||||||
|
|
||||||
|
ATokenInfo := FCurViewToken;
|
||||||
|
ATokenInfo.Tk.TokenLength := LogicIdx + 1 - ATokenInfo.LogicalStart;
|
||||||
|
ATokenInfo.LogicalEnd := LogicIdx + 1;
|
||||||
|
ATokenInfo.PhysicalEnd := ATokenInfo.PhysicalStart;
|
||||||
|
ATokenInfo.PhysicalPaintEnd := ATokenInfo.PhysicalPaintStart;
|
||||||
|
ATokenInfo.PhysicalStart := PhysPos;
|
||||||
|
ATokenInfo.PhysicalPaintStart := Max(PhysPos, PhysTokenStop);
|
||||||
|
ATokenInfo.ExpandedExtraBytes := TabExtra;
|
||||||
|
ATokenInfo.HasDoubleWidth := HasDouble;
|
||||||
|
|
||||||
|
if PhysPos < PhysTokenStop then begin // Last char goes over paint boundary
|
||||||
|
LogicIdx := PrevLogicIdx;
|
||||||
|
PhysPos := PrevPhysPos;
|
||||||
|
end;
|
||||||
|
//else
|
||||||
|
// AMaxPhysEnd := PhysPos;
|
||||||
|
AdjustCurTokenLogStart(LogicIdx + 1);
|
||||||
|
FCurViewToken.PhysicalStart := PhysPos;
|
||||||
|
FCurViewToken.PhysicalPaintStart := Max(PhysPos, PhysTokenStop);
|
||||||
|
|
||||||
|
assert(FCurViewToken.Tk.TokenLength >= 0, 'FCurViewToken.Tk.TokenLength >= 0');
|
||||||
|
if FCurViewToken.Tk.TokenLength = 0 then
|
||||||
|
ATokenInfo.Attr.EndX := PhysPos-1;
|
||||||
|
|
||||||
|
//MaybeFetchToken;
|
||||||
|
MaybeChangeToLtr(LogicIdx, LogicEnd); // get NextTokenPhysStart
|
||||||
|
|
||||||
|
ATokenInfo.NextPhysicalStart := FCurViewToken.PhysicalStart;
|
||||||
|
|
||||||
|
break;
|
||||||
|
end; // case FCurViewinRTL = True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if LogicIdx <> FCurViewToken.LogicalStart - 1 then begin
|
|
||||||
j := (LogicIdx + 1 - FCurViewToken.LogicalStart);
|
|
||||||
FCurViewToken.Tk.TokenLength := FCurViewToken.Tk.TokenLength - j;
|
|
||||||
FCurViewToken.Tk.TokenStart := FCurViewToken.Tk.TokenStart + j;
|
|
||||||
FCurViewToken.LogicalStart := LogicIdx + 1;
|
|
||||||
|
|
||||||
if FCurViewToken.Tk.TokenLength = 0 then
|
end; // while True
|
||||||
continue;
|
|
||||||
assert(FCurViewToken.Tk.TokenLength > 0, 'FCurViewToken.Tk.TokenLength > 0');
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Find end according to AMaxPhysEnd
|
|
||||||
LogicEnd := LogicIdx + FCurViewToken.Tk.TokenLength;
|
|
||||||
PhysPos := FCurViewToken.PhysicalStart;
|
|
||||||
PrevLogicIdx := LogicIdx;
|
|
||||||
PrevPhysPos := PhysPos;
|
|
||||||
HasDouble := False;
|
|
||||||
TabExtra := 0; // Extra bytes needed for expanded Tab/Space(utf8 visible space/dot)
|
|
||||||
i := 0;
|
|
||||||
|
|
||||||
while (LogicIdx < LogicEnd) and (PhysPos < AMaxPhysEnd) do begin
|
|
||||||
if LogicIdx >= CharWidthsLen
|
|
||||||
then j := 1
|
|
||||||
else j := (FCharWidths[LogicIdx] and PCWMask);
|
|
||||||
|
|
||||||
PrevLogicIdx := LogicIdx;
|
|
||||||
PrevPhysPos := PhysPos;
|
|
||||||
inc(PhysPos, j);
|
|
||||||
if j <> 0 then begin
|
|
||||||
c := (FCurViewToken.Tk.TokenStart + i)^;
|
|
||||||
if c = #9 then
|
|
||||||
inc(TabExtra, j-1 + FTabExtraByteCount)
|
|
||||||
else
|
|
||||||
if j > 1 then
|
|
||||||
HasDouble := True;
|
|
||||||
if c = ' ' then
|
|
||||||
inc(TabExtra, FSpaceExtraByteCount);
|
|
||||||
end;
|
|
||||||
|
|
||||||
repeat
|
|
||||||
inc(LogicIdx);
|
|
||||||
inc(i);
|
|
||||||
until (LogicIdx >= CharWidthsLen) or (LogicIdx >= LogicEnd) or ((FCharWidths[LogicIdx] and PCWMask) <> 0);
|
|
||||||
end;
|
|
||||||
Assert(PhysPos > FCurViewToken.PhysicalStart, 'PhysPos > FCurViewToken.PhysicalStart');
|
|
||||||
|
|
||||||
ATokenInfo := FCurViewToken;
|
|
||||||
ATokenInfo.Tk.TokenLength := LogicIdx + 1 - ATokenInfo.LogicalStart;
|
|
||||||
ATokenInfo.LogicalEnd := LogicIdx + 1;
|
|
||||||
ATokenInfo.PhysicalEnd := PhysPos;
|
|
||||||
ATokenInfo.PhysicalPaintEnd := Min(PhysPos, AMaxPhysEnd);
|
|
||||||
ATokenInfo.ExpandedExtraBytes := TabExtra;
|
|
||||||
ATokenInfo.HasDoubleWidth := HasDouble;
|
|
||||||
|
|
||||||
if PhysPos > AMaxPhysEnd then begin // Last char goes over paint boundary
|
|
||||||
LogicIdx := PrevLogicIdx;
|
|
||||||
PhysPos := PrevPhysPos;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
AMaxPhysEnd := PhysPos;
|
|
||||||
j := LogicIdx + 1 - FCurViewToken.LogicalStart;
|
|
||||||
FCurViewToken.Tk.TokenLength := FCurViewToken.Tk.TokenLength - j;
|
|
||||||
FCurViewToken.Tk.TokenStart := FCurViewToken.Tk.TokenStart + j;
|
|
||||||
FCurViewToken.LogicalStart := LogicIdx + 1;
|
|
||||||
FCurViewToken.PhysicalStart := PhysPos;
|
|
||||||
FCurViewToken.PhysicalPaintStart := AMaxPhysEnd;
|
|
||||||
assert(FCurViewToken.Tk.TokenLength >= 0, 'FCurViewToken.Tk.TokenLength >= 0');
|
|
||||||
|
|
||||||
if FCurViewToken.Tk.TokenLength = 0 then
|
|
||||||
ATokenInfo.Attr.EndX := PhysPos-1;
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TLazSynSurfaceManager }
|
{ TLazSynSurfaceManager }
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
unit TestSynTextArea;
|
unit TestSynTextArea;
|
||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
{$INLINE OFF}
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, fpcunit, testregistry, TestBase, SynHighlighterPas,
|
Classes, SysUtils, fpcunit, testregistry, TestBase, LazSynTextArea,
|
||||||
LazSynTextArea, SynEditTypes;
|
SynEditTypes, SynEditMarkupBracket, SynEdit, SynHighlighterPosition, Graphics;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@ -14,12 +15,13 @@ type
|
|||||||
|
|
||||||
TTestSynTextArea = class(TTestBase)
|
TTestSynTextArea = class(TTestBase)
|
||||||
private
|
private
|
||||||
FTheHighLighter: TSynPasSyn;
|
FTheHighLighter: TSynPositionHighlighter;
|
||||||
|
FtkRed, FtkGreen, FtkBlue, FtkYellow: TtkTokenKind;
|
||||||
protected
|
protected
|
||||||
FTokenBreaker: TLazSynPaintTokenBreaker;
|
FTokenBreaker: TLazSynPaintTokenBreaker;
|
||||||
|
|
||||||
procedure ReCreateEdit; reintroduce;
|
procedure ReCreateEdit; reintroduce;
|
||||||
function CreateTheHighLighter: TSynPasSyn;
|
function CreateTheHighLighter: TSynPositionHighlighter;
|
||||||
procedure SetUp; override;
|
procedure SetUp; override;
|
||||||
procedure TearDown; override;
|
procedure TearDown; override;
|
||||||
|
|
||||||
@ -43,9 +45,13 @@ begin
|
|||||||
SynEdit.Highlighter := FTheHighLighter;
|
SynEdit.Highlighter := FTheHighLighter;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TTestSynTextArea.CreateTheHighLighter: TSynPasSyn;
|
function TTestSynTextArea.CreateTheHighLighter: TSynPositionHighlighter;
|
||||||
begin
|
begin
|
||||||
Result := TSynPasSyn.Create(nil);
|
Result := TSynPositionHighlighter.Create(nil);
|
||||||
|
FtkRed := Result.CreateTokenID('red', clRed, clDefault, []);
|
||||||
|
FtkGreen := Result.CreateTokenID('green', clGreen, clDefault, []);
|
||||||
|
FtkBlue := Result.CreateTokenID('blue', clBlue, clDefault, []);
|
||||||
|
FtkYellow := Result.CreateTokenID('yellow', clYellow, clDefault, []);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTestSynTextArea.SetUp;
|
procedure TTestSynTextArea.SetUp;
|
||||||
@ -63,15 +69,20 @@ end;
|
|||||||
procedure TTestSynTextArea.SetRealLinesText;
|
procedure TTestSynTextArea.SetRealLinesText;
|
||||||
begin
|
begin
|
||||||
ReCreateEdit;
|
ReCreateEdit;
|
||||||
SetLines(['unit foo;',
|
SetLines(['unit foo;', // 1
|
||||||
'interface//',
|
'interface//',
|
||||||
'const',
|
'const',
|
||||||
' test =''abcDEF'';',
|
' test =''abcDEF'';',
|
||||||
' testa=''a あアア F'';',
|
' testa=''a あアア F'';', // 5
|
||||||
' testb=''aääDEF''; // föö bar',
|
' testb=''aääDEF''; // föö bar',
|
||||||
#9'i=123;',
|
#9'i=123;',
|
||||||
' a'#9'=0;',
|
' a'#9'=0;',
|
||||||
#9#9#9#9'end'
|
#9#9#9#9'end',
|
||||||
|
'', // 10
|
||||||
|
'شس',
|
||||||
|
'شس ي',
|
||||||
|
'ABشس يCD',
|
||||||
|
''
|
||||||
]);
|
]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -80,6 +91,7 @@ var
|
|||||||
BaseName, Name: String;
|
BaseName, Name: String;
|
||||||
TkCnt: Integer;
|
TkCnt: Integer;
|
||||||
Token: TLazSynDisplayTokenInfoEx;
|
Token: TLazSynDisplayTokenInfoEx;
|
||||||
|
UseViewTokenOnly: Boolean;
|
||||||
|
|
||||||
procedure TestToken(LStart, LEnd, PStart, PEnd, DStart, DEnd: Integer; AText: String);
|
procedure TestToken(LStart, LEnd, PStart, PEnd, DStart, DEnd: Integer; AText: String);
|
||||||
begin
|
begin
|
||||||
@ -97,7 +109,7 @@ var
|
|||||||
var
|
var
|
||||||
RLine: TLineIdx;
|
RLine: TLineIdx;
|
||||||
begin
|
begin
|
||||||
BaseName := Format('%s (Line=%d, F/L=%d-%d): ', [AName, ALine, AFirst, ALast]);
|
BaseName := Format('%s::%s (Line=%d, F/L=%d-%d): ', [BaseTestName, AName, ALine, AFirst, ALast]);
|
||||||
Name := BaseName;
|
Name := BaseName;
|
||||||
TkCnt := 0;
|
TkCnt := 0;
|
||||||
FTokenBreaker.Prepare(SynEdit.ViewedTextBuffer.DisplayView,
|
FTokenBreaker.Prepare(SynEdit.ViewedTextBuffer.DisplayView,
|
||||||
@ -115,7 +127,9 @@ var
|
|||||||
begin
|
begin
|
||||||
inc(TkCnt);
|
inc(TkCnt);
|
||||||
Name := Format('%sL=%d (%d): ', [BaseName, APhysLimit, TkCnt]);
|
Name := Format('%sL=%d (%d): ', [BaseName, APhysLimit, TkCnt]);
|
||||||
R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, APhysLimit);
|
if UseViewTokenOnly
|
||||||
|
then R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, APhysLimit)
|
||||||
|
else R := FTokenBreaker.GetNextHighlighterTokenEx(Token);
|
||||||
AssertTrue(Name + 'Got Token', R);
|
AssertTrue(Name + 'Got Token', R);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -131,142 +145,320 @@ var
|
|||||||
begin
|
begin
|
||||||
inc(TkCnt);
|
inc(TkCnt);
|
||||||
Name := Format('%sL=%d (%d): ', [BaseName, APhysLimit, TkCnt]);
|
Name := Format('%sL=%d (%d): ', [BaseName, APhysLimit, TkCnt]);
|
||||||
R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, APhysLimit);
|
if UseViewTokenOnly
|
||||||
|
then R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, APhysLimit)
|
||||||
|
else R := FTokenBreaker.GetNextHighlighterTokenEx(Token);
|
||||||
AssertFalse(Name + ' No further Token', R);
|
AssertFalse(Name + ' No further Token', R);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
UseViewTokenOnly := True;
|
||||||
SetRealLinesText;
|
SetRealLinesText;
|
||||||
SynEdit.TabWidth := 4;
|
SynEdit.TabWidth := 4;
|
||||||
SynEdit.ViewedTextBuffer.DisplayView.InitHighlighterTokens(FTheHighLighter);
|
SynEdit.ViewedTextBuffer.DisplayView.InitHighlighterTokens(SynEdit.Highlighter);
|
||||||
|
|
||||||
{%region full line}
|
FTheHighLighter.AddToken(2-1, 9, FtkBlue); // interface
|
||||||
TestStart('Scan full line', 2, 1, 100, 2);
|
FTheHighLighter.AddToken(7-1, 1, FtkYellow); // #9
|
||||||
|
FTheHighLighter.AddToken(7-1, 2, FtkGreen); // i
|
||||||
|
FTheHighLighter.AddToken(7-1, 3, FtkRed); // =
|
||||||
|
FTheHighLighter.AddToken(7-1, 6, FtkGreen); // 123
|
||||||
|
|
||||||
TestNext(100, 1, 10, 1, 10, 1, 10, 'interface');
|
{%region LTR only }
|
||||||
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
PushBaseName('LTR-Only');
|
||||||
TestEnd(100);
|
{%region full line}
|
||||||
|
TestStart('Scan full line', 2, 1, 100, 2);
|
||||||
|
TestNext(100, 1, 10, 1, 10, 1, 10, 'interface');
|
||||||
|
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('Scan full line', 2, 1, 100, 2);
|
||||||
|
TestNext(-1, 1, 10, 1, 10, 1, 10, 'interface');
|
||||||
|
TestNext(-1, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(-1);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off end of line}
|
||||||
|
TestStart('Cut off end', 2, 1, 5, 2);
|
||||||
|
|
||||||
|
TestNext(100, 1, 5, 1, 5, 1, 5, 'inte');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off start of line}
|
||||||
|
TestStart('Cut off start', 2, 3, 100, 2);
|
||||||
|
|
||||||
|
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
||||||
|
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off start of line}
|
||||||
|
TestStart('Cut off start 1 tok', 2, 10, 100, 2);
|
||||||
|
|
||||||
|
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off start of line}
|
||||||
|
TestStart('Cut off start 1.5 tok', 2, 11, 100, 2);
|
||||||
|
|
||||||
|
TestNext(100, 11, 12, 11, 12, 11, 12, '/');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off both}
|
||||||
|
TestStart('Cut off both', 2, 3, 10, 2);
|
||||||
|
|
||||||
|
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
||||||
|
//TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off both - 2 token}
|
||||||
|
TestStart('Cut off both - 2 token', 2, 3, 11, 2);
|
||||||
|
|
||||||
|
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
||||||
|
TestNext(100, 10, 11, 10, 11, 10, 11, '/');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off both - 1 token, skip first}
|
||||||
|
TestStart('Cut off both - 1 token, skip 1st', 2, 10, 11, 2);
|
||||||
|
|
||||||
|
TestNext(100, 10, 11, 10, 11, 10, 11, '/');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region 1 token 2 parts}
|
||||||
|
TestStart('1 token 2 parts', 2, 1, 100, 2);
|
||||||
|
|
||||||
|
TestNext( 3, 1, 3, 1, 3, 1, 3, 'in');
|
||||||
|
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
||||||
|
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
// part chars/tabs
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (begin)', 7, 2, 100, 7);
|
||||||
|
|
||||||
|
TestNext( 5, 1, 2, 1, 5, 2, 5, #9);
|
||||||
|
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (end)', 7, 1, 100, 7);
|
||||||
|
|
||||||
|
TestNext( 3, 1, 2, 1, 5, 1, 3, #9);
|
||||||
|
TestNext(100, 1, 2, 1, 5, 3, 5, #9);
|
||||||
|
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (end) next-limit', 7, 1, 100, 7);
|
||||||
|
|
||||||
|
TestNext( 3, 1, 2, 1, 5, 1, 3, #9);
|
||||||
|
TestNext( 5, 1, 2, 1, 5, 3, 5, #9);
|
||||||
|
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (both) continue', 7, 2, 100, 7);
|
||||||
|
|
||||||
|
TestNext( 3, 1, 2, 1, 5, 2, 3, #9);
|
||||||
|
TestNext(100, 1, 2, 1, 5, 3, 5, #9);
|
||||||
|
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (both) global-limit', 7, 2, 3, 7);
|
||||||
|
|
||||||
|
TestNext(100, 1, 2, 1, 5, 2, 3, #9);
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut off PART of char}
|
||||||
|
TestStart('cut off PART of char (both) next-limit', 7, 2, 100, 7);
|
||||||
|
|
||||||
|
TestNext(3, 1, 2, 1, 5, 2, 3, #9);
|
||||||
|
TestEnd(3);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region cut tab in many}
|
||||||
|
TestStart('cut tab in many', 9, 2, 100, 9);
|
||||||
|
|
||||||
|
TestNext( 3, 1, 2, 1, 5, 2, 3, #9);
|
||||||
|
TestNext( 6, 1, 3, 1, 9, 3, 6, #9#9);
|
||||||
|
TestNext( 11, 2, 4, 5, 13, 6, 11, #9#9);
|
||||||
|
TestNext( 13, 3, 4, 9, 13, 11, 13, #9);
|
||||||
|
TestNext( 15, 4, 5, 13, 17, 13, 15, #9);
|
||||||
|
{%endregion}
|
||||||
|
PopBaseName;
|
||||||
{%endregion}
|
{%endregion}
|
||||||
|
|
||||||
{%region cut off end of line}
|
SynEdit.ViewedTextBuffer.DisplayView.FinishHighlighterTokens;
|
||||||
TestStart('Cut off end', 2, 1, 5, 2);
|
SynEdit.Highlighter := nil;
|
||||||
|
SynEdit.ViewedTextBuffer.DisplayView.InitHighlighterTokens(SynEdit.Highlighter);
|
||||||
|
{%region RTL only }
|
||||||
|
PushBaseName('RTL-Only');
|
||||||
|
{%region full line}
|
||||||
|
TestStart('Scan full line', 11, 1, 100, 11);
|
||||||
|
TestNext(100, 1, 5, 1, 3, 1, 3, 'شس');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
TestNext(100, 1, 5, 1, 5, 1, 5, 'inte');
|
TestStart('Scan full line', 11, 1, 100, 11);
|
||||||
TestEnd(100);
|
TestNext(-1, 1, 5, 1, 3, 1, 3, 'شس');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
|
TestStart('Scan full line (2 words)', 12, 1, 100, 12);
|
||||||
|
TestNext(100, 1, 8, 1, 5, 1, 5, 'شس ي');
|
||||||
|
TestEnd(100);
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
{%region part line}
|
||||||
|
// 1 char parts
|
||||||
|
TestStart('part line - begin', 12, 1, 2, 12);
|
||||||
|
TestNext(100, 6, 8, 1, 2, 1, 2, 'ي');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('part line - mid', 12, 2, 3, 12);
|
||||||
|
TestNext(100, 5, 6, 2, 3, 2, 3, ' ');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('part line - mid', 12, 3, 4, 12);
|
||||||
|
TestNext(100, 3, 5, 3, 4, 3, 4, 'س');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('part line - end', 12, 4, 5, 12);
|
||||||
|
TestNext(100, 1, 3, 4, 5, 4, 5, 'ش');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
// 2 char parts
|
||||||
|
TestStart('part line - begin(2)', 12, 1, 3, 12);
|
||||||
|
TestNext(100, 5, 8, 1, 3, 1, 3, ' ي');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('part line - mid(2)', 12, 2, 4, 12);
|
||||||
|
TestNext(100, 3, 6, 2, 4, 2, 4, 'س ');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
TestStart('part line - end(2)', 12, 3, 5, 12);
|
||||||
|
TestNext(100, 1, 5, 3, 5, 3, 5, 'شس');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
// 1 char parts, several chunks
|
||||||
|
TestStart('part line - begin', 12, 1, 100, 12);
|
||||||
|
TestNext(4, 1, 3, 4, 5, 4, 5, 'ش');
|
||||||
|
TestNext(3, 3, 5, 3, 4, 3, 4, 'س');
|
||||||
|
TestNext(2, 5, 6, 2, 3, 2, 3, ' ');
|
||||||
|
TestNext(1, 6, 8, 1, 2, 1, 2, 'ي');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
// 1 char parts, several chunks
|
||||||
|
TestStart('part line - begin', 12, 1, 100, 12);
|
||||||
|
TestNext(4, 1, 3, 4, 5, 4, 5, 'ش');
|
||||||
|
TestNext(3, 3, 5, 3, 4, 3, 4, 'س');
|
||||||
|
TestNext(0, 5, 8, 1, 3, 1, 3, ' ي');
|
||||||
|
TestEnd(100);
|
||||||
|
|
||||||
|
//TestStart('part line - begin', 12, 1, 100, 12);
|
||||||
|
//TestNext(2, 1, 6, 2, 5, 2, 5, 'شس ');
|
||||||
|
//TestNext(5, 1, 3, 4, 5, 4, 5, 'ي');
|
||||||
|
//TestEnd(100);
|
||||||
|
//
|
||||||
|
//TestStart('part line - begin', 12, 1, 100, 12);
|
||||||
|
//TestNext( 2, 1, 6, 2, 5, 2, 5, 'شس ');
|
||||||
|
//TestNext(100, 1, 3, 4, 5, 4, 5, 'شس ي');
|
||||||
|
//TestEnd(100);
|
||||||
|
|
||||||
|
{%endregion}
|
||||||
|
|
||||||
|
PopBaseName;
|
||||||
{%endregion}
|
{%endregion}
|
||||||
|
|
||||||
{%region cut off start of line}
|
{%region MIXED Rtl/Ltr }
|
||||||
TestStart('Cut off start', 2, 3, 100, 2);
|
PushBaseName('MIXED Rtl/Ltr');
|
||||||
|
{%region full line}
|
||||||
|
TestStart('Scan full line', 13, 1, 100, 13);
|
||||||
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
|
TestNext(-1, 3, 10, 3, 7, 3, 7, 'شس ي');
|
||||||
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
{%endregion}
|
||||||
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
|
||||||
TestEnd(100);
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off start of line}
|
{%region parts}
|
||||||
TestStart('Cut off start 1 tok', 2, 10, 100, 2);
|
TestStart('Scan part line, cut at start', 13, 2, 100, 13);
|
||||||
|
TestNext(-1, 2, 3, 2, 3, 2, 3, 'B');
|
||||||
|
TestNext(-1, 3, 10, 3, 7, 3, 7, 'شس ي');
|
||||||
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
TestStart('Scan part line, cut at start', 13, 3, 100, 13);
|
||||||
TestEnd(100);
|
TestNext(-1, 3, 10, 3, 7, 3, 7, 'شس ي');
|
||||||
{%endregion}
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
{%region cut off start of line}
|
TestStart('Scan part line, cut at start', 13, 4, 100, 13);
|
||||||
TestStart('Cut off start 1.5 tok', 2, 11, 100, 2);
|
TestNext(-1, 3, 8, 4, 7, 4, 7, 'شس ');
|
||||||
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 11, 12, 11, 12, 11, 12, '/');
|
TestStart('Scan part line, cut at start', 13, 6, 100, 13);
|
||||||
TestEnd(100);
|
TestNext(-1, 3, 5, 6, 7, 6, 7, 'ش');
|
||||||
{%endregion}
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
{%region cut off both}
|
TestStart('Scan part line, cut at start', 13, 7, 100, 13);
|
||||||
TestStart('Cut off both', 2, 3, 10, 2);
|
TestNext(-1, 10, 12, 7, 9, 7, 9, 'CD');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
TestStart('Scan part line, cut at start', 13, 8, 100, 13);
|
||||||
//TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
TestNext(-1, 11, 12, 8, 9, 8, 9, 'D');
|
||||||
TestEnd(100);
|
TestEnd(-1);
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off both - 2 token}
|
TestStart('Scan part line, cut at start', 13, 9, 100, 13);
|
||||||
TestStart('Cut off both - 2 token', 2, 3, 11, 2);
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
|
||||||
TestNext(100, 10, 11, 10, 11, 10, 11, '/');
|
|
||||||
TestEnd(100);
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off both - 1 token, skip first}
|
TestStart('Scan part line, cut at end', 13, 1, 8, 13);
|
||||||
TestStart('Cut off both - 1 token, skip 1st', 2, 10, 11, 2);
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
|
TestNext(-1, 3, 10, 3, 7, 3, 7, 'شس ي');
|
||||||
|
TestNext(-1, 10, 11, 7, 8, 7, 8, 'C');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext(100, 10, 11, 10, 11, 10, 11, '/');
|
TestStart('Scan part line, cut at end', 13, 1, 7, 13);
|
||||||
TestEnd(100);
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
{%endregion}
|
TestNext(-1, 3, 10, 3, 7, 3, 7, 'شس ي');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
{%region 1 token 2 parts}
|
TestStart('Scan part line, cut at end', 13, 1, 6, 13);
|
||||||
TestStart('1 token 2 parts', 2, 1, 100, 2);
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
|
TestNext(-1, 5, 10, 3, 6, 3, 6, 'س ي');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext( 3, 1, 3, 1, 3, 1, 3, 'in');
|
TestStart('Scan part line, cut at end', 13, 1, 4, 13);
|
||||||
TestNext(100, 3, 10, 3, 10, 3, 10, 'terface');
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
TestNext(100, 10, 12, 10, 12, 10, 12, '//');
|
TestNext(-1, 8, 10, 3, 4, 3, 4, 'ي');
|
||||||
TestEnd(100);
|
TestEnd(-1);
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
// part chars/tabs
|
TestStart('Scan part line, cut at end', 13, 1, 3, 13);
|
||||||
|
TestNext(-1, 1, 3, 1, 3, 1, 3, 'AB');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
{%region cut off PART of char}
|
TestStart('Scan part line, cut at end', 13, 1, 2, 13);
|
||||||
TestStart('cut off PART of char (begin)', 7, 2, 100, 7);
|
TestNext(-1, 1, 2, 1, 2, 1, 2, 'A');
|
||||||
|
TestEnd(-1);
|
||||||
|
|
||||||
TestNext( 5, 1, 2, 1, 5, 2, 5, #9);
|
|
||||||
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off PART of char}
|
{%endregion}
|
||||||
TestStart('cut off PART of char (end)', 7, 1, 100, 7);
|
|
||||||
|
|
||||||
TestNext( 3, 1, 2, 1, 5, 1, 3, #9);
|
PopBaseName;
|
||||||
TestNext(100, 1, 2, 1, 5, 3, 5, #9);
|
|
||||||
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off PART of char}
|
|
||||||
TestStart('cut off PART of char (end) next-limit', 7, 1, 100, 7);
|
|
||||||
|
|
||||||
TestNext( 3, 1, 2, 1, 5, 1, 3, #9);
|
|
||||||
TestNext( 5, 1, 2, 1, 5, 3, 5, #9);
|
|
||||||
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off PART of char}
|
|
||||||
TestStart('cut off PART of char (both) continue', 7, 2, 100, 7);
|
|
||||||
|
|
||||||
TestNext( 3, 1, 2, 1, 5, 2, 3, #9);
|
|
||||||
TestNext(100, 1, 2, 1, 5, 3, 5, #9);
|
|
||||||
TestNext(100, 2, 3, 5, 6, 5, 6, 'i');
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off PART of char}
|
|
||||||
TestStart('cut off PART of char (both) global-limit', 7, 2, 3, 7);
|
|
||||||
|
|
||||||
TestNext(100, 1, 2, 1, 5, 2, 3, #9);
|
|
||||||
TestEnd(100);
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut off PART of char}
|
|
||||||
TestStart('cut off PART of char (both) next-limit', 7, 2, 100, 7);
|
|
||||||
|
|
||||||
TestNext(3, 1, 2, 1, 5, 2, 3, #9);
|
|
||||||
TestEnd(3);
|
|
||||||
{%endregion}
|
|
||||||
|
|
||||||
{%region cut tab in many}
|
|
||||||
TestStart('cut tab in many', 9, 2, 100, 9);
|
|
||||||
|
|
||||||
TestNext( 3, 1, 2, 1, 5, 2, 3, #9);
|
|
||||||
TestNext( 6, 1, 3, 1, 9, 3, 6, #9#9);
|
|
||||||
TestNext( 11, 2, 4, 5, 13, 6, 11, #9#9);
|
|
||||||
TestNext( 13, 3, 4, 9, 13, 11, 13, #9);
|
|
||||||
TestNext( 15, 4, 5, 13, 17, 13, 15, #9);
|
|
||||||
{%endregion}
|
{%endregion}
|
||||||
|
|
||||||
|
|
||||||
|
SynEdit.ViewedTextBuffer.DisplayView.FinishHighlighterTokens;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user