1 unit TestSynTextArea;
2 
3 {$mode objfpc}{$H+}
4 {$INLINE OFF}
5 
6 interface
7 
8 uses
9   Classes, SysUtils, testregistry, TestBase, LazSynTextArea, SynEditTypes,
10   SynEditMarkupBracket, SynEdit, SynHighlighterPosition, SynEditMiscClasses,
11   Graphics;
12 
13 type
14 
15   { TTestSynTextArea }
16 
17   TTestSynTextArea = class(TTestBase)
18   private
19     FTheHighLighter: TSynPositionHighlighter;
20     FtkRed, FtkGreen, FtkBlue, FtkYellow: TtkTokenKind;
21   protected
22     FTokenBreaker: TLazSynPaintTokenBreaker;
23 
24     procedure ReCreateEdit; reintroduce;
CreateTheHighLighternull25     function CreateTheHighLighter: TSynPositionHighlighter;
26     procedure SetUp; override;
27     procedure TearDown; override;
28 
29     procedure SetRealLinesText;
30   published
31     procedure TestPaintTokenBreaker;
32   end;
33 
34 implementation
35 
36 
37 { TTestSynTextArea }
38 
39 procedure TTestSynTextArea.ReCreateEdit;
40 begin
41   if Assigned(SynEdit) then
42     SynEdit.Highlighter := nil;
43   FreeAndNil(FTheHighLighter);
44   inherited ReCreateEdit;
45   FTheHighLighter := CreateTheHighLighter;
46   SynEdit.Highlighter := FTheHighLighter;
47   SynEdit.Color := clWhite;
48   SynEdit.Font.Color := clBlack;
49   SynEdit.SelectedColor.Foreground := clPurple;
50   FTokenBreaker.ForegroundColor := clBlack;
51   FTokenBreaker.BackgroundColor := clWhite;
52 end;
53 
CreateTheHighLighternull54 function TTestSynTextArea.CreateTheHighLighter: TSynPositionHighlighter;
55 begin
56   Result   := TSynPositionHighlighter.Create(nil);
57   FtkRed    := Result.CreateTokenID('red',    clRed,    clDefault, []);
58   FtkGreen  := Result.CreateTokenID('green',  clGreen,  clDefault, []);
59   FtkBlue   := Result.CreateTokenID('blue',   clBlue,   clDefault, []);
60   FtkYellow := Result.CreateTokenID('yellow', clYellow, clDefault, []);
61 end;
62 
63 procedure TTestSynTextArea.SetUp;
64 begin
65   inherited SetUp;
66   FTokenBreaker := TLazSynPaintTokenBreaker.Create;
67 end;
68 
69 procedure TTestSynTextArea.TearDown;
70 begin
71   FTokenBreaker.Free;
72   inherited TearDown;
73 end;
74 
75 procedure TTestSynTextArea.SetRealLinesText;
76 begin
77   ReCreateEdit;
78   SetLines(['unit foo;',                       // 1
79             'interface//',                     //     Hl-token
80             'const',
81             '  test =''abcDEF'';',
82             '  testa=''a あアア F'';',        // 5
83             '  testb=''aääDEF''; // föö bar',
84             #9'i=123;',                       // 7 // Hl-token
85             '  a'#9'=0;',
86             #9#9#9#9'end',
87             '',                               // 10
88             'شس',
89             'شس ي',
90             'ABشس يCD',
91             #9'i'#9'12'#9,
92             'ي'#9'شس',                        // 15
93             #9'('#9')',
94             '//شس يشس ي(شس ي',
95             'a     ''شس''b',
96             'a     ''شسقف',
97             'a     ''شسقف',                  // 20
98             ''
99            ]);
100 end;
101 
102 procedure TTestSynTextArea.TestPaintTokenBreaker;
103 var
104   BaseName, Name: String;
105   TkCnt: Integer;
106   Token: TLazSynDisplayTokenInfoEx;
107   UseViewTokenOnly: Boolean;
108   SkipPreFirst: Boolean;
109 type
110   TBoundExpectation = record
111     ExpPhys, ExpLog, ExpOffs: Integer;
112     WantOffs: Boolean;
113   end;
114 
bnull115   function b(AExpPhys, AExpLog: Integer): TBoundExpectation;
116   begin
117     Result.ExpPhys := AExpPhys;
118     Result.ExpLog  := AExpLog;
119     Result.WantOffs := False;
120   end;
121 
bnull122   function b(AExpPhys, AExpLog, AExpOffs: Integer): TBoundExpectation;
123   begin
124     Result.ExpPhys := AExpPhys;
125     Result.ExpLog  := AExpLog;
126     Result.ExpOffs := AExpOffs;
127     Result.WantOffs := True;
128   end;
129 
130   procedure TestBound(AName: String; ABound: TLazSynDisplayTokenBound; AExpect: TBoundExpectation);
131   begin
132     AssertEquals(AName + ' Bound.Phys',  AExpect.ExpPhys, ABound.Physical);
133     AssertEquals(AName + ' Bound.Log',   AExpect.ExpLog,  ABound.Logical);
134     if AExpect.WantOffs then
135       AssertEquals(AName + ' Bound.Offs',  AExpect.ExpOffs, ABound.Offset);
136   end;
137 
138   procedure TestStart(AName: String; ALine, AFirst, ALast: Integer; ExpRLine: Integer = -1);
139   // ALine, ExpRLine: 1-based
140   var
141     RLine: TLineIdx;
142   begin
143     BaseName := Format('%s::%s (Line=%d, F/L=%d-%d): ', [BaseTestName, AName, ALine, AFirst, ALast]);
144     Name := BaseName;
145     TkCnt := 0;
146     FTokenBreaker.Prepare(SynEdit.ViewedTextBuffer.DisplayView,
147                           SynEdit.ViewedTextBuffer,
148                           SynEdit.TextArea.MarkupManager,
149                           AFirst, ALast);
150     FTokenBreaker.SetHighlighterTokensLine(ALine-1, RLine);
151     if ExpRLine >= 0 then
152       AssertEquals(Name+'Got RealLine', ExpRLine-1, RLine);
153 
154     if not UseViewTokenOnly then
155       SynEdit.TextArea.MarkupManager.PrepareMarkupForRow(ALine);
156   end;
157 
158   procedure TestPreFirst(ExpNext: TBoundExpectation; ExpNxtIsRtl: Boolean);
159   var
160     R: Boolean;
161   begin
162     if SkipPreFirst then exit;
163     Name := Format('%sL (Pre-First): ', [BaseName]);
164     R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, -1, 1);
165 
166     AssertTrue(Name + 'Got Token', R);
167     TestBound(Name + ' Next(BOL)', Token.NextPos, ExpNext);
168     AssertEquals(Name + 'Nxt IsRtl',  ExpNxtIsRtl,  Token.NextRtlInfo.IsRtl);
169   end;
170 
171   procedure TestNext(ALimits: Array of Integer);
172   var
173     R: Boolean;
174     PhysLimit, LogLimit: Integer;
175   begin
176     inc(TkCnt);
177     PhysLimit := -1;
178     LogLimit := -1;
179     if Length(ALimits) > 0 then PhysLimit := ALimits[0];
180     if Length(ALimits) > 1 then LogLimit  := ALimits[1];
181     Name := Format('%sL=%d (%d): ', [BaseName, PhysLimit, TkCnt]);
182     if UseViewTokenOnly
183     then R := FTokenBreaker.GetNextHighlighterTokenFromView(Token, PhysLimit, LogLimit)
184     else R := FTokenBreaker.GetNextHighlighterTokenEx(Token);
185 
186     AssertTrue(Name + 'Got Token', R);
187   end;
188 
189   procedure TestNext(ALimits: Array of Integer;
190     ExpStart, ExpEnd: TBoundExpectation;
191     ExpCharStart, ExpCharEnd: Integer; ExpClipStart, ExpClipEnd: Integer;
192     ExpIsRtl: Boolean; ExpText: String);
193   begin
194     TestNext(ALimits);
195 
196     TestBound(Name + ' Start', Token.StartPos, ExpStart);
197     TestBound(Name + ' End',   Token.EndPos, ExpEnd);
198     AssertEquals(Name + ' PhysicalCharStart', ExpCharStart, Token.PhysicalCharStart);
199     AssertEquals(Name + ' PhysicalCharEnd',   ExpCharEnd,   Token.PhysicalCharEnd);
200     AssertEquals(Name + ' PhysicalClipStart', ExpClipStart, Token.PhysicalClipStart);
201     AssertEquals(Name + ' PhysicalClipEnd',   ExpClipEnd,   Token.PhysicalClipEnd);
202     AssertEquals(Name + ' ExpIsRtl',  ExpIsRtl,   Token.RtlInfo.IsRtl);
203     AssertEquals(Name + ' Text',   ExpText,  copy(Token.Tk.TokenStart, 1, Token.Tk.TokenLength));
204   end;
205 
206   procedure TestNext(ALimits: Array of Integer;
207     ExpStart, ExpEnd: TBoundExpectation;
208     ExpCharStart, ExpCharEnd: Integer; ExpClipStart, ExpClipEnd: Integer;
209     ExpIsRtl: Boolean; ExpText: String;
210     ExpFColor: TColor);
211   begin
212     TestNext(ALimits, ExpStart, ExpEnd, ExpCharStart, ExpCharEnd, ExpClipStart,
213       ExpClipEnd, ExpIsRtl, ExpText);
214 
215     AssertEquals(Name + ' F-Color',   ExpFColor,  Token.Attr.Foreground);
216   end;
217 
218   procedure TestNext(ALimits: Array of Integer;
219     ExpStart, ExpEnd: TBoundExpectation;
220     ExpCharStart, ExpCharEnd: Integer; ExpClipStart, ExpClipEnd: Integer;
221     ExpIsRtl: Boolean; ExpText: String;
222     ExpNext: TBoundExpectation; ExpNxtIsRtl: Boolean);
223   begin
224     TestNext(ALimits, ExpStart, ExpEnd, ExpCharStart, ExpCharEnd, ExpClipStart,
225       ExpClipEnd, ExpIsRtl, ExpText);
226 
227     TestBound(Name + ' Next', Token.NextPos, ExpNext);
228     AssertEquals(Name + 'Nxt IsRtl',  ExpNxtIsRtl,  Token.NextRtlInfo.IsRtl);
229   end;
230 
231   procedure TestNext(ALimits: Array of Integer;
232     ExpStart, ExpEnd: TBoundExpectation;
233     ExpCharStart, ExpCharEnd: Integer; ExpClipStart, ExpClipEnd: Integer;
234     ExpIsRtl: Boolean; ExpText: String;
235     ExpFColor: TColor;
236     ExpNext: TBoundExpectation; ExpNxtIsRtl: Boolean);
237   begin
238     TestNext(ALimits, ExpStart, ExpEnd, ExpCharStart, ExpCharEnd, ExpClipStart,
239       ExpClipEnd, ExpIsRtl, ExpText, ExpNext, ExpNxtIsRtl);
240 
241     AssertEquals(Name + ' F-Color',   ExpFColor,  Token.Attr.Foreground);
242   end;
243 
244   procedure TestEnd;
245   var
246     R: Boolean;
247   begin
248     inc(TkCnt);
249     Name := Format('%sL=(%d): ', [BaseName, TkCnt]);
250     if UseViewTokenOnly
251     then R := FTokenBreaker.GetNextHighlighterTokenFromView(Token)
252     else R := FTokenBreaker.GetNextHighlighterTokenEx(Token);
253     AssertFalse(Name + ' No further Token', R);
254   end;
255 
256   procedure TestEnd(ExpStart: TBoundExpectation);
257   begin
258     TestEnd;
259     TestBound(Name + ' Start(EOL)', Token.StartPos, ExpStart);
260   end;
261 
262   procedure DoTests;
263   begin
264     UseViewTokenOnly := True;
265     SetRealLinesText;
266     SynEdit.TabWidth := 4;
267     SynEdit.ViewedTextBuffer.DisplayView.InitHighlighterTokens(SynEdit.Highlighter);
268 
269     FTheHighLighter.AddToken(2-1,  9, FtkBlue);   // interface
270     FTheHighLighter.AddToken(7-1,  1, FtkYellow); // #9
271     FTheHighLighter.AddToken(7-1,  2, FtkGreen);  // i
272     FTheHighLighter.AddToken(7-1,  3, FtkRed);    // =
273     FTheHighLighter.AddToken(7-1,  6, FtkGreen);  // 123
274     FTheHighLighter.AddToken(17-1, 2, FtkBlue);   // //
275 
276     FTheHighLighter.AddToken(18-1, 6, FtkGreen);   // '      ' 6 spaces
277     FTheHighLighter.AddToken(18-1, 7, FtkYellow);  // '
278     FTheHighLighter.AddToken(18-1,11, FtkBlue);    // شس
279     FTheHighLighter.AddToken(18-1,12, FtkYellow);  // '
280     FTheHighLighter.AddToken(18-1,13, FtkRed);  // ,
281 
282     FTheHighLighter.AddToken(19-1, 6, FtkGreen);   // '      ' 6 spaces
283     FTheHighLighter.AddToken(19-1, 7, FtkYellow);  // '
284     FTheHighLighter.AddToken(19-1,15, FtkBlue);    // شس
285 
286     FTheHighLighter.AddToken(20-1, 6, FtkGreen);   // '      ' 6 spaces
287     FTheHighLighter.AddToken(20-1, 7, FtkYellow);  // '
288     FTheHighLighter.AddToken(20-1,13, FtkRed);    // شس 3 chars, ekcept last will be red
289     FTheHighLighter.AddToken(20-1,15, FtkBlue);    // شس
290 
291     {%region  LTR only }
292       PushBaseName('LTR-Only');
293 
294       {%region  full line}
295         TestStart('Scan full line / hl-token',   2,   1, 100,   2);
296         TestNext([100],    b( 1, 1, 0),  b(10,10, 0),    1,10,   1,10,   False, 'interface', clBlue,   b(10,10, 0), False);
297         TestNext([100],    b(10,10, 0),  b(12,12, 0),   10,12,  10,12,   False, '//',        clBlack,  b(12,12, 0), False);
298         TestEnd(b(12,12,0));
299 
300         TestStart('Scan full line / hl-token',   2,   1, 100,   2);
301         TestPreFirst(b( 1, 1, 0), False);
302         TestNext([],    b( 1, 1),  b(10,10),    1,10,   1,10,   False, 'interface',  b(10,10, 0), False);
303         TestNext([],    b(10,10),  b(12,12),   10,12,  10,12,   False, '//',         b(12,12, 0), False);
304         TestEnd(b(12,12, 0));
305       {%endregion}
306 
307       {%region  cut off end of line}
308         TestStart('Cut off end',   2,   1, 5,   2);
309 
310         TestNext([100],   b( 1, 1),  b( 5, 5),    1, 5,   1, 5,   False, 'inte',  b( 5, 5, 0), False);
311         TestEnd(b( 5, 5, 0));
312       {%endregion}
313 
314       {%region  cut off start of line}
315         TestStart('Cut off start',   2,   3, 100,   2);
316         TestNext([100],    b( 3, 3),  b(10,10),    3,10,   3,10,   False, 'terface',  b(10,10, 0), False);
317         TestNext([100],    b(10,10),  b(12,12),   10,12,  10,12,   False, '//',       b(12,12, 0), False);
318         TestEnd(b(12,12, 0));
319 
320         TestStart('Cut off start 1 tok',   2,  10, 100,   2);
321         TestNext([100],    b(10,10),  b(12,12),   10,12,  10,12,   False, '//',   b(12,12, 0), False);
322         TestEnd(b(12,12, 0));
323 
324         TestStart('Cut off start 1.5 tok',   2,  11, 100,   2);
325         TestNext([100],    b(11,11),  b(12,12),   11,12,  11,12,   False, '/',   b(12,12, 0), False);
326         TestEnd(b(12,12, 0));
327 
328         TestStart('Cut off entire line',   2,  20, 50,   2);
329         AssertFalse(Name + 'Got NO Token', FTokenBreaker.GetNextHighlighterTokenFromView(Token, -1, 1));
330         TestBound(Name + ' Start(BOL)', Token.StartPos, b(12,12, 0));
331       {%endregion}
332 
333       {%region  cut off both}
334         TestStart('Cut off both',   2,   3, 10,   2);
335         TestNext([100],    b( 3, 3),  b(10,10),    3,10,   3,10,   False, 'terface');
336         //TestNext([100],    b(10,10),  b(12,12),   10,12,  10,12,   False, '//');
337         TestEnd;
338 
339         TestStart('Cut off both - 2 token',   2,   3, 11,   2);
340         TestNext([100],    b( 3, 3),  b(10,10),    3,10,   3,10,   False, 'terface');
341         TestNext([100],    b(10,10),  b(11,11),   10,11,  10,11,   False, '/');
342         TestEnd;
343 
344         TestStart('Cut off both - 1 token, skip 1st',   2,   10,11,   2);
345         TestNext([100],    b(10,10),  b(11,11),   10,11,  10,11,   False, '/');
346         TestEnd;
347       {%endregion}
348 
349       {%region  1 token 2 parts}
350         TestStart('1 token 2 parts',   2,   1, 100,   2);
351 
352         TestNext([  3],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, 'in',clBlue );
353         TestNext([100],    b( 3, 3, 0),  b(10,10, 0),    3,10,   3,10,   False, 'terface', clBlue);
354         TestNext([100],    b(10,10, 0),  b(12,12, 0),   10,12,  10,12,   False, '//', clBlack);
355         TestEnd;
356       {%endregion}
357 
358       // part chars/tabs
359 
360       {%region  cut off PART of char }
361         // start at 1
362         TestStart('cut off PART of char (end)',     7,   1, 100,   7);
363         TestPreFirst(b( 1, 1, 0), False);
364         TestNext([  3],   b( 1, 1, 0),  b( 3, 2,-2),    1, 5,   1, 3,   False, #9,  b( 3, 1, 2), False);
365         TestNext([100],   b( 3, 1, 2),  b( 5, 2, 0),    1, 5,   3, 5,   False, #9,  b( 5, 2, 0), False);
366         TestNext([100],   b( 5, 2, 0),  b( 6, 3, 0),    5, 6,   5, 6,   False, 'i');
367 
368         TestStart('cut off PART of char (end) next-limit',   7,   1, 100,   7);
369         TestPreFirst(b( 1, 1, 0), False);
370         TestNext([  3],   b( 1, 1),  b( 3, 2),    1, 5,   1, 3,   False, #9,  b( 3, 1, 2), False);
371         TestNext([  5],   b( 3, 1),  b( 5, 2),    1, 5,   3, 5,   False, #9,  b( 5, 2, 0), False);
372         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
373 
374         TestStart('cut off PART of char (end) next-limit-log',   7,   1, 100,   7);
375         TestPreFirst(b( 1, 1, 0), False);
376         TestNext([  3],   b( 1, 1),  b( 3, 2),    1, 5,   1, 3,   False, #9,  b( 3, 1, 2), False);
377         TestNext([99,2],  b( 3, 1),  b( 5, 2),    1, 5,   3, 5,   False, #9,  b( 5, 2, 0), False);
378         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
379 
380         // start at 2
381         TestStart('cut off PART of char (begin)',   7,   2, 100,   7);
382         TestPreFirst(b( 2, 1, 1), False);
383         TestNext([  5],   b( 2, 1),  b( 5, 2),     1, 5,    2,  5,    False, #9);
384         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
385 
386         TestStart('cut off PART of char (both) continue',   7,   2, 100,   7);
387         TestPreFirst(b( 2, 1, 1), False);
388         TestNext([  3],   b( 2, 1),  b( 3, 2),     1, 5,    2,  3,    False, #9);
389         TestNext([100],   b( 3, 1),  b( 5, 2),     1, 5,    3,  5,    False, #9);
390         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
391 
392         TestStart('cut off PART of char (both) global-limit',   7,   2, 3,   7);
393         TestPreFirst(b( 2, 1, 1), False);
394         TestNext([100],   b( 2, 1),  b( 3, 2),     1, 5,    2,  3,    False, #9);
395         TestEnd;
396 
397         TestStart('cut off PART of char (both) next-limit',   7,   2, 100,   7);
398         TestPreFirst(b( 2, 1, 1), False);
399         TestNext([3],   b( 2, 1),  b( 3, 2),     1, 5,    2,  3,    False, #9);
400         //TestEnd(3);
401 
402         // start at 3
403         TestStart('cut off PART of char (begin)',   7,   3, 100,   7);
404         TestPreFirst(b( 3, 1, 2), False);
405         TestNext([  5],   b( 3, 1),  b( 5, 2),     1, 5,    3,  5,    False, #9);
406         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
407 
408         // start at 4
409         TestStart('cut off PART of char (begin)',   7,   4, 100,   7);
410         TestPreFirst(b( 4, 1, 3), False);
411         TestNext([  5],   b( 4, 1),  b( 5, 2),     1, 5,    4,  5,    False, #9);
412         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
413 
414         // start at 5
415         TestStart('cut off PART of char (begin)',   7,   5, 100,   7);
416         TestPreFirst(b( 5, 2, 0), False);
417         TestNext([100],   b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
418       {%endregion}
419 
420       {%region  cut tab in many}
421         TestStart('cut tab in many',   9,   2, 100,   9);
422 
423         TestNext([  3],   b( 2, 1),  b( 3, 2),     1, 5,    2,  3,    False, #9);
424         TestNext([  6],   b( 3, 1),  b( 6, 3),    1, 9,   3, 6,   False, #9#9);
425         TestNext([ 11],   b( 6, 2),  b(11, 4),    5,13,   6,11,   False, #9#9);
426         TestNext([ 13],   b(11, 3),  b(13, 4),     9,13,   11, 13,    False, #9);
427         TestNext([ 15],   b(13, 4),  b(15, 5),    13,17,   13, 15,    False, #9);
428       {%endregion}
429 
430       {%region  break line // phys log}
431         TestStart('Scan full line',  14,   1, 100,   14);
432         TestPreFirst(b( 1, 1, 0), False);
433         TestNext([-1, -1],    b( 1, 1),  b(13, 7),    1,13,   1,13,   False, #9'i'#9'12'#9);
434 
435         TestStart('Scan full line',  14,   1, 100,   14);
436         TestPreFirst(b( 1, 1, 0), False);
437         TestNext([-1, 2],    b( 1, 1),  b( 5, 2),    1, 5,   1, 5,   False, #9,  b( 5, 2, 0), False);
438         TestNext([-1, 3],    b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
439 
440         TestStart('Scan full line',  14,   1, 100,   14);
441         TestPreFirst(b( 1, 1, 0), False);
442         TestNext([99, 2],    b( 1, 1),  b( 5, 2),    1, 5,   1, 5,   False, #9,  b( 5, 2, 0), False);
443         TestNext([-1, 3],    b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
444 
445         TestStart('Scan full line',  14,   1, 100,   14);
446         TestPreFirst(b( 1, 1, 0), False);
447         TestNext([ 5, 2],    b( 1, 1),  b( 5, 2),    1, 5,   1, 5,   False, #9,  b( 5, 2, 0), False);
448         TestNext([-1, 3],    b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
449 
450         TestStart('Scan full line',  14,   1, 100,   14);
451         TestPreFirst(b( 1, 1, 0), False);
452         TestNext([ 4, 2],    b( 1, 1),  b( 4, 2),    1, 5,   1, 4,   False, #9,  b( 4, 1, 3), False);
453         TestNext([-1, 2],    b( 4, 1),  b( 5, 2),    1, 5,   4, 5,   False, #9,  b( 5, 2, 0), False);
454         TestNext([-1, 3],    b( 5, 2),  b( 6, 3),    5, 6,   5, 6,   False, 'i');
455 
456 
457       {%endregion}
458 
459       PopBaseName;
460     {%endregion}
461 
462     {%region  RTL only }
463       PushBaseName('RTL-Only');
464       {%region  full line}
465         TestStart('Scan full line',  11,   1, 100,   11);
466         TestPreFirst(b( 3, 1, 0), True);
467         TestNext([100],    b( 3, 1, 0),  b( 1, 5, 0),    1, 3,   1, 3,   True,  'شس',  b( 3, 5, 0), False);
468         TestEnd(b( 3, 5, 0));
469 
470         TestStart('Scan full line',  11,   1, 100,   11);
471         TestPreFirst(b( 3, 1, 0), True);
472         TestNext([],    b( 3, 1, 0),  b( 1, 5, 0),    1, 3,   1, 3,   True,  'شس',   b( 3, 5, 0), False);
473         TestEnd(b( 3, 5, 0));
474 
475         TestStart('Scan full line (2 words)',  12,   1, 100,   12);
476         TestPreFirst(b( 5, 1, 0), True);
477         TestNext([100],    b( 5, 1, 0),  b( 1, 8, 0),    1, 5,   1, 5,   True,  'شس ي',   b( 5, 8, 0), False);
478         TestEnd(b( 5, 8, 0));
479       {%endregion}
480 
481       {%region  Cut tab}
482         (*
483           Tab implemetation may change. currently it is calculated on the logical pos of the tab
484         *)
485         // tab will be 3 width
486         TestStart('Scan full line',  15,   3, 7,   15);
487         TestPreFirst(b( 7, 1, 0), True);
488         TestNext([],    b( 7, 1, 0),  b( 3, 4, 0),    3, 7,   3, 7,   True,  'ي'#9,   b( 7, 8, 0), False);
489         TestEnd(b( 7, 8, 0));
490 
491         TestStart('Scan full line',  15,   4, 7,   15);
492         TestPreFirst(b( 7, 1, 0), True);
493         TestNext([],    b( 7, 1, 0),  b( 4, 4,-1),    3, 7,   4, 7,   True,  'ي'#9,   b( 7, 8, 0), False);
494         TestEnd(b( 7, 8, 0));
495 
496         TestStart('Scan full line',  15,   5, 7,   15);
497         TestPreFirst(b( 7, 1, 0), True);
498         TestNext([],    b( 7, 1, 0),  b( 5, 4,-2),    3, 7,   5, 7,   True,  'ي'#9,   b( 7, 8, 0), False);
499         TestEnd(b( 7, 8, 0));
500 
501 
502         TestStart('Scan full line',  15,   1, 7,   15);
503         TestPreFirst(b( 7, 1, 0), True);
504         TestNext([],    b( 7, 1, 0),  b( 1, 8, 0),    1, 7,   1, 7,   True,  'ي'#9'شس',   b( 7, 8, 0), False);
505         TestEnd(b( 7, 8, 0));
506 
507         TestStart('Scan full line',  15,   1, 6,   15);
508         TestPreFirst(b( 6, 3, 0), True);
509         // TODO NextPos and TestEnd: Phys pos is allowed to be 6 OR 7
510         TestNext([],    b( 6, 3, 0),  b( 1, 8, 0),    1, 6,   1, 6,   True,  #9'شس',   b( 7, 8, 0), False);
511         TestEnd(b( 7, 8, 0));
512 
513         TestStart('Scan full line',  15,   1, 5,   15);
514         TestPreFirst(b( 5, 3, 1), True);
515         TestNext([],    b( 5, 3, 1),  b( 1, 8, 0),    1, 6,   1, 5,   True,  #9'شس');
516 
517         TestStart('Scan full line',  15,   1, 4,   15);
518         TestPreFirst(b( 4, 3, 2), True);
519         TestNext([],    b( 4, 3, 2),  b( 1, 8, 0),    1, 6,   1, 4,   True,  #9'شس');
520 
521         // RTL tab in 2 pieces
522         TestStart('RTL tab in 2 pieces',  15,   1, 7,   15);
523         TestPreFirst(b( 7, 1, 0), True);
524         TestNext([5],   b( 7, 1, 0),  b( 5, 4,-2),    3, 7,   5, 7,   True,  'ي'#9,    b( 5, 3, 1), True);
525         TestNext([],    b( 5, 3, 1),  b( 1, 8, 0),    1, 6,   1, 5,   True,  #9'شس',   b( 7, 8, 0), False);
526         TestEnd(b( 7, 8, 0));
527 
528       {%endregion}
529 
530       {%region  part line}
531         // 1 char parts
532         TestStart('part line - begin',  12,   1, 2,  12);
533         TestPreFirst(b( 2, 6, 0), True);
534         TestNext([100],    b( 2, 6),  b( 1, 8),    1, 2,   1, 2,   True,  'ي',   b( 5, 8, 0), False);
535         TestEnd(b( 5, 8, 0));
536 
537         TestStart('part line - mid',  12,   2, 3,  12);
538         TestPreFirst(b( 3, 5, 0), True);
539         TestNext([100],    b( 3, 5),  b( 2, 6),    2, 3,   2, 3,   True,  ' ',   b( 5, 8, 0), False);
540         TestEnd(b( 5, 8, 0));
541 
542         TestStart('part line - mid',  12,   3, 4,  12);
543         TestPreFirst(b( 4, 3, 0), True);
544         TestNext([100],    b( 4, 3),  b( 3, 5),    3, 4,   3, 4,   True,  'س',   b( 5, 8, 0), False);
545         TestEnd(b( 5, 8, 0));
546 
547         TestStart('part line - end',  12,   4, 5,  12);
548         TestPreFirst(b( 5, 1, 0), True);
549         TestNext([100],    b( 5, 1),  b( 4, 3),    4, 5,   4, 5,   True,  'ش',   b( 5, 8, 0), False);
550         TestEnd(b( 5, 8, 0));
551 
552         // 2 char parts
553         TestStart('part line - begin(2)',  12,   1, 3,  12);
554         TestPreFirst(b( 3, 5, 0), True);
555         TestNext([100],    b( 3, 5),  b( 1, 8),    1, 3,   1, 3,   True,  ' ي');
556         TestEnd;
557 
558         TestStart('part line - mid(2)',  12,   2, 4,  12);
559         TestPreFirst(b( 4, 3, 0), True);
560         TestNext([100],    b( 4, 3),  b( 2, 6),    2, 4,   2, 4,   True,  'س ');
561         TestEnd;
562 
563         TestStart('part line - end(2)',  12,   3, 5,  12);
564         TestPreFirst(b( 5, 1, 0), True);
565         TestNext([100],    b( 5, 1),  b( 3, 5),    3, 5,   3, 5,   True,  'شس');
566         TestEnd;
567 
568         // 1 char parts, several chunks
569         TestStart('part line - begin',  12,   1, 100,  12);
570         TestPreFirst(b( 5, 1, 0), True);
571         TestNext([4],    b( 5, 1),  b( 4, 3),    4, 5,   4, 5,   True,  'ش',   b( 4, 3, 0), True);
572         TestNext([3],    b( 4, 3),  b( 3, 5),    3, 4,   3, 4,   True,  'س',   b( 3, 5, 0), True);
573         TestNext([2],    b( 3, 5),  b( 2, 6),    2, 3,   2, 3,   True,  ' ',   b( 2, 6, 0), True);
574         TestNext([1],    b( 2, 6),  b( 1, 8),    1, 2,   1, 2,   True,  'ي',   b( 5, 8, 0), False);
575         TestEnd(b( 5, 8, 0));
576 
577         // 1 char parts, several chunks
578         TestStart('part line - begin',  12,   1, 100,  12);
579         TestPreFirst(b( 5, 1, 0), True);
580         TestNext([4],    b( 5, 1),  b( 4, 3),    4, 5,   4, 5,   True,  'ش');
581         TestNext([3],    b( 4, 3),  b( 3, 5),    3, 4,   3, 4,   True,  'س');
582         TestNext([0],    b( 3, 5),  b( 1, 8),    1, 3,   1, 3,   True,  ' ي');
583         TestEnd;
584 
585         //TestStart('part line - begin',  12,   1, 100,  12);
586         //TestNext(2,    1, 6,   2,  5,   2,  5,  True,  'شس ');
587         //TestNext(5,    1, 3,   4,  5,   4,  5,  True,  'ي');
588         //TestEnd;
589         //
590         //TestStart('part line - begin',  12,   1, 100,  12);
591         //TestNext(  2,    1, 6,   2,  5,   2,  5,  True,  'شس ');
592         //TestNext([100],    b( 5, 1),  b( 4, 3),    4, 5,   4, 5,   True,  'شس ي');
593         //TestEnd;
594 
595       {%endregion}
596 
597       PopBaseName;
598     {%endregion}
599 
600     {%region  MIXED Rtl/Ltr }
601       PushBaseName('MIXED Rtl/Ltr');
602       {%region  full line}
603         TestStart('Scan full line',  13,   1, 100,   13);
604         TestPreFirst(b( 1, 1, 0), False);
605         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB',    b( 7, 3, 0), True);
606         TestNext([],    b( 7, 3),  b( 3,10),    3, 7,   3, 7,   True,  'شس ي',  b( 7,10, 0), False);
607         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD',    b( 9,12, 0), False);
608         TestEnd(b( 9,12, 0));
609 
610       {%endregion}
611 
612       {%region  parts}
613         TestStart('Scan part line, cut at start',  13,   2, 100,   13);
614         TestPreFirst(b( 2, 2, 0), False);
615         TestNext([],    b( 2, 2),  b( 3, 3),    2, 3,   2, 3,   False, 'B',  b( 7, 3, 0), True);
616         TestNext([],    b( 7, 3),  b( 3,10),    3, 7,   3, 7,   True,  'شس ي',  b( 7,10, 0), False);
617         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD');
618         TestEnd;
619 
620         TestStart('Scan part line, cut at start',  13,   3, 100,   13);
621         TestPreFirst(b( 7, 3, 0), True);
622         TestNext([],    b( 7, 3),  b( 3,10),    3, 7,   3, 7,   True,  'شس ي',  b( 7,10, 0), False);
623         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD');
624         TestEnd;
625 
626         TestStart('Scan part line, cut at start',  13,   4, 100,   13);
627         TestPreFirst(b( 7, 3, 0), True);
628         TestNext([],    b( 7, 3),  b( 4, 8),    4, 7,   4, 7,   True,  'شس ',  b( 7,10, 0), False);
629         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD');
630         TestEnd;
631 
632         TestStart('Scan part line, cut at start',  13,   6, 100,   13);
633         TestPreFirst(b( 7, 3, 0), True);
634         TestNext([],    b( 7, 3),  b( 6, 5),    6, 7,   6, 7,   True,  'ش',  b( 7,10, 0), False);
635         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD');
636         TestEnd;
637 
638         TestStart('Scan part line, cut at start',  13,   7, 100,   13);
639         TestPreFirst(b( 7,10, 0), False);
640         TestNext([],    b( 7,10),  b( 9,12),    7, 9,   7, 9,   False, 'CD');
641         TestEnd;
642 
643         TestStart('Scan part line, cut at start',  13,   8, 100,   13);
644         TestPreFirst(b( 8,11, 0), False);
645         TestNext([],    b( 8,11),  b( 9,12),    8, 9,   8, 9,   False, 'D');
646         TestEnd;
647 
648         TestStart('Scan part line, cut at start',  13,   9, 100,   13);
649         TestEnd;
650 
651 
652         TestStart('Scan part line, cut at end',  13,   1, 8,   13);
653         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB',  b( 7, 3, 0), True);
654         TestNext([],    b( 7, 3),  b( 3,10),    3, 7,   3, 7,   True,  'شس ي',  b( 7,10, 0), False);
655         TestNext([],    b( 7,10),  b( 8,11),    7, 8,   7, 8,   False, 'C');
656         TestEnd;
657 
658         TestStart('Scan part line, cut at end',  13,   1, 7,   13);
659         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB',  b( 7, 3, 0), True);
660         TestNext([],    b( 7, 3),  b( 3,10),    3, 7,   3, 7,   True,  'شس ي');
661         TestEnd;
662 
663         TestStart('Scan part line, cut at end',  13,   1, 6,   13);
664         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB',  b( 6, 5, 0), True);
665         TestNext([],    b( 6, 5),  b( 3,10),    3, 6,   3, 6,   True,  'س ي');
666         TestEnd;
667 
668         TestStart('Scan part line, cut at end',  13,   1, 4,   13);
669         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB',  b( 4, 8, 0), True);
670         TestNext([],    b( 4, 8),  b( 3,10),    3, 4,   3, 4,   True,  'ي');
671         TestEnd;
672 
673         TestStart('Scan part line, cut at end',  13,   1, 3,   13);
674         TestNext([],    b( 1, 1),  b( 3, 3),    1, 3,   1, 3,   False, 'AB');
675         TestEnd;
676 
677         TestStart('Scan part line, cut at end',  13,   1, 2,   13);
678         TestNext([],    b( 1, 1),  b( 2, 2),    1, 2,   1, 2,   False, 'A');
679         TestEnd;
680 
681       {%endregion}
682 
683 
684       {%region}
685         TestStart('Scan full line 18 / hl-token',   20,   9, 30,   20);
686         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق', clRed,   b(12, 16, 0), False);
687         TestEnd(b(12, 16, 0));
688 
689         TestStart('Scan full line 18 / hl-token',   20,  10, 30,   20);
690         TestNext([],    b(12, 8, 0),  b(10,12, 0),   10,12,  10,12,   True,  'شس', clRed,   b(12, 16, 0), False);
691         TestEnd(b(12, 16, 0));
692 
693       {%endregion}
694 
695 
696       PopBaseName;
697     {%endregion}
698 
699 
700     UseViewTokenOnly := False;
701 
702     {%region  LTR only }
703       PushBaseName('LTR-Only - WITH MARKUP');
704 
705       {%region  full line}
706         SynEdit.BlockBegin := Point( 1,1); // clear selection
707         TestStart('Scan full line / hl-token',   1,   1, 99,   1);
708         TestNext([],    b( 1, 1, 0),  b(10,10, 0),    1,10,   1,10,   False, 'unit foo;', clBlack);
709         TestNext([],    b(10,10, 0),  b(99,99, 0),   10,99,  10,99,   False, ' ',         clBlack);
710         TestEnd;
711 
712         SynEdit.BlockBegin := Point(2,1);
713         SynEdit.BlockEnd   := Point(4,1);
714         TestStart('Scan full line / hl-token',   1,   1, 99,   1);
715         TestNext([],    b( 1, 1, 0),  b( 2, 2, 0),    1, 2,   1, 2,   False, 'u',         clBlack);
716         TestNext([],    b( 2, 2, 0),  b( 4, 4, 0),    2, 4,   2, 4,   False, 'ni',        clPurple);
717         TestNext([],    b( 4, 4, 0),  b(10,10, 0),    4,10,   4,10,   False, 't foo;',    clBlack);
718         TestNext([],    b(10,10, 0),  b(99,99, 0),   10,99,  10,99,   False, ' ',         clBlack);
719         TestEnd;
720 
721         SynEdit.BlockBegin := Point(2,1);
722         SynEdit.BlockEnd   := Point(4,1);
723         TestStart('Scan full line / hl-token',   1,   6, 99,   1);
724         TestNext([],    b( 6, 6, 0),  b(10,10, 0),    6,10,   6,10,   False, 'foo;',      clBlack);
725         TestNext([],    b(10,10, 0),  b(99,99, 0),   10,99,  10,99,   False, ' ',         clBlack);
726         TestEnd;
727 
728         SynEdit.BlockBegin := Point(20,1);
729         SynEdit.BlockEnd   := Point(30,1);
730         TestStart('Scan full line / hl-token',   1,   1, 99,   1);
731         TestNext([],    b( 1, 1, 0),  b(10,10, 0),    1,10,   1,10,   False, 'unit foo;', clBlack);
732         TestNext([],    b(10,10, 0),  b(20,20, 0),   10,20,  10,20,   False, ' ',         clBlack);
733         TestNext([],    b(20,20, 0),  b(30,30, 0),   20,30,  20,30,   False, ' ',         clPurple);
734         TestNext([],    b(30,30, 0),  b(99,99, 0),   30,99,  30,99,   False, ' ',         clBlack);
735         TestEnd;
736 
737         SynEdit.BlockBegin := Point( 8,1);
738         SynEdit.BlockEnd   := Point(30,1);
739         TestStart('Scan full line / hl-token',   1,   1, 99,   1);
740         TestNext([],    b( 1, 1, 0),  b( 8, 8, 0),    1, 8,   1, 8,   False, 'unit fo',    clBlack);
741         TestNext([],    b( 8, 8, 0),  b(10,10, 0),    8,10,   8,10,   False, 'o;',       clPurple);
742         TestNext([],    b(10,10, 0),  b(30,30, 0),   10,30,  10,30,   False, ' ',         clPurple);
743         TestNext([],    b(30,30, 0),  b(99,99, 0),   30,99,  30,99,   False, ' ',         clBlack);
744         TestEnd;
745 
746 
747         // Paint eol only
748         SynEdit.BlockBegin := Point( 1,1); // clear selection
749         TestStart('Scan full line / hl-token',   1,  10, 99,   1);
750         TestNext([],    b(10,10, 0),  b(99,99, 0),   10,99,  10,99,   False, ' ',         clBlack);
751         TestEnd;
752 
753         SynEdit.BlockBegin := Point(20,1);
754         SynEdit.BlockEnd   := Point(30,1);
755         TestStart('Scan full line / hl-token',   1,  25, 99,   1);
756         TestNext([],    b(25,25, 0),  b(30,30, 0),   25,30,  25,30,   False, ' ',         clPurple);
757         TestNext([],    b(30,30, 0),  b(99,99, 0),   30,99,  30,99,   False, ' ',         clBlack);
758         TestEnd;
759       {%endregion}
760 
761       {%region}
762         SynEdit.Options :=SynEdit.Options + [eoBracketHighlight];
763         SynEdit.BracketHighlightStyle := sbhsBoth;
764         SynEdit.BracketMatchColor.Foreground := clMaroon;
765         SynEdit.BracketMatchColor.FrameColor := clBlack;
766         SynEdit.BracketMatchColor.FrameEdges := sfeAround;
767         SynEdit.BracketMatchColor.FrameStyle := slsSolid;
768 
769         SynEdit.LogicalCaretXY := point(2, 16);
770         TestStart('Scan full line / hl-token',   16,  1, 10,   16);
771         TestNext([],    b( 1, 1, 0),  b( 5, 2, 0),   1, 5,   1, 5,   False, #9,         clBlack);
772         AssertEquals(Name + ' #9 No-Frame l',   clNone,  Token.Attr.FrameSideColors[bsLeft]);
773         AssertEquals(Name + ' #9 No-Frame r',   clNone,  Token.Attr.FrameSideColors[bsRight]);
774         TestNext([],    b( 5, 2, 0),  b( 6, 3, 0),   5, 6,   5, 6,   False, '(',        clMaroon);
775         AssertEquals(Name + ' "(" Frame t',   clBlack,  Token.Attr.FrameSideColors[bsTop]);
776         AssertEquals(Name + ' "(" Frame l',   clBlack,  Token.Attr.FrameSideColors[bsLeft]);
777         AssertEquals(Name + ' "(" Frame r',   clBlack,  Token.Attr.FrameSideColors[bsRight]);
778         TestNext([],    b( 6, 3, 0),  b( 9, 4, 0),   6, 9,   6, 9,   False, #9,         clBlack);
779       {%endregion}
780 
781 
782 
783     {%endregion}
784 
785     {%region  RTL only }
786       PushBaseName('RTL-Only - WITH MARKUP');
787       {%region  full line}
788         SynEdit.BlockBegin := Point( 1,1); // clear selection
789         TestStart('Scan full line',  11,   1, 90,   11);
790         TestPreFirst(b( 3, 1, 0), True);
791         TestNext([],    b( 3, 1, 0),  b( 1, 5, 0),    1, 3,   1, 3,   True,  'شس',   clBlack);
792         TestNext([],    b( 3, 5, 0),  b(90,92, 0),    3,90,   3,90,   False, ' ',    clBlack);
793         TestEnd;
794 
795         SynEdit.BlockBegin := Point(3,12); // 2nd logical char
796         SynEdit.BlockEnd   := Point(5,12);
797         TestStart('Scan full line',  12,   1, 90,   12);
798         TestPreFirst(b( 5, 1, 0), True);
799         TestNext([],    b( 5, 1, 0),  b( 4, 3, 0),    4, 5,   4, 5,   True,  'ش',    clBlack);
800         TestNext([],    b( 4, 3, 0),  b( 3, 5, 0),    3, 4,   3, 4,   True,  'س',    clPurple);
801         TestNext([],    b( 3, 5, 0),  b( 1, 8, 0),    1, 3,   1, 3,   True,  ' ي',   clBlack);
802         TestNext([],    b( 5, 8, 0),  b(90,93, 0),    5,90,   5,90,   False, ' ',    clBlack);
803         TestEnd;
804       {%endregion}
805       PopBaseName;
806     {%endregion}
807 
808 
809         // HL token ends exactly at LTR to RTL change
810 
811         SynEdit.BlockBegin := Point(1,1);
812         TestStart('Scan full line 17 / hl-token',   17,   1, 30,   17);
813         TestNext([],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, '//',            clBlue);
814         TestNext([],    b(16, 3, 0),  b( 3,25, 0),    3,16,   3,16,   True,  'شس يشس ي(شس ي', clBlack);
815         TestNext([],    b(16,25, 0),  b(30,39, 0),   16,30,  16,30,   False, ' ',             clBlack);
816         TestEnd;
817 
818         SynEdit.BlockBegin := Point( 3,17);
819         SynEdit.BlockEnd   := Point(25,17);
820         TestStart('Scan full line 17 / hl-token',   17,   1, 30,   17);
821         TestNext([],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, '//',            clBlue);
822         TestNext([],    b(16, 3, 0),  b( 3,25, 0),    3,16,   3,16,   True,  'شس يشس ي(شس ي', clPurple);
823         TestNext([],    b(16,25, 0),  b(30,39, 0),   16,30,  16,30,   False, ' ',             clBlack);
824         TestEnd;
825 
826         SynEdit.BlockBegin := Point( 3,17);
827         SynEdit.BlockEnd   := Point(22,17); // 2 chars off
828         TestStart('Scan full line 17 / hl-token',   17,   1, 30,   17);
829         TestNext([],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, '//',          clBlue);
830         TestNext([],    b(16, 3, 0),  b( 5,22, 0),    5,16,   5,16,   True,  'شس يشس ي(شس', clPurple);
831         TestNext([],    b( 5,22, 0),  b( 3,25, 0),    3, 5,   3, 5,   True,  ' ي',          clBlack);
832         TestNext([],    b(16,25, 0),  b(30,39, 0),   16,30,  16,30,   False, ' ',           clBlack);
833         TestEnd;
834 
835         SynEdit.BlockBegin := Point( 7,17); // 2 chars off
836         SynEdit.BlockEnd   := Point(25,17);
837         TestStart('Scan full line 17 / hl-token',   17,   1, 30,   17);
838         TestNext([],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, '//',          clBlue);
839         TestNext([],    b(16, 3, 0),  b(14, 7, 0),   14,16,  14,16,   True,  'شس',          clBlack);
840         TestNext([],    b(14, 7, 0),  b( 3,25, 0),    3,14,   3,14,   True,  ' يشس ي(شس ي', clPurple);
841         TestNext([],    b(16,25, 0),  b(30,39, 0),   16,30,  16,30,   False, ' ',           clBlack);
842         TestEnd;
843 
844         SynEdit.BlockBegin := Point( 7,17);
845         SynEdit.BlockEnd   := Point(22,17);
846         TestStart('Scan full line 17 / hl-token',   17,   1, 30,   17);
847         TestNext([],    b( 1, 1, 0),  b( 3, 3, 0),    1, 3,   1, 3,   False, '//',          clBlue);
848         TestNext([],    b(16, 3, 0),  b(14, 7, 0),   14,16,  14,16,   True,  'شس',          clBlack);
849         TestNext([],    b(14, 7, 0),  b( 5,22, 0),    5,14,   5,14,   True,  ' يشس ي(شس', clPurple);
850         TestNext([],    b( 5,22, 0),  b( 3,25, 0),    3, 5,   3, 5,   True,  ' ي',          clBlack);
851         TestNext([],    b(16,25, 0),  b(30,39, 0),   16,30,  16,30,   False, ' ',           clBlack);
852         TestEnd;
853 
854         // Mixed RTL (and weak)
855         // increase LeftChar
856         SynEdit.BlockBegin := Point(1,1);
857         TestStart('Scan full line 18 / hl-token',   18,   1, 30,   18);
858         TestNext([],    b( 1, 1, 0),  b( 7, 7, 0),    1, 7,   1, 7,   False, 'a     ',  clGreen);
859         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
860         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
861         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
862         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
863         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
864         TestEnd;
865 
866         TestStart('Scan full line 18 / hl-token',   18,   2, 30,   18);
867         TestNext([],    b( 2, 2, 0),  b( 7, 7, 0),    2, 7,   2, 7,   False, '     ',   clGreen);
868         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
869         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
870         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
871         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
872         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
873         TestEnd;
874 
875         TestStart('Scan full line 18 / hl-token',   18,   3, 30,   18);
876         TestNext([],    b( 3, 3, 0),  b( 7, 7, 0),    3, 7,   3, 7,   False, '    ',    clGreen);
877         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
878         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
879         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
880         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
881         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
882         TestEnd;
883 
884         TestStart('Scan full line 18 / hl-token',   18,   4, 30,   18);
885         TestNext([],    b( 4, 4, 0),  b( 7, 7, 0),    4, 7,   4, 7,   False, '   ',     clGreen);
886         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
887         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
888         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
889         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
890         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
891         TestEnd;
892 
893         TestStart('Scan full line 18 / hl-token',   18,   5, 30,   18);
894         TestNext([],    b( 5, 5, 0),  b( 7, 7, 0),    5, 7,   5, 7,   False, '  ',      clGreen);
895         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
896         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
897         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
898         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
899         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
900         TestEnd;
901 
902         TestStart('Scan full line 18 / hl-token',   18,   6, 30,   18);
903         TestNext([],    b( 6, 6, 0),  b( 7, 7, 0),    6, 7,   6, 7,   False, ' ',       clGreen);
904         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
905         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
906         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
907         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
908         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
909         TestEnd;
910 
911         TestStart('Scan full line 18 / hl-token',   18,   7, 30,   18);
912         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
913         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
914         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
915         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
916         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
917         TestEnd;
918 
919         TestStart('Scan full line 18 / hl-token',   18,   8, 30,   18);
920         TestNext([],    b(10, 8, 0),  b( 8,12, 0),    8,10,   8,10,   True,  'شس',      clBlue);
921         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
922         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
923         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
924         TestEnd;
925 
926         TestStart('Scan full line 18 / hl-token',   18,   9, 30,   18);
927         TestNext([],    b(10, 8, 0),  b( 9,10, 0),    9,10,   9,10,   True,  'ش',      clBlue);
928         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
929         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
930         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
931         TestEnd;
932 
933         TestStart('Scan full line 18 / hl-token',   18,  10, 30,   18);
934         TestNext([],    b(10,12, 0),  b(11,13, 0),   10,11,  10,11,   False, '''',      clYellow);
935         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
936         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
937         TestEnd;
938 
939         TestStart('Scan full line 18 / hl-token',   18,  11, 30,   18);
940         TestNext([],    b(11,13, 0),  b(12,14, 0),   11,12,  11,12,   False, 'b',       clRed);
941         TestNext([],    b(12,14, 0),  b(30,32, 0),   12,30,  12,30,   False, ' ',       clBlack);
942         TestEnd;
943 
944         // Mixed RTL (and weak), end in RTL
945         // increase LeftChar
946         SynEdit.BlockBegin := Point(1,1);
947         TestStart('Scan full line 18 / hl-token',   19,   1, 30,   19);
948         TestNext([],    b( 1, 1, 0),  b( 7, 7, 0),    1, 7,   1, 7,   False, 'a     ',  clGreen);
949         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
950         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
951         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
952         TestEnd;
953 
954         TestStart('Scan full line 18 / hl-token',   19,   2, 30,   19);
955         TestNext([],    b( 2, 2, 0),  b( 7, 7, 0),    2, 7,   2, 7,   False, '     ',   clGreen);
956         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
957         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
958         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
959         TestEnd;
960 
961         TestStart('Scan full line 18 / hl-token',   19,   3, 30,   19);
962         TestNext([],    b( 3, 3, 0),  b( 7, 7, 0),    3, 7,   3, 7,   False, '    ',    clGreen);
963         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
964         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
965         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
966         TestEnd;
967 
968         TestStart('Scan full line 18 / hl-token',   19,   4, 30,   19);
969         TestNext([],    b( 4, 4, 0),  b( 7, 7, 0),    4, 7,   4, 7,   False, '   ',     clGreen);
970         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
971         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
972         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
973         TestEnd;
974 
975         TestStart('Scan full line 18 / hl-token',   19,   5, 30,   19);
976         TestNext([],    b( 5, 5, 0),  b( 7, 7, 0),    5, 7,   5, 7,   False, '  ',      clGreen);
977         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
978         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
979         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
980         TestEnd;
981 
982         TestStart('Scan full line 18 / hl-token',   19,   6, 30,   19);
983         TestNext([],    b( 6, 6, 0),  b( 7, 7, 0),    6, 7,   6, 7,   False, ' ',       clGreen);
984         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
985         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
986         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
987         TestEnd;
988 
989         TestStart('Scan full line 18 / hl-token',   19,   7, 30,   19);
990         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
991         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
992         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
993         TestEnd;
994 
995         TestStart('Scan full line 18 / hl-token',   19,   8, 30,   19);
996         TestNext([],    b(12, 8, 0),  b( 8,16, 0),    8,12,   8,12,   True,  'شسقف',      clBlue);
997         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
998         TestEnd;
999 
1000         TestStart('Scan full line 18 / hl-token',   19,   9, 30,   19);
1001         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clBlue);
1002         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1003         TestEnd;
1004 
1005         TestStart('Scan full line 18 / hl-token',   19,  10, 30,   19);
1006         TestNext([],    b(12, 8, 0),  b(10,12, 0),   10,12,  10,12,   True,  'شس',      clBlue);
1007         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1008         TestEnd;
1009 
1010         TestStart('Scan full line 18 / hl-token',   19,  11, 30,   19);
1011         TestNext([],    b(12, 8, 0),  b(11,10, 0),   11,12,  11,12,   True,  'ش',      clBlue);
1012         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1013         TestEnd;
1014 
1015         TestStart('Scan full line 18 / hl-token',   19,  12, 30,   19);
1016         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1017         TestEnd;
1018 
1019         TestStart('Scan full line 18 / hl-token',   19,  13, 30,   19);
1020         TestNext([],    b(13,17, 0),  b(30,34, 0),   13,30,  13,30,   False, ' ',       clBlack);
1021         TestEnd;
1022 
1023     // Change highlight, so last char is diff color
1024 
1025         SynEdit.BlockBegin := Point(1,1);
1026         TestStart('Scan full line 18 / hl-token',   20,   1, 30,   20);
1027         TestNext([],    b( 1, 1, 0),  b( 7, 7, 0),    1, 7,   1, 7,   False, 'a     ',  clGreen);
1028         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1029         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1030         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1031         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1032         TestEnd;
1033 
1034         TestStart('Scan full line 18 / hl-token',   20,   2, 30,   20);
1035         TestNext([],    b( 2, 2, 0),  b( 7, 7, 0),    2, 7,   2, 7,   False, '     ',   clGreen);
1036         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1037         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1038         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1039         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1040         TestEnd;
1041 
1042         TestStart('Scan full line 18 / hl-token',   20,   3, 30,   20);
1043         TestNext([],    b( 3, 3, 0),  b( 7, 7, 0),    3, 7,   3, 7,   False, '    ',    clGreen);
1044         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1045         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1046         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1047         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1048         TestEnd;
1049 
1050         TestStart('Scan full line 18 / hl-token',   20,   4, 30,   20);
1051         TestNext([],    b( 4, 4, 0),  b( 7, 7, 0),    4, 7,   4, 7,   False, '   ',     clGreen);
1052         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1053         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1054         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1055         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1056         TestEnd;
1057 
1058         TestStart('Scan full line 18 / hl-token',   20,   5, 30,   20);
1059         TestNext([],    b( 5, 5, 0),  b( 7, 7, 0),    5, 7,   5, 7,   False, '  ',      clGreen);
1060         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1061         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1062         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1063         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1064         TestEnd;
1065 
1066         TestStart('Scan full line 18 / hl-token',   20,   6, 30,   20);
1067         TestNext([],    b( 6, 6, 0),  b( 7, 7, 0),    6, 7,   6, 7,   False, ' ',       clGreen);
1068         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1069         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1070         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1071         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1072         TestEnd;
1073 
1074         TestStart('Scan full line 18 / hl-token',   20,   7, 30,   20);
1075         TestNext([],    b( 7, 7, 0),  b( 8, 8, 0),    7, 8,   7, 8,   False, '''',      clYellow);
1076         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1077         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1078         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1079         TestEnd;
1080 
1081         TestStart('Scan full line 18 / hl-token',   20,   8, 30,   20);
1082         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1083         TestNext([],    b( 9,14, 0),  b( 8,16, 0),    8, 9,   8, 9,   True,  'ف',      clBlue);
1084         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1085         TestEnd;
1086 
1087         TestStart('Scan full line 18 / hl-token',   20,   9, 30,   20);
1088         TestNext([],    b(12, 8, 0),  b( 9,14, 0),    9,12,   9,12,   True,  'شسق',      clRed);
1089         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1090         TestEnd;
1091 
1092         TestStart('Scan full line 18 / hl-token',   20,  10, 30,   20);
1093         TestNext([],    b(12, 8, 0),  b(10,12, 0),   10,12,  10,12,   True,  'شس',      clRed);
1094         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1095         TestEnd;
1096 
1097         TestStart('Scan full line 18 / hl-token',   20,  11, 30,   20);
1098         TestNext([],    b(12, 8, 0),  b(11,10, 0),   11,12,  11,12,   True,  'ش',      clRed);
1099         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1100         TestEnd;
1101 
1102         TestStart('Scan full line 18 / hl-token',   20,  12, 30,   20);
1103         TestNext([],    b(12,16, 0),  b(30,34, 0),   12,30,  12,30,   False, ' ',       clBlack);
1104         TestEnd;
1105 
1106         TestStart('Scan full line 18 / hl-token',   20,  13, 30,   20);
1107         TestNext([],    b(13,17, 0),  b(30,34, 0),   13,30,  13,30,   False, ' ',       clBlack);
1108         TestEnd;
1109 
1110 
1111 
1112 
1113 
1114 
1115 
1116     SynEdit.ViewedTextBuffer.DisplayView.FinishHighlighterTokens;
1117 
1118   end;
1119 begin
1120   PushBaseName('Incl PreFirst');
1121   SkipPreFirst := False;
1122   DoTests;
1123   PopPushBaseName('Excl PreFirst');
1124   SkipPreFirst := True;
1125   DoTests;
1126   PopBaseName;
1127 end;
1128 
1129 initialization
1130   RegisterTest(TTestSynTextArea);
1131 
1132 end.
1133 
1134