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 The Original Code is: SynHighlighterXML.pas, released 2000-11-20.
12 The Initial Author of this file is Jeff Rafter.
13 All Rights Reserved.
14 
15 Contributors to the SynEdit and mwEdit projects are listed in the
16 Contributors.txt file.
17 
18 Alternatively, the contents of this file may be used under the terms of the
19 GNU General Public License Version 2 or later (the "GPL"), in which case
20 the provisions of the GPL are applicable instead of those above.
21 If you wish to allow use of your version of this file only under the terms
22 of the GPL and not to allow others to use your version of this file
23 under the MPL, indicate your decision by deleting the provisions above and
24 replace them with the notice and other provisions required by the GPL.
25 If you do not delete the provisions above, a recipient may use your version
26 of this file under either the MPL or the GPL.
27 
28 $Id$
29 
30 You may retrieve the latest version of this file at the SynEdit home page,
31 located at http://SynEdit.SourceForge.net
32 
33 History:
34 -------------------------------------------------------------------------------
35 2000-11-30 Removed mHashTable and MakeIdentTable per Michael Hieke
36 
37 Known Issues:
38 - Nothing is really constrained (properly) to valid name chars
39 - Entity Refs are not constrained to valid name chars
40 - Support for "Combining Chars and Extender Chars" in names are lacking
41 - The internal DTD is not parsed (and not handled correctly)
42 -------------------------------------------------------------------------------}
43 
44 {
45 @abstract(Provides an XML highlighter for SynEdit)
46 @author(Jeff Rafter-- Phil 4:13, based on SynHighlighterHTML by Hideo Koiso)
47 @created(2000-11-17)
48 @lastmod(2001-03-12)
49 The SynHighlighterXML unit provides SynEdit with an XML highlighter.
50 }
51 
52 unit SynHighlighterXML;
53 
54 interface
55 
56 {$I SynEdit.inc}
57 
58 uses
59   Classes, Graphics, SynEditTypes, SynEditHighlighter,
60   SynEditHighlighterFoldBase, SynEditHighlighterXMLBase, SynEditStrConst;
61 
62 type
63   TtkTokenKind = (tkAposAttrValue, tkAposEntityRef, tkAttribute, tkCDATA,
64     tkComment, tkElement, tkEntityRef, tkEqual, tkNull, tkProcessingInstruction,
65     tkQuoteAttrValue, tkQuoteEntityRef, tkSpace, tkSymbol, tkText,
66     //
67     tknsAposAttrValue, tknsAposEntityRef, tknsAttribute, tknsEqual,
68     tknsQuoteAttrValue, tknsQuoteEntityRef,
69     //These are unused at the moment
70     tkDocType
71     {tkDocTypeAposAttrValue, tkDocTypeAposEntityRef, tkDocTypeAttribute,
72      tkDocTypeElement, tkDocTypeEqual tkDocTypeQuoteAttrValue,
73      tkDocTypeQuoteEntityRef}
74   );
75 
76   TRangeState = (rsAposAttrValue, rsAPosEntityRef, rsAttribute, rsCDATA,
77     rsComment, rsElement, rsCloseElement, rsOpenElement, rsEntityRef, rsEqual, rsProcessingInstruction,
78     rsQuoteAttrValue, rsQuoteEntityRef, rsText,
79     //
80     rsnsAposAttrValue, rsnsAPosEntityRef, rsnsEqual, rsnsQuoteAttrValue,
81     rsnsQuoteEntityRef,
82     //These are unused at the moment
83     rsDocType, rsDocTypeSquareBraces                                           //ek 2001-11-11
84     {rsDocTypeAposAttrValue, rsDocTypeAposEntityRef, rsDocTypeAttribute,
85      rsDocTypeElement, rsDocTypeEqual, rsDocTypeQuoteAttrValue,
86      rsDocTypeQuoteEntityRef}
87   );
88 
89  TXmlCodeFoldBlockType = (
90     cfbtXmlNode,     // <foo>...</node>
91     cfbtXmlComment,  // <!-- -->
92     cfbtXmlCData,    // <![CDATA[ ]]>
93     cfbtXmlDocType,  // <!DOCTYPE
94     cfbtXmlProcess,   // <?
95     // internal types / not configurable
96     cfbtXmlNone
97   );
98 
99 type
100 
101   TProcTableProc = procedure of object;
102 
103   { TSynXMLSyn }
104 
105   TSynXMLSyn = class(TSynCustomXmlHighlighter)
106   private
107     fRange: TRangeState;
108     fLine: PChar;
109     Run: Longint;
110     fTokenPos: Integer;
111     fTokenID: TtkTokenKind;
112     fLineNumber: Integer;
113     fElementAttri: TSynHighlighterAttributes;
114     fSpaceAttri: TSynHighlighterAttributes;
115     fTextAttri: TSynHighlighterAttributes;
116     fEntityRefAttri: TSynHighlighterAttributes;
117     fProcessingInstructionAttri: TSynHighlighterAttributes;
118     fCDATAAttri: TSynHighlighterAttributes;
119     fCommentAttri: TSynHighlighterAttributes;
120     fDocTypeAttri: TSynHighlighterAttributes;
121     fAttributeAttri: TSynHighlighterAttributes;
122     fnsAttributeAttri: TSynHighlighterAttributes;
123     fAttributeValueAttri: TSynHighlighterAttributes;
124     fnsAttributeValueAttri: TSynHighlighterAttributes;
125     fSymbolAttri: TSynHighlighterAttributes;
126     fProcTable: array[#0..#255] of TProcTableProc;
127     FWantBracesParsed: Boolean;
128     procedure NullProc;
129     procedure CarriageReturnProc;
130     procedure LineFeedProc;
131     procedure SpaceProc;
132     procedure LessThanProc;
133     procedure GreaterThanProc;
134     procedure CommentProc;
135     procedure ProcessingInstructionProc;
136     procedure DocTypeProc;
137     procedure CDATAProc;
138     procedure TextProc;
139     procedure ElementProc;
140     procedure AttributeProc;
141     procedure QAttributeValueProc;
142     procedure AAttributeValueProc;
143     procedure EqualProc;
144     procedure IdentProc;
145     procedure MakeMethodTables;
NextTokenIsnull146     function NextTokenIs(T: String): Boolean;
147     procedure EntityRefProc;
148     procedure QEntityRefProc;
149     procedure AEntityRefProc;
150   protected
GetIdentCharsnull151     function GetIdentChars: TSynIdentChars; override;
GetSampleSourcenull152     function GetSampleSource : String; override;
153   protected
154     // folding
155     procedure CreateRootCodeFoldBlock; override;
156 
StartXmlCodeFoldBlocknull157     function StartXmlCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType): TSynCustomCodeFoldBlock;
StartXmlNodeCodeFoldBlocknull158     function StartXmlNodeCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType;
159                                    OpenPos: Integer; AName: String): TSynCustomCodeFoldBlock;
160     procedure EndXmlNodeCodeFoldBlock(ClosePos: Integer = -1; AName: String = '');
TopXmlCodeFoldBlockTypenull161     function TopXmlCodeFoldBlockType(DownIndex: Integer = 0): TXmlCodeFoldBlockType;
162 
GetFoldConfigInstancenull163     function GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig; override;
GetFoldConfigCountnull164     function GetFoldConfigCount: Integer; override;
GetFoldConfigInternalCountnull165     function GetFoldConfigInternalCount: Integer; override;
166   public
GetLanguageNamenull167     class function GetLanguageName: string; override;
168   public
169     constructor Create(AOwner: TComponent); override;
GetDefaultAttributenull170     function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
171       override;
GetEolnull172     function GetEol: Boolean; override;
GetRangenull173     function GetRange: Pointer; override;
GetTokenIDnull174     function GetTokenID: TtkTokenKind;
175     procedure SetLine(const NewValue: string; LineNumber:Integer); override;
GetTokennull176     function GetToken: string; override;
177     procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
GetTokenAttributenull178     function GetTokenAttribute: TSynHighlighterAttributes; override;
GetTokenKindnull179     function GetTokenKind: integer; override;
GetTokenPosnull180     function GetTokenPos: Integer; override;
181     procedure Next; override;
182     procedure SetRange(Value: Pointer); override;
183     procedure ReSetRange; override;
184     property IdentChars;
185   published
186     property ElementAttri: TSynHighlighterAttributes read fElementAttri
187       write fElementAttri;
188     property AttributeAttri: TSynHighlighterAttributes read fAttributeAttri
189       write fAttributeAttri;
190     property NamespaceAttributeAttri: TSynHighlighterAttributes
191       read fnsAttributeAttri write fnsAttributeAttri;
192     property AttributeValueAttri: TSynHighlighterAttributes
193       read fAttributeValueAttri write fAttributeValueAttri;
194     property NamespaceAttributeValueAttri: TSynHighlighterAttributes
195       read fnsAttributeValueAttri write fnsAttributeValueAttri;
196     property TextAttri: TSynHighlighterAttributes read fTextAttri
197       write fTextAttri;
198     property CDATAAttri: TSynHighlighterAttributes read fCDATAAttri
199       write fCDATAAttri;
200     property EntityRefAttri: TSynHighlighterAttributes read fEntityRefAttri
201       write fEntityRefAttri;
202     property ProcessingInstructionAttri: TSynHighlighterAttributes
203       read fProcessingInstructionAttri write fProcessingInstructionAttri;
204     property CommentAttri: TSynHighlighterAttributes read fCommentAttri
205       write fCommentAttri;
206     property DocTypeAttri: TSynHighlighterAttributes read fDocTypeAttri
207       write fDocTypeAttri;
208     property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri
209       write fSpaceAttri;
210     property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri
211       write fSymbolAttri;
212     property WantBracesParsed : Boolean read FWantBracesParsed
213       write FWantBracesParsed default True;
214   end;
215 
216 implementation
217 
218 const
219   NameChars : set of char = ['0'..'9', 'a'..'z', 'A'..'Z', '_', '.', ':', '-'];
220 
221 constructor TSynXMLSyn.Create(AOwner: TComponent);
222 begin
223   inherited Create(AOwner);
224 
225   fElementAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrElementName, SYNS_XML_AttrElementName);
226   fTextAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrText, SYNS_XML_AttrText);
227   fSpaceAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrWhitespace, SYNS_XML_AttrWhitespace);
228   fEntityRefAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrEntityReference, SYNS_XML_AttrEntityReference);
229   fProcessingInstructionAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrProcessingInstr, SYNS_XML_AttrProcessingInstr);
230   fCDATAAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrCDATASection, SYNS_XML_AttrCDATASection);
231   fCommentAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrComment, SYNS_XML_AttrComment);
232   fDocTypeAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrDOCTYPESection, SYNS_XML_AttrDOCTYPESection);
233   fAttributeAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrAttributeName, SYNS_XML_AttrAttributeName);
234   fnsAttributeAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrNamespaceAttrName, SYNS_XML_AttrNamespaceAttrName);
235   fAttributeValueAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrAttributeValue, SYNS_XML_AttrAttributeValue);
236   fnsAttributeValueAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrNamespaceAttrValue, SYNS_XML_AttrNamespaceAttrValue);
237   fSymbolAttri:= TSynHighlighterAttributes.Create(@SYNS_AttrSymbol, SYNS_XML_AttrSymbol);
238 
239   fElementAttri.Foreground:= clMaroon;
240   fElementAttri.Style:= [fsBold];
241 
242   fDocTypeAttri.Foreground:= clblue;
243   fDocTypeAttri.Style:= [fsItalic];
244 
245   fCDATAAttri.Foreground:= clOlive;
246   fCDATAAttri.Style:= [fsItalic];
247 
248   fEntityRefAttri.Foreground:= clblue;
249   fEntityRefAttri.Style:= [fsbold];
250 
251   fProcessingInstructionAttri.Foreground:= clblue;
252   fProcessingInstructionAttri.Style:= [];
253 
254   fTextAttri.Foreground:= clBlack;
255   fTextAttri.Style:= [fsBold];
256 
257   fAttributeAttri.Foreground:= clMaroon;
258   fAttributeAttri.Style:= [];
259 
260   fnsAttributeAttri.Foreground:= clRed;
261   fnsAttributeAttri.Style:= [];
262 
263   fAttributeValueAttri.Foreground:= clNavy;
264   fAttributeValueAttri.Style:= [fsBold];
265 
266   fnsAttributeValueAttri.Foreground:= clRed;
267   fnsAttributeValueAttri.Style:= [fsBold];
268 
269   fCommentAttri.Background:= clSilver;
270   fCommentAttri.Foreground:= clGray;
271   fCommentAttri.Style:= [fsbold, fsItalic];
272 
273   fSymbolAttri.Foreground:= clblue;
274   fSymbolAttri.Style:= [];
275 
276   AddAttribute(fSymbolAttri);
277   AddAttribute(fProcessingInstructionAttri);
278   AddAttribute(fDocTypeAttri);
279   AddAttribute(fCommentAttri);
280   AddAttribute(fElementAttri);
281   AddAttribute(fAttributeAttri);
282   AddAttribute(fnsAttributeAttri);
283   AddAttribute(fAttributeValueAttri);
284   AddAttribute(fnsAttributeValueAttri);
285   AddAttribute(fEntityRefAttri);
286   AddAttribute(fCDATAAttri);
287   AddAttribute(fSpaceAttri);
288   AddAttribute(fTextAttri);
289 
290   SetAttributesOnChange(@DefHighlightChange);
291 
292   MakeMethodTables;
293   fRange := rsText;
294   fDefaultFilter := SYNS_FilterXML;
295 end;
296 
297 procedure TSynXMLSyn.MakeMethodTables;
298 var
299   i: Char;
300 begin
301   for i:= #0 To #255 do begin
302     case i of
303     #0:
304       begin
305         fProcTable[i] := @NullProc;
306       end;
307     #10:
308       begin
309         fProcTable[i] := @LineFeedProc;
310       end;
311     #13:
312       begin
313         fProcTable[i] := @CarriageReturnProc;
314       end;
315     #1..#9, #11, #12, #14..#32:
316       begin
317         fProcTable[i] := @SpaceProc;
318       end;
319     '<':
320       begin
321         fProcTable[i] := @LessThanProc;
322       end;
323     '>':
324       begin
325         fProcTable[i] := @GreaterThanProc;
326       end;
327     else
328       fProcTable[i] := @IdentProc;
329     end;
330   end;
331 end;
332 
333 procedure TSynXMLSyn.SetLine(const NewValue: string;
334   LineNumber:Integer);
335 begin
336   inherited;
337   fLine := PChar(NewValue);
338   Run := 0;
339   fLineNumber := LineNumber;
340   Next;
341 end;
342 
343 procedure TSynXMLSyn.NullProc;
344 begin
345   fTokenID := tkNull;
346 end;
347 
348 procedure TSynXMLSyn.CarriageReturnProc;
349 begin
350   fTokenID := tkSpace;
351   Inc(Run);
352   if fLine[Run] = #10 then Inc(Run);
353 end;
354 
355 procedure TSynXMLSyn.LineFeedProc;
356 begin
357   fTokenID := tkSpace;
358   Inc(Run);
359 end;
360 
361 procedure TSynXMLSyn.SpaceProc;
362 begin
363   Inc(Run);
364   fTokenID := tkSpace;
365   while fLine[Run] <= #32 do begin
366     if fLine[Run] in [#0, #9, #10, #13] then break;
367     Inc(Run);
368   end;
369 end;
370 
371 procedure TSynXMLSyn.LessThanProc;
372 begin
373   Inc(Run);
374   if (fLine[Run] = '/') then begin
375     Inc(Run);
376     fTokenID := tkSymbol;
377     fRange := rsCloseElement;
378     exit;
379   end;
380 
381   if (fLine[Run] = '!') then
382   begin
383     if NextTokenIs('--') then begin
384       fTokenID := tkSymbol;
385       fRange := rsComment;
386       StartXmlCodeFoldBlock(cfbtXmlComment);
387       Inc(Run, 3);
388     end else if NextTokenIs('DOCTYPE') then begin
389       fTokenID := tkDocType;
390       fRange := rsDocType;
391       StartXmlCodeFoldBlock(cfbtXmlDocType);
392       Inc(Run, 7);
393     end else if NextTokenIs('[CDATA[') then begin
394       fTokenID := tkCDATA;
395       fRange := rsCDATA;
396       StartXmlCodeFoldBlock(cfbtXmlCData);
397       Inc(Run, 7);
398     end else begin
399       fTokenID := tkSymbol;
400       fRange := rsElement;
401       Inc(Run);
402     end;
403   end else if fLine[Run]= '?' then begin
404     fTokenID := tkProcessingInstruction;
405     fRange := rsProcessingInstruction;
406     StartXmlCodeFoldBlock(cfbtXmlProcess);
407     Inc(Run);
408   end else begin
409     fTokenID := tkSymbol;
410     fRange := rsOpenElement;
411   end;
412 end;
413 
414 procedure TSynXMLSyn.GreaterThanProc;
415 begin
416   if (Run > 0) and (fLine[Run - 1] = '/') then
417     if TopXmlCodeFoldBlockType = cfbtXmlNode then
418       EndXmlNodeCodeFoldBlock;
419 
420   fTokenId := tkSymbol;
421   fRange:= rsText;
422   Inc(Run);
423 end;
424 
425 procedure TSynXMLSyn.CommentProc;
426 begin
427   if (fLine[Run] = '-') and (fLine[Run + 1] = '-') and
428      (fLine[Run + 2] = '>')
429   then begin
430     fTokenID := tkSymbol;
431     fRange:= rsText;
432     Inc(Run, 3);
433     if TopXmlCodeFoldBlockType = cfbtXmlComment then
434       EndXmlCodeFoldBlock;
435     Exit;
436   end;
437 
438   fTokenID := tkComment;
439 
440   if (fLine[Run] In [#0, #10, #13]) then begin
441     fProcTable[fLine[Run]]();
442     Exit;
443   end;
444 
445   while not (fLine[Run] in [#0, #10, #13]) do begin
446     if (fLine[Run] = '-') and (fLine[Run + 1] = '-') and (fLine[Run + 2] = '>')
447     then begin
448       fRange := rsComment;
449       break;
450     end;
451     Inc(Run);
452   end;
453 end;
454 
455 procedure TSynXMLSyn.ProcessingInstructionProc;
456 begin
457   fTokenID := tkProcessingInstruction;
458   if (fLine[Run] In [#0, #10, #13]) then begin
459     fProcTable[fLine[Run]]();
460     Exit;
461   end;
462 
463   while not (fLine[Run] in [#0, #10, #13]) do begin
464     if (fLine[Run] = '>') and (fLine[Run - 1] = '?')
465     then begin
466       fRange := rsText;
467       Inc(Run);
468       if TopXmlCodeFoldBlockType = cfbtXmlProcess then
469         EndXmlCodeFoldBlock;
470       break;
471     end;
472     Inc(Run);
473   end;
474 end;
475 
476 procedure TSynXMLSyn.DocTypeProc;                                              //ek 2001-11-11
477 begin
478   fTokenID := tkDocType;
479 
480   if (fLine[Run] In [#0, #10, #13]) then begin
481     fProcTable[fLine[Run]]();
482     Exit;
483   end;
484 
485   case fRange of
486     rsDocType:
487       begin
488         while not (fLine[Run] in [#0, #10, #13]) do
489         begin
490           case fLine[Run] of
491             '[': begin
492                    while True do
493                    begin
494                      inc(Run);
495                      case fLine[Run] of
496                        ']':
497                          begin
498                            Inc(Run);
499                            Exit;
500                          end;
501                        #0, #10, #13:
502                          begin
503                            fRange:=rsDocTypeSquareBraces;
504                            Exit;
505                          end;
506                      end;
507                    end;
508                  end;
509             '>': begin
510                    fRange := rsAttribute;
511                    if TopXmlCodeFoldBlockType = cfbtXmlDocType then
512                      EndXmlCodeFoldBlock;
513                    Inc(Run);
514                    Break;
515                  end;
516           end;
517           inc(Run);
518         end;
519     end;
520     rsDocTypeSquareBraces:
521       begin
522         while not (fLine[Run] in [#0, #10, #13]) do
523         begin
524           if (fLine[Run]=']') then
525           begin
526             fRange := rsDocType;
527             Inc(Run);
528             Exit;
529           end;
530           inc(Run);
531         end;
532       end;
533   end;
534 end;
535 
536 procedure TSynXMLSyn.CDATAProc;
537 begin
538   fTokenID := tkCDATA;
539   if (fLine[Run] In [#0, #10, #13]) then
540   begin
541     fProcTable[fLine[Run]]();
542     Exit;
543   end;
544 
545   while not (fLine[Run] in [#0, #10, #13]) do
546   begin
547     if (Run >= 2) and (fLine[Run] = '>') and (fLine[Run - 1] = ']') and
548        (fLine[Run - 2] = ']')
549     then begin
550       fRange := rsText;
551       Inc(Run);
552       if TopXmlCodeFoldBlockType = cfbtXmlCData then
553         EndXmlCodeFoldBlock;
554       break;
555     end;
556     Inc(Run);
557   end;
558 end;
559 
560 procedure TSynXMLSyn.ElementProc;
561 var
562   NameStart: LongInt;
563 begin
564   if fLine[Run] = '/' then
565     Inc(Run);
566   NameStart := Run;
567   while (fLine[Run] in NameChars) do Inc(Run);
568 
569   if fRange = rsOpenElement then
570     StartXmlNodeCodeFoldBlock(cfbtXmlNode, NameStart, Copy(fLine, NameStart + 1, Run - NameStart));
571 
572   if fRange = rsCloseElement then
573     EndXmlNodeCodeFoldBlock(NameStart, Copy(fLine, NameStart + 1, Run - NameStart));   // TODO: defer until ">" reached
574 
575   fRange := rsAttribute;
576   fTokenID := tkElement;
577 end;
578 
579 procedure TSynXMLSyn.AttributeProc;
580 begin
581   //Check if we are starting on a closing quote
582   if (fLine[Run] in [#34, #39]) then
583   begin
584     fTokenID := tkSymbol;
585     fRange := rsAttribute;
586     Inc(Run);
587     Exit;
588   end;
589   //Read the name
590   while (fLine[Run] in NameChars) do Inc(Run);
591   //Check if this is an xmlns: attribute
592   if (Pos('xmlns', GetToken) > 0) then begin
593     fTokenID := tknsAttribute;
594     fRange := rsnsEqual;
595   end else begin
596     fTokenID := tkAttribute;
597     fRange := rsEqual;
598   end;
599 end;
600 
601 procedure TSynXMLSyn.EqualProc;
602 begin
603   if fRange = rsnsEqual then
604     fTokenID := tknsEqual
605   else
606     fTokenID := tkEqual;
607 
608   while not (fLine[Run] in [#0, #10, #13]) do
609   begin
610     if (fLine[Run] = '/') then
611     begin
612       fTokenID := tkSymbol;
613       fRange := rsElement;
614       Inc(Run);
615       Exit;
616     end else if (fLine[Run] = #34) then
617     begin
618       if fRange = rsnsEqual then
619         fRange := rsnsQuoteAttrValue
620       else
621         fRange := rsQuoteAttrValue;
622       Inc(Run);
623       Exit;
624     end else if (fLine[Run] = #39) then
625     begin
626       if fRange = rsnsEqual then
627         fRange := rsnsAPosAttrValue
628       else
629         fRange := rsAPosAttrValue;
630       Inc(Run);
631       Exit;
632     end;
633     Inc(Run);
634   end;
635 end;
636 
637 procedure TSynXMLSyn.QAttributeValueProc;
638 begin
639   if fRange = rsnsQuoteAttrValue then
640     fTokenID := tknsQuoteAttrValue
641   else
642     fTokenID := tkQuoteAttrValue;
643 
644   while not (fLine[Run] in [#0, #10, #13, '&', #34]) do Inc(Run);
645 
646   if fLine[Run] = '&' then
647   begin
648     if fRange = rsnsQuoteAttrValue then
649       fRange := rsnsQuoteEntityRef
650     else
651       fRange := rsQuoteEntityRef;
652     Exit;
653   end else if fLine[Run] <> #34 then
654   begin
655     Exit;
656   end;
657 
658   fRange := rsAttribute;
659 end;
660 
661 procedure TSynXMLSyn.AAttributeValueProc;
662 begin
663   if fRange = rsnsAPosAttrValue then
664     fTokenID := tknsAPosAttrValue
665   else
666     fTokenID := tkAPosAttrValue;
667 
668   while not (fLine[Run] in [#0, #10, #13, '&', #39]) do Inc(Run);
669 
670   if fLine[Run] = '&' then
671   begin
672     if fRange = rsnsAPosAttrValue then
673       fRange := rsnsAPosEntityRef
674     else
675       fRange := rsAPosEntityRef;
676     Exit;
677   end else if fLine[Run] <> #39 then
678   begin
679     Exit;
680   end;
681 
682   fRange := rsAttribute;
683 end;
684 
685 procedure TSynXMLSyn.TextProc;
686 const StopSet = [#0..#31, '<', '&'];
687 begin
688   if fLine[Run] in (StopSet - ['&']) then begin
689     fProcTable[fLine[Run]]();
690     exit;
691   end;
692 
693   fTokenID := tkText;
694   while not (fLine[Run] in StopSet) do Inc(Run);
695 
696   if (fLine[Run] = '&') then begin
697     fRange := rsEntityRef;
698     Exit;
699   end;
700 end;
701 
702 procedure TSynXMLSyn.EntityRefProc;
703 begin
704   fTokenID := tkEntityRef;
705   fRange := rsEntityRef;
706   while not (fLine[Run] in [#0..#32, ';']) do Inc(Run);
707   if (fLine[Run] = ';') then Inc(Run);
708   fRange := rsText;
709 end;
710 
711 procedure TSynXMLSyn.QEntityRefProc;
712 begin
713   if fRange = rsnsQuoteEntityRef then
714     fTokenID := tknsQuoteEntityRef
715   else
716     fTokenID := tkQuoteEntityRef;
717 
718   while not (fLine[Run] in [#0..#32, ';']) do Inc(Run);
719   if (fLine[Run] = ';') then Inc(Run);
720 
721   if fRange = rsnsQuoteEntityRef then
722     fRange := rsnsQuoteAttrValue
723   else
724     fRange := rsQuoteAttrValue;
725 end;
726 
727 procedure TSynXMLSyn.AEntityRefProc;
728 begin
729   if fRange = rsnsAPosEntityRef then
730     fTokenID := tknsAPosEntityRef
731   else
732     fTokenID := tkAPosEntityRef;
733 
734   while not (fLine[Run] in [#0..#32, ';']) do Inc(Run);
735   if (fLine[Run] = ';') then Inc(Run);
736 
737   if fRange = rsnsAPosEntityRef then
738     fRange := rsnsAPosAttrValue
739   else
740     fRange := rsAPosAttrValue;
741 end;
742 
GetFoldConfigInstancenull743 function TSynXMLSyn.GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig;
744 begin
745   Result := inherited GetFoldConfigInstance(Index);
746   Result.Enabled := True;
747   if TXmlCodeFoldBlockType(Index) in [cfbtXmlNode] then begin
748     Result.SupportedModes := Result.SupportedModes + [fmMarkup];
749     Result.Modes := Result.Modes + [fmMarkup];
750   end;
751 end;
752 
753 procedure TSynXMLSyn.IdentProc;
754 begin
755   case fRange of
756   rsElement, rsOpenElement, rsCloseElement:
757     begin
758       ElementProc();
759     end;
760   rsAttribute:
761     begin
762       AttributeProc();
763     end;
764   rsEqual, rsnsEqual:
765     begin
766       EqualProc();
767     end;
768   rsQuoteAttrValue, rsnsQuoteAttrValue:
769     begin
770       QAttributeValueProc();
771     end;
772   rsAposAttrValue, rsnsAPosAttrValue:
773     begin
774       AAttributeValueProc();
775     end;
776   rsQuoteEntityRef, rsnsQuoteEntityRef:
777     begin
778       QEntityRefProc();
779     end;
780   rsAposEntityRef, rsnsAPosEntityRef:
781     begin
782       AEntityRefProc();
783     end;
784   rsEntityRef:
785     begin
786       EntityRefProc();
787     end;
788   else ;
789   end;
790 end;
791 
792 procedure TSynXMLSyn.Next;
793 begin
794   fTokenPos := Run;
795   case fRange of
796   rsText:
797     begin
798       TextProc();
799     end;
800   rsComment:
801     begin
802       CommentProc();
803     end;
804   rsProcessingInstruction:
805     begin
806       ProcessingInstructionProc();
807     end;
808   rsDocType, rsDocTypeSquareBraces:                                            //ek 2001-11-11
809     begin
810       DocTypeProc();
811     end;
812   rsCDATA:
813     begin
814       CDATAProc();
815     end;
816   else
817     fProcTable[fLine[Run]]();
818   end;
819 end;
820 
TSynXMLSyn.NextTokenIsnull821 function TSynXMLSyn.NextTokenIs(T : String) : Boolean;
822 var I, Len : Integer;
823 begin
824   Result:= True;
825   Len:= Length(T);
826   for I:= 1 to Len do
827     if (fLine[Run + I] <> T[I]) then
828     begin
829       Result:= False;
830       Break;
831     end;
832 end;
833 
GetDefaultAttributenull834 function TSynXMLSyn.GetDefaultAttribute(
835   Index: integer): TSynHighlighterAttributes;
836 begin
837   case Index of
838     SYN_ATTR_COMMENT: Result := fCommentAttri;
839     SYN_ATTR_IDENTIFIER: Result := fAttributeAttri;
840     SYN_ATTR_KEYWORD: Result := fElementAttri;
841     SYN_ATTR_WHITESPACE: Result := fSpaceAttri;
842     SYN_ATTR_SYMBOL: Result := fSymbolAttri;
843   else
844     Result := nil;
845   end;
846 end;
847 
GetEolnull848 function TSynXMLSyn.GetEol: Boolean;
849 begin
850   Result := fTokenId = tkNull;
851 end;
852 
TSynXMLSyn.GetTokennull853 function TSynXMLSyn.GetToken: string;
854 var
855   len: Longint;
856 begin
857   Result := '';
858   Len := (Run - fTokenPos);
859   SetString(Result, (FLine + fTokenPos), len);
860 end;
861 
862 procedure TSynXMLSyn.GetTokenEx(out TokenStart: PChar;
863   out TokenLength: integer);
864 begin
865   TokenLength:=Run-fTokenPos;
866   TokenStart:=FLine + fTokenPos;
867 end;
868 
GetTokenIDnull869 function TSynXMLSyn.GetTokenID: TtkTokenKind;
870 begin
871   Result := fTokenId;
872 end;
873 
TSynXMLSyn.GetTokenAttributenull874 function TSynXMLSyn.GetTokenAttribute: TSynHighlighterAttributes;
875 begin
876   case fTokenID of
877     tkElement: Result:= fElementAttri;
878     tkAttribute: Result:= fAttributeAttri;
879     tknsAttribute: Result:= fnsAttributeAttri;
880     tkEqual: Result:= fSymbolAttri;
881     tknsEqual: Result:= fSymbolAttri;
882     tkQuoteAttrValue: Result:= fAttributeValueAttri;
883     tkAPosAttrValue: Result:= fAttributeValueAttri;
884     tknsQuoteAttrValue: Result:= fnsAttributeValueAttri;
885     tknsAPosAttrValue: Result:= fnsAttributeValueAttri;
886     tkText: Result:= fTextAttri;
887     tkCDATA: Result:= fCDATAAttri;
888     tkEntityRef: Result:= fEntityRefAttri;
889     tkQuoteEntityRef: Result:= fEntityRefAttri;
890     tkAposEntityRef: Result:= fEntityRefAttri;
891     tknsQuoteEntityRef: Result:= fEntityRefAttri;
892     tknsAposEntityRef: Result:= fEntityRefAttri;
893     tkProcessingInstruction: Result:= fProcessingInstructionAttri;
894     tkComment: Result:= fCommentAttri;
895     tkDocType: Result:= fDocTypeAttri;
896     tkSymbol: Result:= fSymbolAttri;
897     tkSpace: Result:= fSpaceAttri;
898   else
899     Result := nil;
900   end;
901 end;
902 
TSynXMLSyn.GetTokenKindnull903 function TSynXMLSyn.GetTokenKind: integer;
904 begin
905   Result := Ord(fTokenId);
906 end;
907 
GetTokenPosnull908 function TSynXMLSyn.GetTokenPos: Integer;
909 begin
910   Result := fTokenPos;
911 end;
912 
GetRangenull913 function TSynXMLSyn.GetRange: Pointer;
914 begin
915   CodeFoldRange.RangeType:=Pointer(PtrUInt(Integer(fRange)));
916   Result := inherited;
917 end;
918 
919 procedure TSynXMLSyn.SetRange(Value: Pointer);
920 begin
921   inherited;
922   fRange := TRangeState(Integer(PtrUInt(CodeFoldRange.RangeType)));
923 end;
924 
925 procedure TSynXMLSyn.ReSetRange;
926 begin
927   inherited;
928   fRange:= rsText;
929 end;
930 
GetIdentCharsnull931 function TSynXMLSyn.GetIdentChars: TSynIdentChars;
932 begin
933   Result := ['0'..'9', 'a'..'z', 'A'..'Z', '_', '.', '-'] + TSynSpecialChars;
934 end;
935 
TSynXMLSyn.GetLanguageNamenull936 class function TSynXMLSyn.GetLanguageName: string;
937 begin
938   Result := SYNS_LangXML;
939 end;
940 
GetSampleSourcenull941 function TSynXMLSyn.GetSampleSource: String;
942 begin
943   Result:= '<?xml version="1.0"?>'#13#10+
944            '<!DOCTYPE root ['#13#10+
945            '  ]>'#13#10+
946            '<!-- Comment -->'#13#10+
947            '<root version="&test;">'#13#10+
948            '  <![CDATA[ **CDATA section** ]]>'#13#10+
949            '</root>';
950 end;
951 
952 procedure TSynXMLSyn.CreateRootCodeFoldBlock;
953 begin
954   inherited CreateRootCodeFoldBlock;
955   RootCodeFoldBlock.InitRootBlockType(Pointer(PtrInt(cfbtXmlNone)));
956 end;
957 
StartXmlCodeFoldBlocknull958 function TSynXMLSyn.StartXmlCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType): TSynCustomCodeFoldBlock;
959 begin
960   Result := inherited StartXmlCodeFoldBlock(ord(ABlockType));
961 end;
962 
StartXmlNodeCodeFoldBlocknull963 function TSynXMLSyn.StartXmlNodeCodeFoldBlock(ABlockType: TXmlCodeFoldBlockType;
964   OpenPos: Integer; AName: String): TSynCustomCodeFoldBlock;
965 begin
966   if not FFoldConfig[ord(cfbtXmlNode)].Enabled then exit(nil);
967   Result := inherited StartXmlNodeCodeFoldBlock(ord(ABlockType), OpenPos, AName);
968 end;
969 
970 procedure TSynXMLSyn.EndXmlNodeCodeFoldBlock(ClosePos: Integer; AName: String);
971 begin
972   if not FFoldConfig[ord(cfbtXmlNode)].Enabled then exit;
973   inherited EndXmlNodeCodeFoldBlock(ClosePos, AName);
974 end;
975 
TSynXMLSyn.TopXmlCodeFoldBlockTypenull976 function TSynXMLSyn.TopXmlCodeFoldBlockType(DownIndex: Integer): TXmlCodeFoldBlockType;
977 begin
978   Result := TXmlCodeFoldBlockType(PtrUInt(TopCodeFoldBlockType(DownIndex)));
979 end;
980 
TSynXMLSyn.GetFoldConfigCountnull981 function TSynXMLSyn.GetFoldConfigCount: Integer;
982 begin
983   // excluded cfbtXmlNone
984   Result := ord(high(TXmlCodeFoldBlockType)) - ord(low(TXmlCodeFoldBlockType));
985 end;
986 
TSynXMLSyn.GetFoldConfigInternalCountnull987 function TSynXMLSyn.GetFoldConfigInternalCount: Integer;
988 begin
989   // excluded cfbtXmlNone;
990   Result := ord(high(TXmlCodeFoldBlockType)) - ord(low(TXmlCodeFoldBlockType)) + 1;
991 end;
992 
993 initialization
994   RegisterPlaceableHighlighter(TSynXMLSyn);
995 
996 end.
997 
998