1 {-------------------------------------------------------------------------------
2 The contents of this file are subject to the Mozilla Public License
3 Version 1.1 (the "License"); you may not use this file except in compliance
4 with the License. You may obtain a copy of the License at
5 http://www.mozilla.org/MPL/
6 
7 Software distributed under the License is distributed on an "AS IS" basis,
8 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9 the specific language governing rights and limitations under the License.
10 
11 Alternatively, the contents of this file may be used under the terms of the
12 GNU General Public License Version 2 or later (the "GPL"), in which case
13 the provisions of the GPL are applicable instead of those above.
14 If you wish to allow use of your version of this file only under the terms
15 of the GPL and not to allow others to use your version of this file
16 under the MPL, indicate your decision by deleting the provisions above and
17 replace them with the notice and other provisions required by the GPL.
18 If you do not delete the provisions above, a recipient may use your version
19 of this file under either the MPL or the GPL.
20 
21 This file was added to the Lazarus branch of SynEdit.
22 The original Author is M Friebe
23 }
24 
25 { This unit provide Highlighting for diff files
26   Currently supported formats: Context, Unified
27   //Todo: support original diff
28 }
29 
30 unit SynHighlighterDiff;
31 
32 {$I SynEdit.inc}
33 
34 interface
35 
36 uses
37   Classes, Graphics, math,
38   SynEditHighlighter, SynEditHighlighterFoldBase;
39 
40 type
41   TtkTokenKind = (tkNull, tkUnknown, tkSpace,
42                   // File Header
43                   tkFileOrigMark, tkFileNewMark,
44                   tkFileOrig, tkFileNew,
45                   // Chunk Header
46                   tkChunkSeparator,
47                   tkChunkMixedMark, tkChunkOrigMark, tkChunkNewMark,
48                   tkChunkMixed, tkChunkOrig, tkChunkNew,
49                   // Lines
50                   tkLineRemovedMark, tkLineAddedMark, tkLineChangedMark, tkLineContextMark,
51                   tkLineRemoved, tkLineAdded, tkLineChanged, tkLineContext
52                  );
53 
54   TRangeState = (rsUnknown,
55                  // Context
56                  rsCtxFirst,
57                    rsCtxUnknown,
58                    rsCtxFileOrig, rsCtxFileNew,
59                    rsCtxChunkHeader, rsCtxChunkOrig, rsCtxChunkNew,
60                    rsCtxLineRemoved, rsCtxLineAdded, rsCtxLineChanged,
61                    rsCtxLineContext,
62                  rsCtxLast,
63                  // Unified
64                  rsUniFirst,
65                    rsUniUnknown,
66                    rsUniFileOrig, rsUniFileNew,
67                    rsUniChunkHeader,
68                    rsUniLineRemoved, rsUniLineAdded,
69                    rsUniLineContext,
70                  rsUniLast
71                 );
72 
73   TDiffCodeFoldBlockType = (
74     cfbtDiffFile,
75     cfbtDiffChunk,
76     cfbtDiffChunkSect,
77     cfbtDiffNone
78     );
79 
80   TProcTableProc = procedure of object;
81 
82 const
83   CountDiffCodeFoldBlockOffset: Pointer =
84     Pointer(PtrInt(Integer(high(TDiffCodeFoldBlockType))+1));
85 
86 type
87 
88   { TSynDiffSyn }
89 
90   TSynDiffSyn = class(TSynCustomFoldHighlighter)
91   private
92     fRange: TRangeState;
93     fLine: PChar;
94     fLineNumber: Integer;
95     Run: LongInt;
96     fTokenPos: Integer;
97     FTokenID: TtkTokenKind;
98   private
99     fProcTable: array[#0..#255] of TProcTableProc;
100     procedure MakeMethodTables;
101     procedure CRProc;
102     procedure LFProc;
103     procedure NullProc;
104     procedure LineProc;
105     procedure UnknownProc;
106     procedure AsteriskProc;
107     procedure MinusProc;
108     procedure PlusProc;
109     procedure ExclamationProc;
110     procedure AtProc;
111     procedure SpaceProc;
112   private
113     FChunkMarkerAttri: TSynHighlighterAttributes;
114     FChunkMixedAttri: TSynHighlighterAttributes;
115     FChunkNewAttri: TSynHighlighterAttributes;
116     FChunkOldAttri: TSynHighlighterAttributes;
117     FLineAddedAttri: TSynHighlighterAttributes;
118     FLineChangedAttri: TSynHighlighterAttributes;
119     FLineContextAttri: TSynHighlighterAttributes;
120     FLineRemovedAttri: TSynHighlighterAttributes;
121     FNewFileAttri: TSynHighlighterAttributes;
122     FOrigFileAttri: TSynHighlighterAttributes;
123     FSpaceAttri: TSynHighlighterAttributes;
124     FUnknownAttri: TSynHighlighterAttributes;
125   protected
GetSampleSourcenull126     function GetSampleSource : String; override;
127   public
128     constructor Create(AOwner: TComponent); override;
129     destructor  Destroy; override;
130 
GetTokennull131     function  GetToken: String; override;
132     procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
GetTokenAttributenull133     function  GetTokenAttribute: TSynHighlighterAttributes; override;
GetTokenKindnull134     function  GetTokenKind: integer; override;
GetTokenPosnull135     function  GetTokenPos: Integer; override;
GetTokenIDnull136     function  GetTokenID: TtkTokenKind;
137 
138     procedure Next; override;
GetEolnull139     function GetEol: Boolean; override;
140 
141     procedure SetLine(const NewValue: String;
142       LineNumber: Integer); override;
GetRangenull143     function GetRange: Pointer; override;
144     procedure SetRange(Value: Pointer); override;
145     procedure ResetRange; override;
146 
GetDefaultAttributenull147     function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes; override;
GetLanguageNamenull148     class function GetLanguageName: string; override;
149   protected
150     // folding
151     procedure CreateRootCodeFoldBlock; override;
152 
StartDiffCodeFoldBlocknull153     function StartDiffCodeFoldBlock(ABlockType: TDiffCodeFoldBlockType): TSynCustomCodeFoldBlock;
154     procedure EndDiffCodeFoldBlock;
TopDiffCodeFoldBlockTypenull155     function TopDiffCodeFoldBlockType(DownIndex: Integer = 0): TDiffCodeFoldBlockType;
156 
GetFoldConfigInstancenull157     function GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig; override;
GetFoldConfigCountnull158     function GetFoldConfigCount: Integer; override;
GetFoldConfigInternalCountnull159     function GetFoldConfigInternalCount: Integer; override;
160   published
161     property UnknownAttri: TSynHighlighterAttributes read FUnknownAttri write FUnknownAttri;
162     property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
163     property OrigFileAttri: TSynHighlighterAttributes read FOrigFileAttri write FOrigFileAttri;
164     property NewFileAttri: TSynHighlighterAttributes read FNewFileAttri write FNewFileAttri;
165     property ChunkMarkerAttri: TSynHighlighterAttributes read FChunkMarkerAttri write FChunkMarkerAttri;
166     property ChunkNewAttri: TSynHighlighterAttributes read FChunkNewAttri write FChunkNewAttri;
167     property ChunkOldAttri: TSynHighlighterAttributes read FChunkOldAttri write FChunkOldAttri;
168     property ChunkMixedAttri: TSynHighlighterAttributes read FChunkMixedAttri write FChunkMixedAttri;
169     property LineAddedAttri: TSynHighlighterAttributes read FLineAddedAttri write FLineAddedAttri;
170     property LineRemovedAttri: TSynHighlighterAttributes read FLineRemovedAttri write FLineRemovedAttri;
171     property LineChangedAttri: TSynHighlighterAttributes read FLineChangedAttri write FLineChangedAttri;
172     property LineContextAttri: TSynHighlighterAttributes read FLineContextAttri write FLineContextAttri;
173   end;
174 
175 implementation
176 
177 uses
178   SynEditStrConst;
179 
180 
181 { TSynDiffSyn }
182 
183 procedure TSynDiffSyn.MakeMethodTables;
184 var
185   I: Char;
186 begin
187   for I := #0 to #255 do
188     case I of
189       #13: fProcTable[I] := @CRProc;
190       #10: fProcTable[I] := @LFProc;
191       #0: fProcTable[I] :=  @NullProc;
192       '*': fProcTable[I] := @AsteriskProc;
193       '-': fProcTable[I] := @MinusProc;
194       '+': fProcTable[I] := @PlusProc;
195       '!': fProcTable[I] := @ExclamationProc;
196       '@': fProcTable[I] := @AtProc;
197       ' ': fProcTable[I] := @SpaceProc;
198     else fProcTable[I] := @UnknownProc;
199     end;
200 end;
201 
202 procedure TSynDiffSyn.CRProc;
203 begin
204   fTokenID := tkSpace;
205   Inc(Run);
206   if (fLine[Run] = #10) then Inc(Run);
207 end;
208 
209 procedure TSynDiffSyn.LFProc;
210 begin
211   fTokenID := tkSpace;
212   inc(Run);
213 end;
214 
215 procedure TSynDiffSyn.NullProc;
216 begin
217   fTokenID := tkNull;
218 end;
219 
220 procedure TSynDiffSyn.LineProc;
221 var
222   l: Integer;
223 begin
224   case fRange of
225     rsCtxFileOrig, rsUniFileOrig: FTokenID := tkFileOrig;
226     rsCtxFileNew, rsUniFileNew:   FTokenID := tkFileNew;
227     rsCtxChunkNew: begin
228         l := length(fLine);
229         if fLine[Run] = '-' then begin
230           FTokenID := tkChunkNewMark;
231           while (Run < l-1) and (fLine[Run] = '-') do inc(Run);
232         end else begin
233           FTokenID := tkChunkNew;
234           while (Run < l-1) and (fLine[Run] <> '-') do inc(Run);
235         end;
236       end;
237     rsCtxChunkOrig: begin
238         l := length(fLine);
239         if fLine[Run] = '*' then begin
240           FTokenID := tkChunkOrigMark;
241           while (Run < l-1) and (fLine[Run] = '*') do inc(Run);
242         end else begin
243           FTokenID := tkChunkOrig;
244           while (Run < l-1) and (fLine[Run] <> '*') do inc(Run);
245         end;
246       end;
247     rsUniChunkHeader: begin
248         l := length(fLine);
249         if fLine[Run] = '@' then begin
250           FTokenID := tkChunkMixedMark;
251           while (Run < l-1) and (fLine[Run] = '@') do inc(Run);
252         end else begin
253           FTokenID := tkChunkMixed;
254           while (Run < l-1) and (fLine[Run] <> '@') do inc(Run);
255         end;
256       end;
257     rsCtxLineRemoved, rsUniLineRemoved: FTokenID := tkLineRemoved;
258     rsCtxLineAdded, rsUniLineAdded:     FTokenID := tkLineAdded;
259     rsCtxLineChanged:                   FTokenID := tkLineChanged;
260     rsCtxLineContext, rsUniLineContext: FTokenID := tkLineContext;
261     else begin
262       FTokenID := tkUnknown;
263     end;
264   end;
265   Run := length(fLine); // #0 NullProc
266 end;
267 
268 procedure TSynDiffSyn.UnknownProc;
269 begin
270   if (fRange in [rsCtxFirst..rsCtxLast]) then
271     fRange := rsCtxUnknown
272   else if (fRange in [rsUniFirst..rsUniLast]) then
273     fRange := rsUniUnknown
274   else
275     fRange := rsUnknown;
276   FTokenID := tkUnknown;
277   Run := length(fLine);
278 end;
279 
280 procedure TSynDiffSyn.AsteriskProc;
281 var
282   l: Integer;
283 begin
284   (* Could be:
285      *** /path/to/original   # orig file                     (Context Format)
286      ***************         # start of chunk                (Context Format)
287      *** 10,15 ****          # chunk: lines in orig file     (Context Format)
288   *)
289   l := length(fLine);
290   if (not (fRange in [rsUnknown, rsCtxFirst..rsCtxLast])) or
291      (l < 4) or (fLine[1] <> '*') or (fLine[2] <> '*')
292   then begin
293     UnknownProc;
294     exit;
295   end;
296 
297   if fLine[3] = '*' then begin
298     // ***************
299     fRange := rsCtxChunkHeader;
300     FTokenID := tkChunkSeparator;
301     Run := l;
302     exit;
303   end;
304 
305   if fLine[3] = ' ' then begin
306     if fRange in [rsCtxChunkHeader..rsCtxChunkNew] then begin
307       // *** 10,15 ****
308       fRange := rsCtxChunkOrig;
309       FTokenID := tkChunkOrigMark;
310       Run := 3;
311     end
312     else begin
313       // *** /path/to/original
314       fRange := rsCtxFileOrig;
315       FTokenID := tkFileOrigMark;
316       Run := 3;
317     end;
318   end
319   else
320     UnknownProc;
321 end;
322 
323 procedure TSynDiffSyn.MinusProc;
324 var
325   l: Integer;
326 begin
327   (* Could be:
328      --- /path/to/new        # new file                      (Context) [usually after *** / path/to/orig]
329      --- 10,15 ----          # chunk: lines in new file      (Context)
330      - foo                   # Removed Line                  (Context)
331      --- /path/to/original   # orig file                     (Unified) [usually before +++ / path/to/new]
332      -foo                    # Removed Line                  (Unified)
333   *)
334 
335   l := length(fLine);
336   if (l > 4) and (fLine[1] = '-') and (fLine[2] = '-') and (fLine[3] = ' ') then begin
337     // Todo: this check is unsufficent in Unified format; need to track amount of lines in Chunk
338     if fRange in [rsUnknown, rsUniFirst..rsUniLast] then begin
339       // --- /path/to/original   # orig file                   (Unified)
340       fRange := rsUniFileOrig;
341       FTokenID := tkFileOrigMark;
342       Run := 3;
343     end
344     else if fRange in [rsCtxFileOrig] then begin
345       // --- /path/to/new        # new file                    (Context)
346       fRange := rsCtxFileNew;
347       FTokenID := tkFileNewMark;
348       Run := 3;
349     end
350     else begin
351       // --- 10,15 ----          # new line                    (Context)
352       fRange := rsCtxChunkNew;
353       FTokenID := tkChunkNewMark;
354       Run := 3;
355     end;
356 
357     exit;
358   end;
359 
360   if fRange = rsUnknown then begin
361     FTokenID := tkUnknown;
362     Run := l;
363     exit;
364   end;
365 
366   if (fRange in [rsCtxFirst..rsCtxLast]) then begin
367     fRange := rsCtxLineRemoved;
368     Run := Min(l, 2);
369   end else begin
370     fRange := rsUniLineRemoved;
371     Run := 1;
372   end;
373   FTokenID := tkLineRemovedMark;
374 end;
375 
376 procedure TSynDiffSyn.PlusProc;
377 var
378   l: Integer;
379 begin
380   (* Could be:
381      + foo                   # Removed Line                  (Context)
382      +++ /path/to/new        # orig file                     (Unified)
383      +foo                    # Removed Line                  (Unified)
384   *)
385 
386   l := length(fLine);
387   if (l > 4) and (fLine[1] = '+') and (fLine[2] = '+') and (fLine[3] = ' ') then begin
388     // Todo: this check is unsufficent in Unified format; need to track amount of lines in Chunk
389     if fRange in [rsUnknown, rsUniFirst..rsUniLast] then begin
390       // --- /path/to/new      # new file                    (Unified)
391       fRange := rsUniFileNew;
392       FTokenID := tkFileNewMark;
393       Run := 3;
394       exit;
395     end;
396   end;
397 
398   if fRange = rsUnknown then begin
399     FTokenID := tkUnknown;
400     Run := l;
401     exit;
402   end;
403 
404   if (fRange in [rsCtxFirst..rsCtxLast]) then begin
405     fRange := rsCtxLineAdded;
406     Run := Min(l, 2);
407   end else begin
408     fRange := rsUniLineAdded;
409     Run := 1;
410   end;
411   FTokenID := tkLineAddedMark;
412 end;
413 
414 procedure TSynDiffSyn.ExclamationProc;
415 var
416   l: Integer;
417 begin
418   (* Could be:
419      ! foo                   # Changed Line                  (Context)
420   *)
421 
422   l := length(fLine);
423   if (fRange in [rsCtxFirst..rsCtxLast]) and (l >= 2) and (fLine[1] = ' ')
424   then begin
425     fRange := rsCtxLineChanged;
426     FTokenID := tkLineChangedMark;
427     Run := Min(l, 2);
428     exit;
429   end;
430 
431   UnknownProc;
432 end;
433 
434 procedure TSynDiffSyn.AtProc;
435 var
436   l: Integer;
437 begin
438   (* Could be:
439      @@ -1,3 +1,9 @@         # Start of Chunk                (Unified)
440   *)
441 
442   l := length(fLine);
443   if (fRange in [rsCtxFirst..rsCtxLast]) or
444      (l < 3) or (fLine[1] <> '@') or (fLine[2] <> ' ')
445   then begin
446     UnknownProc;
447     exit;
448   end;
449 
450   fRange := rsUniChunkHeader;
451   FTokenID := tkChunkMixedMark;
452     Run := Min(l, 2);
453 end;
454 
455 procedure TSynDiffSyn.SpaceProc;
456 begin
457   (* Could be:
458      " foo"                  # Context Line                  (Context, Unified)
459   *)
460 
461   if fRange = rsUnknown then
462     UnknownProc;
463 
464   if (fRange in [rsCtxFirst..rsCtxLast]) then begin
465     fRange := rsCtxLineContext;
466     Run := Min(length(fLine), 2);
467   end else begin
468     fRange := rsUniLineContext;
469     Run := 1;
470   end;
471 
472   FTokenID := tkChunkMixedMark;
473 end;
474 
GetSampleSourcenull475 function TSynDiffSyn.GetSampleSource: string;
476 begin
477   Result := ''#13#10 +
478             '';
479 end;
480 
481 constructor TSynDiffSyn.Create(AOwner: TComponent);
482 begin
483   inherited Create(AOwner);
484 
485   FUnknownAttri := TSynHighlighterAttributes.Create(@SYNS_AttrUnknownWord, SYNS_XML_AttrUnknownWord);
486   FUnknownAttri.Style := [fsItalic];
487   AddAttribute(FUnknownAttri);
488 
489   FSpaceAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSpace, SYNS_XML_AttrSpace);
490   AddAttribute(FSpaceAttri);
491 
492   FOrigFileAttri := TSynHighlighterAttributes.Create(@SYNS_AttrOrigFile, SYNS_XML_AttrOrigFile);
493   FOrigFileAttri.Style := [fsBold];
494   FOrigFileAttri.Background := clRed;
495   AddAttribute(FOrigFileAttri);
496 
497   FNewFileAttri := TSynHighlighterAttributes.Create(@SYNS_AttrNewFile, SYNS_XML_AttrNewFile);
498   FNewFileAttri.Style := [fsBold];
499   FNewFileAttri.Background := clGreen;
500   AddAttribute(FNewFileAttri);
501 
502   FChunkMarkerAttri := TSynHighlighterAttributes.Create(@SYNS_AttrChunkMarker, SYNS_XML_AttrChunkMarker);
503   FChunkMarkerAttri.Style := [fsBold];
504   AddAttribute(FChunkMarkerAttri);
505 
506   FChunkNewAttri := TSynHighlighterAttributes.Create(@SYNS_AttrChunkNew, SYNS_XML_AttrChunkNew);
507   FChunkNewAttri.Style := [fsBold];
508   FChunkNewAttri.Foreground := clGreen;
509   AddAttribute(FChunkNewAttri);
510 
511   FChunkOldAttri := TSynHighlighterAttributes.Create(@SYNS_AttrChunkOrig, SYNS_XML_AttrChunkOrig);
512   FChunkOldAttri.Style := [fsBold];
513   FChunkOldAttri.Foreground := clRed;
514   AddAttribute(FChunkOldAttri);
515 
516   FChunkMixedAttri := TSynHighlighterAttributes.Create(@SYNS_AttrChunkMixed, SYNS_XML_AttrChunkMixed);
517   FChunkMixedAttri.Style := [fsBold];
518   FChunkMixedAttri.Foreground := clPurple;
519   AddAttribute(FChunkMixedAttri);
520 
521   FLineAddedAttri := TSynHighlighterAttributes.Create(@SYNS_AttrLineAdded, SYNS_XML_AttrLineAdded);
522   FLineAddedAttri.Foreground := clGreen;
523   AddAttribute(FLineAddedAttri);
524 
525   FLineRemovedAttri := TSynHighlighterAttributes.Create(@SYNS_AttrLineRemoved, SYNS_XML_AttrLineRemoved);
526   FLineRemovedAttri.Foreground := clRed;
527   AddAttribute(FLineRemovedAttri);
528 
529   FLineChangedAttri := TSynHighlighterAttributes.Create(@SYNS_AttrLineChanged, SYNS_XML_AttrLineChanged);
530   FLineChangedAttri.Foreground := clPurple;
531   AddAttribute(FLineChangedAttri);
532 
533   FLineContextAttri := TSynHighlighterAttributes.Create(@SYNS_AttrLineContext, SYNS_XML_AttrLineContext);
534   AddAttribute(FLineContextAttri);
535 
536   SetAttributesOnChange(@DefHighlightChange);
537   MakeMethodTables;
538   fDefaultFilter := '';
539   fRange := rsUnknown;
540 end;
541 
542 destructor TSynDiffSyn.Destroy;
543 begin
544   inherited Destroy;
545 end;
546 
TSynDiffSyn.GetTokennull547 function TSynDiffSyn.GetToken: String;
548 var
549   Len: LongInt;
550 begin
551   Result := '';
552   Len := Run - fTokenPos;
553   SetString(Result, (FLine + fTokenPos), Len);
554 end;
555 
556 procedure TSynDiffSyn.GetTokenEx(out TokenStart: PChar;
557   out TokenLength: integer);
558 begin
559   TokenLength:=Run-fTokenPos;
560   TokenStart:=FLine + fTokenPos;
561 end;
562 
GetTokenAttributenull563 function TSynDiffSyn.GetTokenAttribute: TSynHighlighterAttributes;
564 begin
565   case fTokenID of
566     tkNull:            Result := FUnknownAttri;
567     tkUnknown:         Result := FUnknownAttri;
568     tkSpace:           Result := FSpaceAttri;
569     tkFileOrigMark:    Result := FOrigFileAttri;
570     tkFileNewMark:     Result := FNewFileAttri;
571     tkFileOrig:        Result := FOrigFileAttri;
572     tkFileNew:         Result := FNewFileAttri;
573     tkChunkSeparator:  Result := FChunkMarkerAttri;
574     tkChunkMixedMark:  Result := FChunkMixedAttri;
575     tkChunkOrigMark:   Result := FChunkOldAttri;
576     tkChunkNewMark:    Result := FChunkNewAttri;
577     tkChunkMixed:      Result := FChunkMixedAttri;
578     tkChunkOrig:       Result := FChunkOldAttri;
579     tkChunkNew:        Result := FChunkNewAttri;
580     tkLineRemovedMark: Result := FLineRemovedAttri;
581     tkLineAddedMark:   Result := FLineAddedAttri;
582     tkLineChangedMark: Result := FLineChangedAttri;
583     tkLineContextMark: Result := FLineContextAttri;
584     tkLineRemoved:     Result := FLineRemovedAttri;
585     tkLineAdded:       Result := FLineAddedAttri;
586     tkLineChanged:     Result := FLineChangedAttri;
587     tkLineContext:     Result := FLineContextAttri;
588     else Result := nil;
589   end;
590 end;
591 
GetTokenKindnull592 function TSynDiffSyn.GetTokenKind: integer;
593 begin
594   Result := Ord(fTokenID);
595 end;
596 
TSynDiffSyn.GetTokenPosnull597 function TSynDiffSyn.GetTokenPos: Integer;
598 begin
599   Result := fTokenPos;
600 end;
601 
GetTokenIDnull602 function TSynDiffSyn.GetTokenID: TtkTokenKind;
603 begin
604   Result := fTokenId;
605 end;
606 
607 procedure TSynDiffSyn.Next;
608 var
609   OldRange: TRangeState;
610 begin
611   fTokenPos := Run;
612   if Run > 0 then begin
613     if fLine[Run] = #0 then NullProc
614                        else LineProc;
615   end else begin
616     OldRange := fRange;
617     fProcTable[fLine[Run]]();
618 
619     if ((fRange in [rsCtxFileOrig, rsCtxFileNew, rsUniFileOrig..rsUniFileNew]) and
620         not (OldRange in [rsCtxFileOrig, rsCtxFileNew, rsUniFileOrig..rsUniFileNew]))
621     then begin
622       while (TopDiffCodeFoldBlockType in [cfbtDiffChunkSect, cfbtDiffChunk, cfbtDiffFile]) do
623         EndDiffCodeFoldBlock;
624       StartDiffCodeFoldBlock(cfbtDiffFile);
625     end;
626 
627     if (fRange in [rsCtxChunkHeader, rsUniChunkHeader])
628     then begin
629       while (TopDiffCodeFoldBlockType in [cfbtDiffChunkSect, cfbtDiffChunk]) do
630         EndDiffCodeFoldBlock;
631       StartDiffCodeFoldBlock(cfbtDiffChunk);
632     end;
633 
634     if (fRange in [rsCtxChunkOrig, rsCtxChunkNew])
635     then begin
636       if (TopDiffCodeFoldBlockType = cfbtDiffChunkSect) then
637         EndDiffCodeFoldBlock;
638       StartDiffCodeFoldBlock(cfbtDiffChunkSect);
639     end;
640 
641 
642   end;
643 end;
644 
GetEolnull645 function TSynDiffSyn.GetEol: Boolean;
646 begin
647   Result := fTokenId = tkNull;
648 end;
649 
650 procedure TSynDiffSyn.SetLine(const NewValue: String;
651   LineNumber: Integer);
652 begin
653   inherited;
654   fLine := PChar(NewValue);
655   Run := 0;
656   fLineNumber := LineNumber;
657   Next;
658 end;
659 
TSynDiffSyn.GetRangenull660 function TSynDiffSyn.GetRange: Pointer;
661 begin
662   CodeFoldRange.RangeType:=Pointer(PtrUInt(Integer(fRange)));
663   Result := inherited;
664 end;
665 
666 procedure TSynDiffSyn.SetRange(Value: Pointer);
667 begin
668   inherited;
669   fRange := TRangeState(Integer(PtrUInt(CodeFoldRange.RangeType)));
670 end;
671 
672 procedure TSynDiffSyn.ResetRange;
673 begin
674   inherited;
675   fRange := rsUnknown;
676 end;
677 
GetDefaultAttributenull678 function TSynDiffSyn.GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
679 begin
680   Result := nil;
681 end;
682 
TSynDiffSyn.GetLanguageNamenull683 class function TSynDiffSyn.GetLanguageName: string;
684 begin
685   Result := SYNS_LangDiff;
686 end;
687 
688 procedure TSynDiffSyn.CreateRootCodeFoldBlock;
689 begin
690   inherited CreateRootCodeFoldBlock;
691   RootCodeFoldBlock.InitRootBlockType(Pointer(PtrInt(cfbtDiffNone)));
692 end;
693 
StartDiffCodeFoldBlocknull694 function TSynDiffSyn.StartDiffCodeFoldBlock(ABlockType: TDiffCodeFoldBlockType): TSynCustomCodeFoldBlock;
695 var
696   FoldBlock: Boolean;
697   p: PtrInt;
698 begin
699   FoldBlock :=  FFoldConfig[ord(ABlockType)].Enabled;
700   p := 0;
701   if not FoldBlock then
702     p := PtrInt(CountDiffCodeFoldBlockOffset);
703   Result := StartCodeFoldBlock(p + Pointer(PtrInt(ABlockType)), FoldBlock);
704 end;
705 
706 procedure TSynDiffSyn.EndDiffCodeFoldBlock;
707 var
708   DecreaseLevel: Boolean;
709 begin
710   DecreaseLevel := TopCodeFoldBlockType < CountDiffCodeFoldBlockOffset;
711   EndCodeFoldBlock(DecreaseLevel);
712 end;
713 
TopDiffCodeFoldBlockTypenull714 function TSynDiffSyn.TopDiffCodeFoldBlockType(DownIndex: Integer): TDiffCodeFoldBlockType;
715 var
716   p: Pointer;
717 begin
718   p := TopCodeFoldBlockType(DownIndex);
719   if p >= CountDiffCodeFoldBlockOffset then
720     p := p - PtrUInt(CountDiffCodeFoldBlockOffset);
721   Result := TDiffCodeFoldBlockType(PtrUInt(p));
722 end;
723 
GetFoldConfigInstancenull724 function TSynDiffSyn.GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig;
725 begin
726   Result := inherited GetFoldConfigInstance(Index);
727   Result.Enabled := True;
728 end;
729 
GetFoldConfigCountnull730 function TSynDiffSyn.GetFoldConfigCount: Integer;
731 begin
732   // excluded cfbtDiffnone;
733   Result := ord(high(TDiffCodeFoldBlockType)) - ord(low(TDiffCodeFoldBlockType));
734 end;
735 
TSynDiffSyn.GetFoldConfigInternalCountnull736 function TSynDiffSyn.GetFoldConfigInternalCount: Integer;
737 begin
738   // include cfbtDiffnone;
739   Result := ord(high(TDiffCodeFoldBlockType)) - ord(low(TDiffCodeFoldBlockType)) + 1;
740 end;
741 
742 initialization
743   RegisterPlaceableHighlighter(TSynDiffSyn);
744 
745 end.
746