1 // Scintilla source code edit control
5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
19 #include "Scintilla.h"
22 #define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START)
23 #define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START)
24 #define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START)
26 enum { eScriptNone
= 0, eScriptJS
, eScriptVBS
, eScriptPython
, eScriptPHP
, eScriptXML
};
27 enum { eHtml
= 0, eNonHtmlScript
, eNonHtmlPreProc
, eNonHtmlScriptPreProc
};
29 static int segIsScriptingIndicator(Accessor
&styler
, unsigned int start
, unsigned int end
, int prevValue
) {
32 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
33 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
36 //Platform::DebugPrintf("Scripting indicator [%s]\n", s);
37 if (strstr(s
, "src")) // External script
41 if (strstr(s
, "pyth"))
43 if (strstr(s
, "javas"))
45 if (strstr(s
, "jscr"))
55 static int PrintScriptingIndicatorOffset(Accessor
&styler
, unsigned int start
, unsigned int end
) {
59 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
60 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
63 if (0 == strncmp(s
, "php", 3)) {
70 static int ScriptOfState(int state
) {
73 if ((state
>= SCE_HP_START
) && (state
<= SCE_HP_IDENTIFIER
)) {
74 scriptLanguage
= eScriptPython
;
75 } else if ((state
>= SCE_HB_START
) && (state
<= SCE_HB_STRINGEOL
)) {
76 scriptLanguage
= eScriptVBS
;
77 } else if ((state
>= SCE_HJ_START
) && (state
<= SCE_HJ_REGEX
)) {
78 scriptLanguage
= eScriptJS
;
79 } else if ((state
>= SCE_HPHP_DEFAULT
) && (state
<= SCE_HPHP_COMMENTLINE
)) {
80 scriptLanguage
= eScriptPHP
;
82 // scriptLanguage = defaultScript;
83 scriptLanguage
= eScriptNone
;
86 return scriptLanguage
;
89 static int statePrintForState(int state
, int inScriptType
) {
92 if ((state
>= SCE_HP_START
) && (state
<= SCE_HP_IDENTIFIER
)) {
93 StateToPrint
= state
+ ((inScriptType
== eNonHtmlScript
) ? 0 : SCE_HA_PYTHON
);
94 } else if ((state
>= SCE_HB_START
) && (state
<= SCE_HB_STRINGEOL
)) {
95 StateToPrint
= state
+ ((inScriptType
== eNonHtmlScript
) ? 0 : SCE_HA_VBS
);
96 } else if ((state
>= SCE_HJ_START
) && (state
<= SCE_HJ_REGEX
)) {
97 StateToPrint
= state
+ ((inScriptType
== eNonHtmlScript
) ? 0 : SCE_HA_JS
);
105 static int stateForPrintState(int StateToPrint
) {
108 if ((StateToPrint
>= SCE_HPA_START
) && (StateToPrint
<= SCE_HPA_IDENTIFIER
)) {
109 state
= StateToPrint
- SCE_HA_PYTHON
;
110 } else if ((StateToPrint
>= SCE_HBA_START
) && (StateToPrint
<= SCE_HBA_STRINGEOL
)) {
111 state
= StateToPrint
- SCE_HA_VBS
;
112 } else if ((StateToPrint
>= SCE_HJA_START
) && (StateToPrint
<= SCE_HJA_REGEX
)) {
113 state
= StateToPrint
- SCE_HA_JS
;
115 state
= StateToPrint
;
121 static inline bool IsNumber(unsigned int start
, Accessor
&styler
) {
122 return isdigit(styler
[start
]) || (styler
[start
] == '.') ||
123 (styler
[start
] == '-') || (styler
[start
] == '#');
126 static inline bool isStringState(int state
) {
130 case SCE_HJ_DOUBLESTRING
:
131 case SCE_HJ_SINGLESTRING
:
132 case SCE_HJA_DOUBLESTRING
:
133 case SCE_HJA_SINGLESTRING
:
138 case SCE_HPHP_HSTRING
:
139 case SCE_HPHP_SIMPLESTRING
:
149 // not really well done, since it's only comments that should lex the %> and <%
150 static inline bool isCommentASPState(int state
) {
155 case SCE_HJ_COMMENTLINE
:
156 case SCE_HJ_COMMENTDOC
:
157 case SCE_HB_COMMENTLINE
:
158 case SCE_HP_COMMENTLINE
:
159 case SCE_HPHP_COMMENT
:
160 case SCE_HPHP_COMMENTLINE
:
170 static void classifyAttribHTML(unsigned int start
, unsigned int end
, WordList
&keywords
, Accessor
&styler
) {
171 bool wordIsNumber
= IsNumber(start
, styler
);
172 char chAttr
= SCE_H_ATTRIBUTEUNKNOWN
;
174 chAttr
= SCE_H_NUMBER
;
178 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
179 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
182 if (keywords
.InList(s
))
183 chAttr
= SCE_H_ATTRIBUTE
;
185 if ((chAttr
== SCE_H_ATTRIBUTEUNKNOWN
) && !keywords
)
186 // No keywords -> all are known
187 chAttr
= SCE_H_ATTRIBUTE
;
188 styler
.ColourTo(end
, chAttr
);
191 static int classifyTagHTML(unsigned int start
, unsigned int end
,
192 WordList
&keywords
, Accessor
&styler
) {
194 // Copy after the '<'
196 for (unsigned int cPos
= start
; cPos
<= end
&& i
< 30; cPos
++) {
197 char ch
= styler
[cPos
];
199 s
[i
++] = static_cast<char>(tolower(ch
));
202 bool isScript
= false;
203 char chAttr
= SCE_H_TAGUNKNOWN
;
204 if (s
[0] == '!' && s
[1] == '-' && s
[2] == '-') { //Comment
205 chAttr
= SCE_H_COMMENT
;
206 } else if (strcmp(s
, "![cdata[") == 0) { // In lower case because already converted
207 chAttr
= SCE_H_CDATA
;
208 } else if (s
[0] == '!') {
210 } else if (s
[0] == '/') { // Closing tag
211 if (keywords
.InList(s
+ 1))
214 if (keywords
.InList(s
)) {
216 isScript
= 0 == strcmp(s
, "script");
219 if ((chAttr
== SCE_H_TAGUNKNOWN
) && !keywords
)
220 // No keywords -> all are known
222 styler
.ColourTo(end
, chAttr
);
223 return isScript
? SCE_H_SCRIPT
: chAttr
;
226 static void classifyWordHTJS(unsigned int start
, unsigned int end
,
227 WordList
&keywords
, Accessor
&styler
, int inScriptType
) {
228 char chAttr
= SCE_HJ_WORD
;
229 bool wordIsNumber
= isdigit(styler
[start
]) || (styler
[start
] == '.');
231 chAttr
= SCE_HJ_NUMBER
;
234 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
235 s
[i
] = styler
[start
+ i
];
238 if (keywords
.InList(s
))
239 chAttr
= SCE_HJ_KEYWORD
;
241 styler
.ColourTo(end
, statePrintForState(chAttr
, inScriptType
));
244 static int classifyWordHTVB(unsigned int start
, unsigned int end
, WordList
&keywords
, Accessor
&styler
, int inScriptType
) {
245 char chAttr
= SCE_HB_IDENTIFIER
;
246 bool wordIsNumber
= isdigit(styler
[start
]) || (styler
[start
] == '.');
248 chAttr
= SCE_HB_NUMBER
;
251 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
252 s
[i
] = static_cast<char>(tolower(styler
[start
+ i
]));
255 if (keywords
.InList(s
)) {
256 chAttr
= SCE_HB_WORD
;
257 if (strcmp(s
, "rem") == 0)
258 chAttr
= SCE_HB_COMMENTLINE
;
261 styler
.ColourTo(end
, statePrintForState(chAttr
, inScriptType
));
262 if (chAttr
== SCE_HB_COMMENTLINE
)
263 return SCE_HB_COMMENTLINE
;
265 return SCE_HB_DEFAULT
;
268 static void classifyWordHTPy(unsigned int start
, unsigned int end
, WordList
&keywords
, Accessor
&styler
, char *prevWord
, int inScriptType
) {
269 bool wordIsNumber
= isdigit(styler
[start
]);
271 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
272 s
[i
] = styler
[start
+ i
];
275 char chAttr
= SCE_HP_IDENTIFIER
;
276 if (0 == strcmp(prevWord
, "class"))
277 chAttr
= SCE_HP_CLASSNAME
;
278 else if (0 == strcmp(prevWord
, "def"))
279 chAttr
= SCE_HP_DEFNAME
;
280 else if (wordIsNumber
)
281 chAttr
= SCE_HP_NUMBER
;
282 else if (keywords
.InList(s
))
283 chAttr
= SCE_HP_WORD
;
284 styler
.ColourTo(end
, statePrintForState(chAttr
, inScriptType
));
288 // Update the word colour to default or keyword
289 // Called when in a PHP word
290 static void classifyWordHTPHP(unsigned int start
, unsigned int end
, WordList
&keywords
, Accessor
&styler
) {
291 char chAttr
= SCE_HPHP_DEFAULT
;
292 bool wordIsNumber
= isdigit(styler
[start
]);
294 chAttr
= SCE_HPHP_NUMBER
;
297 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
298 s
[i
] = styler
[start
+ i
];
301 if (keywords
.InList(s
))
302 chAttr
= SCE_HPHP_WORD
;
304 styler
.ColourTo(end
, chAttr
);
307 // Return the first state to reach when entering a scripting language
308 static int StateForScript(int scriptLanguage
) {
310 switch (scriptLanguage
) {
312 Result
= SCE_HB_START
;
315 Result
= SCE_HP_START
;
318 Result
= SCE_HPHP_DEFAULT
;
321 Result
= SCE_H_TAGUNKNOWN
;
324 Result
= SCE_HJ_START
;
330 inline bool ishtmlwordchar(char ch
) {
331 return isalnum(ch
) || ch
== '.' || ch
== '-' || ch
== '_' || ch
== ':' || ch
== '!' || ch
== '#';
334 static bool InTagState(int state
) {
335 return state
== SCE_H_TAG
|| state
== SCE_H_TAGUNKNOWN
||
336 state
== SCE_H_SCRIPT
||
337 state
== SCE_H_ATTRIBUTE
|| state
== SCE_H_ATTRIBUTEUNKNOWN
||
338 state
== SCE_H_NUMBER
|| state
== SCE_H_OTHER
||
339 state
== SCE_H_DOUBLESTRING
|| state
== SCE_H_SINGLESTRING
;
342 static bool isLineEnd(char ch
) {
343 return ch
== '\r' || ch
== '\n';
346 static bool isOKBeforeRE(char ch
) {
347 return (ch
== '(') || (ch
== '=') || (ch
== ',');
350 static bool isPHPStringState(int state
) {
352 (state
== SCE_HPHP_HSTRING
) ||
353 (state
== SCE_HPHP_SIMPLESTRING
) ||
354 (state
== SCE_HPHP_HSTRING_VARIABLE
);
357 static void ColouriseHyperTextDoc(unsigned int startPos
, int length
, int initStyle
, WordList
*keywordlists
[],
360 WordList
&keywords
= *keywordlists
[0];
361 WordList
&keywords2
= *keywordlists
[1];
362 WordList
&keywords3
= *keywordlists
[2];
363 WordList
&keywords4
= *keywordlists
[3];
364 WordList
&keywords5
= *keywordlists
[4];
366 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
367 styler
.StartAt(startPos
, 127);
370 int StateToPrint
= initStyle
;
371 int state
= stateForPrintState(StateToPrint
);
373 // If inside a tag, it may be a script tag, so reread from the start to ensure any language tags are seen
374 if (InTagState(state
)) {
375 while ((startPos
> 0) && (InTagState(styler
.StyleAt(startPos
- 1)))) {
379 state
= SCE_H_DEFAULT
;
381 styler
.StartAt(startPos
, 127);
383 int lineState
= eScriptVBS
;
384 int lineCurrent
= styler
.GetLine(startPos
);
386 lineState
= styler
.GetLineState(lineCurrent
);
387 int inScriptType
= (lineState
>> 0) & 0x03; // 2 bits of scripting type
388 bool tagOpened
= (lineState
>> 2) & 0x01; // 1 bit to know if we are in an opened tag
389 bool tagClosing
= (lineState
>> 3) & 0x01; // 1 bit to know if we are in a closing tag
390 int defaultScript
= (lineState
>> 4) & 0x0F; // 4 bits of script name
391 int beforePreProc
= (lineState
>> 8) & 0xFF; // 8 bits of state
393 int scriptLanguage
= ScriptOfState(state
);
395 bool fold
= styler
.GetPropertyInt("fold");
396 bool foldHTML
= styler
.GetPropertyInt("fold.html",0);
397 bool foldCompact
= styler
.GetPropertyInt("fold.compact",1);
399 fold
= foldHTML
&& fold
;
401 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
402 int levelCurrent
= levelPrev
;
409 char chPrevNonWhite
= ' ';
410 styler
.StartSegment(startPos
);
411 int lengthDoc
= startPos
+ length
;
412 for (int i
= startPos
; i
< lengthDoc
; i
++) {
413 char chPrev2
= chPrev
;
415 if (ch
!= ' ' && ch
!= '\t')
418 char chNext
= styler
.SafeGetCharAt(i
+ 1);
419 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
421 // Handle DBCS codepages
422 if (styler
.IsLeadByte(ch
)) {
428 if ((!isspacechar(ch
) || !foldCompact
) && fold
)
431 // decide what is the current state to print (depending of the script tag)
432 StateToPrint
= statePrintForState(state
, inScriptType
);
434 // handle script folding
436 switch (scriptLanguage
) {
439 //not currently supported case eScriptVBS:
441 if ((state
!= SCE_HPHP_COMMENT
) && (state
!= SCE_HPHP_COMMENTLINE
) && (state
!= SCE_HJ_COMMENT
) && (state
!= SCE_HJ_COMMENTLINE
) && (state
!= SCE_HJ_COMMENTDOC
)) {
442 if ((ch
== '{') || (ch
== '}')) {
443 levelCurrent
+= (ch
== '{') ? 1 : -1;
448 if (state
!= SCE_HP_COMMENTLINE
) {
449 if ((ch
== ':') && ((chNext
== '\n') || (chNext
== '\r' && chNext2
== '\n'))) {
451 } else if ((ch
== '\n') && !((chNext
== '\r') && (chNext2
== '\n')) && (chNext
!= '\n')) {
452 // check if the number of tabs is lower than the level
453 int Findlevel
= (levelCurrent
& ~SC_FOLDLEVELBASE
) * 8;
454 for (int j
= 0;Findlevel
> 0;j
++) {
455 char chTmp
= styler
.SafeGetCharAt(i
+ j
+ 1);
458 } else if (chTmp
== ' ') {
464 levelCurrent
-= Findlevel
/ 8;
465 if (Findlevel
% 8) levelCurrent
--;
473 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n')) {
474 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
475 // Avoid triggering two times on Dos/Win
476 // New line -> record any line state onto /next/ line
479 if (visibleChars
== 0)
480 lev
|= SC_FOLDLEVELWHITEFLAG
;
481 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
482 lev
|= SC_FOLDLEVELHEADERFLAG
;
484 styler
.SetLevel(lineCurrent
, lev
);
486 levelPrev
= levelCurrent
;
489 styler
.SetLineState(lineCurrent
,
490 ((inScriptType
& 0x03) << 0) |
491 ((tagOpened
& 0x01) << 2) |
492 ((tagClosing
& 0x01) << 3) |
493 ((defaultScript
& 0x0F) << 4) |
494 ((beforePreProc
& 0xFF) << 8));
497 // generic end of script processing
498 else if ((inScriptType
== eNonHtmlScript
) && (ch
== '<') && (chNext
== '/')) {
499 // Check if it's the end of the script tag (or any other HTML tag)
501 // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!)
502 case SCE_H_DOUBLESTRING
:
503 case SCE_H_SINGLESTRING
:
505 case SCE_HJ_COMMENTDOC
:
506 // SCE_HJ_COMMENTLINE removed as this is a common thing done to hide
507 // the end of script marker from some JS interpreters.
508 //case SCE_HJ_COMMENTLINE:
509 case SCE_HJ_DOUBLESTRING
:
510 case SCE_HJ_SINGLESTRING
:
514 case SCE_HP_TRIPLEDOUBLE
:
517 // maybe we should check here if it's a tag and if it's SCRIPT
518 styler
.ColourTo(i
- 1, StateToPrint
);
519 state
= SCE_H_TAGUNKNOWN
;
520 inScriptType
= eHtml
;
521 scriptLanguage
= eScriptNone
;
523 // unfold closing script
529 /////////////////////////////////////
530 // handle the start of PHP pre-processor = Non-HTML
531 else if ((state
!= SCE_H_ASPAT
) &&
532 !isPHPStringState(state
) &&
533 (state
!= SCE_HPHP_COMMENT
) &&
536 styler
.ColourTo(i
- 1, StateToPrint
);
537 beforePreProc
= state
;
538 scriptLanguage
= segIsScriptingIndicator(styler
, styler
.GetStartSegment() + 2, i
+ 10, eScriptPHP
);
540 i
+= PrintScriptingIndicatorOffset(styler
, styler
.GetStartSegment() + 2, i
+ 10);
541 if (scriptLanguage
== eScriptXML
)
542 styler
.ColourTo(i
, SCE_H_XMLSTART
);
544 styler
.ColourTo(i
, SCE_H_QUESTION
);
545 state
= StateForScript(scriptLanguage
);
546 if (inScriptType
== eNonHtmlScript
)
547 inScriptType
= eNonHtmlScriptPreProc
;
549 inScriptType
= eNonHtmlPreProc
;
552 if (scriptLanguage
== eScriptXML
)
553 levelCurrent
--; // no folding of the XML first tag (all XML-like tags in this case)
555 ch
= styler
.SafeGetCharAt(i
);
559 // handle the start of ASP pre-processor = Non-HTML
560 else if (!isCommentASPState(state
) && (ch
== '<') && (chNext
== '%')) {
561 styler
.ColourTo(i
- 1, StateToPrint
);
562 beforePreProc
= state
;
563 if (inScriptType
== eNonHtmlScript
)
564 inScriptType
= eNonHtmlScriptPreProc
;
566 inScriptType
= eNonHtmlPreProc
;
568 if (chNext2
== '@') {
569 i
+= 2; // place as if it was the second next char treated
571 } else if ((chNext2
== '-') && (styler
.SafeGetCharAt(i
+ 3) == '-')) {
572 styler
.ColourTo(i
+ 3, SCE_H_ASP
);
573 state
= SCE_H_XCCOMMENT
;
574 scriptLanguage
= eScriptVBS
;
577 if (chNext2
== '=') {
578 i
+= 2; // place as if it was the second next char treated
580 i
++; // place as if it was the next char treated
583 state
= StateForScript(defaultScript
);
585 scriptLanguage
= eScriptVBS
;
586 styler
.ColourTo(i
, SCE_H_ASP
);
590 ch
= styler
.SafeGetCharAt(i
);
594 // handle the end of a pre-processor = Non-HTML
596 ((inScriptType
== eNonHtmlPreProc
)
597 || (inScriptType
== eNonHtmlScriptPreProc
)) && (
598 ((scriptLanguage
== eScriptPHP
) && (ch
== '?') && !isPHPStringState(state
) && (state
!= SCE_HPHP_COMMENT
)) ||
599 ((scriptLanguage
!= eScriptNone
) && !isStringState(state
) &&
601 ) && (chNext
== '>')) {
602 if (state
== SCE_H_ASPAT
) {
603 defaultScript
= segIsScriptingIndicator(styler
,
604 styler
.GetStartSegment(), i
- 1, defaultScript
);
606 // Bounce out of any ASP mode
609 classifyWordHTJS(styler
.GetStartSegment(), i
- 1, keywords2
, styler
, inScriptType
);
612 classifyWordHTVB(styler
.GetStartSegment(), i
- 1, keywords3
, styler
, inScriptType
);
615 classifyWordHTPy(styler
.GetStartSegment(), i
- 1, keywords4
, styler
, prevWord
, inScriptType
);
618 classifyWordHTPHP(styler
.GetStartSegment(), i
- 1, keywords5
, styler
);
620 case SCE_H_XCCOMMENT
:
621 styler
.ColourTo(i
- 1, state
);
624 styler
.ColourTo(i
- 1, StateToPrint
);
629 styler
.ColourTo(i
, SCE_H_ASP
);
630 else if (scriptLanguage
== eScriptXML
)
631 styler
.ColourTo(i
, SCE_H_XMLEND
);
633 styler
.ColourTo(i
, SCE_H_QUESTION
);
634 state
= beforePreProc
;
635 if (inScriptType
== eNonHtmlScriptPreProc
)
636 inScriptType
= eNonHtmlScript
;
638 inScriptType
= eHtml
;
639 scriptLanguage
= eScriptNone
;
640 // unfold all scripting languages
644 /////////////////////////////////////
649 // in HTML, fold on tag open and unfold on tag close
657 styler
.ColourTo(i
- 1, StateToPrint
);
658 if (chNext
== '!' && chNext2
== '-' && styler
.SafeGetCharAt(i
+ 3) == '-') {
662 state
= SCE_H_COMMENT
;
664 state
= SCE_H_TAGUNKNOWN
;
665 } else if (ch
== '&') {
666 styler
.ColourTo(i
- 1, SCE_H_DEFAULT
);
667 state
= SCE_H_ENTITY
;
671 if ((ch
== '>') && (chPrev
== '-') && (chPrev2
== '-')) {
672 // unfold HTML comment
674 styler
.ColourTo(i
, StateToPrint
);
675 state
= SCE_H_DEFAULT
;
680 if ((ch
== '>') && (chPrev
== ']') && (chPrev2
== ']')) {
681 styler
.ColourTo(i
, StateToPrint
);
682 state
= SCE_H_DEFAULT
;
689 styler
.ColourTo(i
, StateToPrint
);
690 state
= SCE_H_DEFAULT
;
696 styler
.ColourTo(i
, StateToPrint
);
697 state
= SCE_H_DEFAULT
;
699 if (ch
!= '#' && !isalnum(ch
)) { // Should check that '#' follows '&', but it is unlikely anyway...
700 styler
.ColourTo(i
, SCE_H_TAGUNKNOWN
);
701 state
= SCE_H_DEFAULT
;
704 case SCE_H_TAGUNKNOWN
:
705 if (!ishtmlwordchar(ch
) && !((ch
== '/') && (chPrev
== '<')) && ch
!= '[') {
706 int eClass
= classifyTagHTML(styler
.GetStartSegment(), i
- 1, keywords
, styler
);
707 if (eClass
== SCE_H_SCRIPT
) {
708 inScriptType
= eNonHtmlScript
;
709 scriptLanguage
= defaultScript
;
713 styler
.ColourTo(i
, eClass
);
714 if (inScriptType
== eNonHtmlScript
) {
715 state
= StateForScript(scriptLanguage
);
717 state
= SCE_H_DEFAULT
;
725 } else if (ch
== '/' && chNext
== '>') {
726 if (eClass
== SCE_H_TAGUNKNOWN
) {
727 styler
.ColourTo(i
+ 1, SCE_H_TAGUNKNOWN
);
729 styler
.ColourTo(i
- 1, StateToPrint
);
730 styler
.ColourTo(i
+ 1, SCE_H_TAGEND
);
734 state
= SCE_H_DEFAULT
;
737 if (eClass
!= SCE_H_TAGUNKNOWN
) {
738 if (eClass
== SCE_H_CDATA
) {
740 } else if (eClass
== SCE_H_SGML
) {
749 case SCE_H_ATTRIBUTE
:
750 if (!ishtmlwordchar(ch
) && ch
!= '/' && ch
!= '-') {
751 if (inScriptType
== eNonHtmlScript
) {
752 int scriptLanguagePrev
= scriptLanguage
;
753 scriptLanguage
= segIsScriptingIndicator(styler
, styler
.GetStartSegment(), i
- 1, scriptLanguage
);
754 if ((scriptLanguagePrev
!= scriptLanguage
) && (scriptLanguage
== eScriptNone
))
755 inScriptType
= eHtml
;
757 classifyAttribHTML(styler
.GetStartSegment(), i
- 1, keywords
, styler
);
759 styler
.ColourTo(i
, SCE_H_TAG
);
760 if (inScriptType
== eNonHtmlScript
) {
761 state
= StateForScript(scriptLanguage
);
763 state
= SCE_H_DEFAULT
;
771 } else if (ch
== '=') {
772 styler
.ColourTo(i
, SCE_H_OTHER
);
781 styler
.ColourTo(i
- 1, StateToPrint
);
782 styler
.ColourTo(i
, SCE_H_TAG
);
783 if (inScriptType
== eNonHtmlScript
) {
784 state
= StateForScript(scriptLanguage
);
786 state
= SCE_H_DEFAULT
;
794 } else if (ch
== '\"') {
795 styler
.ColourTo(i
- 1, StateToPrint
);
796 state
= SCE_H_DOUBLESTRING
;
797 } else if (ch
== '\'') {
798 styler
.ColourTo(i
- 1, StateToPrint
);
799 state
= SCE_H_SINGLESTRING
;
800 } else if (ch
== '=') {
801 styler
.ColourTo(i
, StateToPrint
);
803 } else if (ch
== '/' && chNext
== '>') {
804 styler
.ColourTo(i
- 1, StateToPrint
);
805 styler
.ColourTo(i
+ 1, SCE_H_TAGEND
);
808 state
= SCE_H_DEFAULT
;
810 } else if (ch
== '?' && chNext
== '>') {
811 styler
.ColourTo(i
- 1, StateToPrint
);
812 styler
.ColourTo(i
+ 1, SCE_H_XMLEND
);
815 state
= SCE_H_DEFAULT
;
816 } else if (ishtmlwordchar(ch
)) {
817 styler
.ColourTo(i
- 1, StateToPrint
);
818 state
= SCE_H_ATTRIBUTE
;
821 case SCE_H_DOUBLESTRING
:
823 if (inScriptType
== eNonHtmlScript
) {
824 scriptLanguage
= segIsScriptingIndicator(styler
, styler
.GetStartSegment(), i
, scriptLanguage
);
826 styler
.ColourTo(i
, SCE_H_DOUBLESTRING
);
830 case SCE_H_SINGLESTRING
:
832 if (inScriptType
== eNonHtmlScript
) {
833 scriptLanguage
= segIsScriptingIndicator(styler
, styler
.GetStartSegment(), i
, scriptLanguage
);
835 styler
.ColourTo(i
, SCE_H_SINGLESTRING
);
840 if (!ishtmlwordchar(ch
)) {
842 // Should really test for being first character
843 state
= SCE_H_DOUBLESTRING
;
844 } else if (ch
== '\'') {
845 state
= SCE_H_SINGLESTRING
;
847 if (IsNumber(styler
.GetStartSegment(), styler
)) {
848 styler
.ColourTo(i
- 1, SCE_H_NUMBER
);
850 styler
.ColourTo(i
- 1, StateToPrint
);
853 styler
.ColourTo(i
, SCE_H_TAG
);
854 if (inScriptType
== eNonHtmlScript
) {
855 state
= StateForScript(scriptLanguage
);
857 state
= SCE_H_DEFAULT
;
874 if (iswordstart(ch
)) {
875 styler
.ColourTo(i
- 1, StateToPrint
);
877 } else if (ch
== '/' && chNext
== '*') {
878 styler
.ColourTo(i
- 1, StateToPrint
);
880 state
= SCE_HJ_COMMENTDOC
;
882 state
= SCE_HJ_COMMENT
;
883 } else if (ch
== '/' && chNext
== '/') {
884 styler
.ColourTo(i
- 1, StateToPrint
);
885 state
= SCE_HJ_COMMENTLINE
;
886 } else if (ch
== '/' && isOKBeforeRE(chPrevNonWhite
)) {
887 styler
.ColourTo(i
- 1, StateToPrint
);
888 state
= SCE_HJ_REGEX
;
889 } else if (ch
== '\"') {
890 styler
.ColourTo(i
- 1, StateToPrint
);
891 state
= SCE_HJ_DOUBLESTRING
;
892 } else if (ch
== '\'') {
893 styler
.ColourTo(i
- 1, StateToPrint
);
894 state
= SCE_HJ_SINGLESTRING
;
895 } else if ((ch
== '<') && (chNext
== '!') && (chNext2
== '-') &&
896 styler
.SafeGetCharAt(i
+ 3) == '-') {
897 styler
.ColourTo(i
- 1, StateToPrint
);
898 state
= SCE_HJ_COMMENTLINE
;
899 } else if ((ch
== '-') && (chNext
== '-') && (chNext2
== '>')) {
900 styler
.ColourTo(i
- 1, StateToPrint
);
901 state
= SCE_HJ_COMMENTLINE
;
903 } else if (isoperator(ch
)) {
904 styler
.ColourTo(i
- 1, StateToPrint
);
905 styler
.ColourTo(i
, statePrintForState(SCE_HJ_SYMBOLS
, inScriptType
));
906 state
= SCE_HJ_DEFAULT
;
907 } else if ((ch
== ' ') || (ch
== '\t')) {
908 if (state
== SCE_HJ_START
) {
909 styler
.ColourTo(i
- 1, StateToPrint
);
910 state
= SCE_HJ_DEFAULT
;
915 if (!iswordchar(ch
)) {
916 classifyWordHTJS(styler
.GetStartSegment(), i
- 1, keywords2
, styler
, inScriptType
);
917 //styler.ColourTo(i - 1, eHTJSKeyword);
918 state
= SCE_HJ_DEFAULT
;
919 if (ch
== '/' && chNext
== '*') {
921 state
= SCE_HJ_COMMENTDOC
;
923 state
= SCE_HJ_COMMENT
;
924 } else if (ch
== '/' && chNext
== '/') {
925 state
= SCE_HJ_COMMENTLINE
;
926 } else if (ch
== '\"') {
927 state
= SCE_HJ_DOUBLESTRING
;
928 } else if (ch
== '\'') {
929 state
= SCE_HJ_SINGLESTRING
;
930 } else if ((ch
== '-') && (chNext
== '-') && (chNext2
== '>')) {
931 styler
.ColourTo(i
- 1, StateToPrint
);
932 state
= SCE_HJ_COMMENTLINE
;
934 } else if (isoperator(ch
)) {
935 styler
.ColourTo(i
, statePrintForState(SCE_HJ_SYMBOLS
, inScriptType
));
936 state
= SCE_HJ_DEFAULT
;
941 case SCE_HJ_COMMENTDOC
:
942 if (ch
== '/' && chPrev
== '*') {
943 styler
.ColourTo(i
, StateToPrint
);
944 state
= SCE_HJ_DEFAULT
;
947 case SCE_HJ_COMMENTLINE
:
948 if (ch
== '\r' || ch
== '\n') {
949 styler
.ColourTo(i
- 1, statePrintForState(SCE_HJ_COMMENTLINE
, inScriptType
));
950 state
= SCE_HJ_DEFAULT
;
953 case SCE_HJ_DOUBLESTRING
:
955 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
958 } else if (ch
== '\"') {
959 styler
.ColourTo(i
, statePrintForState(SCE_HJ_DOUBLESTRING
, inScriptType
));
960 state
= SCE_HJ_DEFAULT
;
961 } else if ((inScriptType
== eNonHtmlScript
) && (ch
== '-') && (chNext
== '-') && (chNext2
== '>')) {
962 styler
.ColourTo(i
- 1, StateToPrint
);
963 state
= SCE_HJ_COMMENTLINE
;
965 } else if (isLineEnd(ch
)) {
966 styler
.ColourTo(i
- 1, StateToPrint
);
967 state
= SCE_HJ_STRINGEOL
;
970 case SCE_HJ_SINGLESTRING
:
972 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
975 } else if (ch
== '\'') {
976 styler
.ColourTo(i
, statePrintForState(SCE_HJ_SINGLESTRING
, inScriptType
));
977 state
= SCE_HJ_DEFAULT
;
978 } else if ((inScriptType
== eNonHtmlScript
) && (ch
== '-') && (chNext
== '-') && (chNext2
== '>')) {
979 styler
.ColourTo(i
- 1, StateToPrint
);
980 state
= SCE_HJ_COMMENTLINE
;
982 } else if (isLineEnd(ch
)) {
983 styler
.ColourTo(i
- 1, StateToPrint
);
984 state
= SCE_HJ_STRINGEOL
;
987 case SCE_HJ_STRINGEOL
:
988 if (!isLineEnd(ch
)) {
989 styler
.ColourTo(i
- 1, StateToPrint
);
990 state
= SCE_HJ_DEFAULT
;
991 } else if (!isLineEnd(chNext
)) {
992 styler
.ColourTo(i
, StateToPrint
);
993 state
= SCE_HJ_DEFAULT
;
997 if (ch
== '\r' || ch
== '\n' || ch
== '/') {
998 styler
.ColourTo(i
, StateToPrint
);
999 state
= SCE_HJ_DEFAULT
;
1000 } else if (ch
== '\\') {
1001 // Gobble up the quoted character
1002 if (chNext
== '\\' || chNext
== '/') {
1005 chNext
= styler
.SafeGetCharAt(i
+ 1);
1009 case SCE_HB_DEFAULT
:
1011 if (iswordstart(ch
)) {
1012 styler
.ColourTo(i
- 1, StateToPrint
);
1013 state
= SCE_HB_WORD
;
1014 } else if (ch
== '\'') {
1015 styler
.ColourTo(i
- 1, StateToPrint
);
1016 state
= SCE_HB_COMMENTLINE
;
1017 } else if (ch
== '\"') {
1018 styler
.ColourTo(i
- 1, StateToPrint
);
1019 state
= SCE_HB_STRING
;
1020 } else if ((ch
== '<') && (chNext
== '!') && (chNext2
== '-') &&
1021 styler
.SafeGetCharAt(i
+ 3) == '-') {
1022 styler
.ColourTo(i
- 1, StateToPrint
);
1023 state
= SCE_HB_COMMENTLINE
;
1024 } else if (isoperator(ch
)) {
1025 styler
.ColourTo(i
- 1, StateToPrint
);
1026 styler
.ColourTo(i
, statePrintForState(SCE_HB_DEFAULT
, inScriptType
));
1027 state
= SCE_HB_DEFAULT
;
1028 } else if ((ch
== ' ') || (ch
== '\t')) {
1029 if (state
== SCE_HB_START
) {
1030 styler
.ColourTo(i
- 1, StateToPrint
);
1031 state
= SCE_HB_DEFAULT
;
1036 if (!iswordchar(ch
)) {
1037 state
= classifyWordHTVB(styler
.GetStartSegment(), i
- 1, keywords3
, styler
, inScriptType
);
1038 if (state
== SCE_HB_DEFAULT
) {
1040 state
= SCE_HB_STRING
;
1041 } else if (ch
== '\'') {
1042 state
= SCE_HB_COMMENTLINE
;
1043 } else if (isoperator(ch
)) {
1044 styler
.ColourTo(i
, statePrintForState(SCE_HB_DEFAULT
, inScriptType
));
1045 state
= SCE_HB_DEFAULT
;
1052 styler
.ColourTo(i
, StateToPrint
);
1053 state
= SCE_HB_DEFAULT
;
1054 } else if (ch
== '\r' || ch
== '\n') {
1055 styler
.ColourTo(i
- 1, StateToPrint
);
1056 state
= SCE_HB_STRINGEOL
;
1059 case SCE_HB_COMMENTLINE
:
1060 if (ch
== '\r' || ch
== '\n') {
1061 styler
.ColourTo(i
- 1, StateToPrint
);
1062 state
= SCE_HB_DEFAULT
;
1065 case SCE_HB_STRINGEOL
:
1066 if (!isLineEnd(ch
)) {
1067 styler
.ColourTo(i
- 1, StateToPrint
);
1068 state
= SCE_HB_DEFAULT
;
1069 } else if (!isLineEnd(chNext
)) {
1070 styler
.ColourTo(i
, StateToPrint
);
1071 state
= SCE_HB_DEFAULT
;
1074 case SCE_HP_DEFAULT
:
1076 if (iswordstart(ch
)) {
1077 styler
.ColourTo(i
- 1, StateToPrint
);
1078 state
= SCE_HP_WORD
;
1079 } else if ((ch
== '<') && (chNext
== '!') && (chNext2
== '-') &&
1080 styler
.SafeGetCharAt(i
+ 3) == '-') {
1081 styler
.ColourTo(i
- 1, StateToPrint
);
1082 state
= SCE_HP_COMMENTLINE
;
1083 } else if (ch
== '#') {
1084 styler
.ColourTo(i
- 1, StateToPrint
);
1085 state
= SCE_HP_COMMENTLINE
;
1086 } else if (ch
== '\"') {
1087 styler
.ColourTo(i
- 1, StateToPrint
);
1088 if (chNext
== '\"' && chNext2
== '\"') {
1090 state
= SCE_HP_TRIPLEDOUBLE
;
1093 chNext
= styler
.SafeGetCharAt(i
+ 1);
1095 // state = statePrintForState(SCE_HP_STRING,inScriptType);
1096 state
= SCE_HP_STRING
;
1098 } else if (ch
== '\'') {
1099 styler
.ColourTo(i
- 1, StateToPrint
);
1100 if (chNext
== '\'' && chNext2
== '\'') {
1102 state
= SCE_HP_TRIPLE
;
1105 chNext
= styler
.SafeGetCharAt(i
+ 1);
1107 state
= SCE_HP_CHARACTER
;
1109 } else if (isoperator(ch
)) {
1110 styler
.ColourTo(i
- 1, StateToPrint
);
1111 styler
.ColourTo(i
, statePrintForState(SCE_HP_OPERATOR
, inScriptType
));
1112 } else if ((ch
== ' ') || (ch
== '\t')) {
1113 if (state
== SCE_HP_START
) {
1114 styler
.ColourTo(i
- 1, StateToPrint
);
1115 state
= SCE_HP_DEFAULT
;
1120 if (!iswordchar(ch
)) {
1121 classifyWordHTPy(styler
.GetStartSegment(), i
- 1, keywords4
, styler
, prevWord
, inScriptType
);
1122 state
= SCE_HP_DEFAULT
;
1124 state
= SCE_HP_COMMENTLINE
;
1125 } else if (ch
== '\"') {
1126 if (chNext
== '\"' && chNext2
== '\"') {
1128 state
= SCE_HP_TRIPLEDOUBLE
;
1131 chNext
= styler
.SafeGetCharAt(i
+ 1);
1133 state
= SCE_HP_STRING
;
1135 } else if (ch
== '\'') {
1136 if (chNext
== '\'' && chNext2
== '\'') {
1138 state
= SCE_HP_TRIPLE
;
1141 chNext
= styler
.SafeGetCharAt(i
+ 1);
1143 state
= SCE_HP_CHARACTER
;
1145 } else if (isoperator(ch
)) {
1146 styler
.ColourTo(i
, statePrintForState(SCE_HP_OPERATOR
, inScriptType
));
1150 case SCE_HP_COMMENTLINE
:
1151 if (ch
== '\r' || ch
== '\n') {
1152 styler
.ColourTo(i
- 1, StateToPrint
);
1153 state
= SCE_HP_DEFAULT
;
1158 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
1161 chNext
= styler
.SafeGetCharAt(i
+ 1);
1163 } else if (ch
== '\"') {
1164 styler
.ColourTo(i
, StateToPrint
);
1165 state
= SCE_HP_DEFAULT
;
1168 case SCE_HP_CHARACTER
:
1170 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
1173 chNext
= styler
.SafeGetCharAt(i
+ 1);
1175 } else if (ch
== '\'') {
1176 styler
.ColourTo(i
, StateToPrint
);
1177 state
= SCE_HP_DEFAULT
;
1181 if (ch
== '\'' && chPrev
== '\'' && chPrev2
== '\'') {
1182 styler
.ColourTo(i
, StateToPrint
);
1183 state
= SCE_HP_DEFAULT
;
1186 case SCE_HP_TRIPLEDOUBLE
:
1187 if (ch
== '\"' && chPrev
== '\"' && chPrev2
== '\"') {
1188 styler
.ColourTo(i
, StateToPrint
);
1189 state
= SCE_HP_DEFAULT
;
1192 ///////////// start - PHP state handling
1194 if (!iswordstart(ch
)) {
1195 classifyWordHTPHP(styler
.GetStartSegment(), i
- 1, keywords5
, styler
);
1196 if (ch
== '/' && chNext
== '*') {
1198 state
= SCE_HPHP_COMMENT
;
1199 } else if (ch
== '/' && chNext
== '/') {
1201 state
= SCE_HPHP_COMMENTLINE
;
1202 } else if (ch
== '#') {
1203 state
= SCE_HPHP_COMMENTLINE
;
1204 } else if (ch
== '\"') {
1205 state
= SCE_HPHP_HSTRING
;
1206 } else if (ch
== '\'') {
1207 state
= SCE_HPHP_SIMPLESTRING
;
1208 } else if (ch
== '$') {
1209 state
= SCE_HPHP_VARIABLE
;
1210 } else if (isoperator(ch
)) {
1211 state
= SCE_HPHP_OPERATOR
;
1213 state
= SCE_HPHP_DEFAULT
;
1217 case SCE_HPHP_NUMBER
:
1219 styler
.ColourTo(i
- 1, SCE_HPHP_NUMBER
);
1221 state
=SCE_HPHP_OPERATOR
;
1223 state
= SCE_HPHP_DEFAULT
;
1226 case SCE_HPHP_VARIABLE
:
1227 if (!iswordstart(ch
)) {
1228 styler
.ColourTo(i
- 1, SCE_HPHP_VARIABLE
);
1230 state
=SCE_HPHP_OPERATOR
;
1232 state
= SCE_HPHP_DEFAULT
;
1235 case SCE_HPHP_COMMENT
:
1236 if (ch
== '/' && chPrev
== '*') {
1237 styler
.ColourTo(i
, StateToPrint
);
1238 state
= SCE_HPHP_DEFAULT
;
1241 case SCE_HPHP_COMMENTLINE
:
1242 if (ch
== '\r' || ch
== '\n') {
1243 styler
.ColourTo(i
- 1, StateToPrint
);
1244 state
= SCE_HPHP_DEFAULT
;
1247 case SCE_HPHP_HSTRING
:
1249 // skip the next char
1251 } else if (ch
== '$') {
1252 styler
.ColourTo(i
-1, StateToPrint
);
1253 state
= SCE_HPHP_HSTRING_VARIABLE
;
1254 } else if (ch
== '\"') {
1255 styler
.ColourTo(i
, StateToPrint
);
1256 state
= SCE_HPHP_DEFAULT
;
1259 case SCE_HPHP_SIMPLESTRING
:
1261 // skip the next char
1263 } else if (ch
== '\'') {
1264 styler
.ColourTo(i
, StateToPrint
);
1265 state
= SCE_HPHP_DEFAULT
;
1268 case SCE_HPHP_HSTRING_VARIABLE
:
1269 if (!iswordstart(ch
)) {
1270 styler
.ColourTo(i
-1, StateToPrint
);
1271 i
--; // strange but it works
1272 state
= SCE_HPHP_HSTRING
;
1275 case SCE_HPHP_OPERATOR
:
1276 case SCE_HPHP_DEFAULT
:
1277 styler
.ColourTo(i
- 1, StateToPrint
);
1279 state
= SCE_HPHP_NUMBER
;
1280 } else if (iswordstart(ch
)) {
1281 state
= SCE_HPHP_WORD
;
1282 } else if (ch
== '/' && chNext
== '*') {
1284 state
= SCE_HPHP_COMMENT
;
1285 } else if (ch
== '/' && chNext
== '/') {
1287 state
= SCE_HPHP_COMMENTLINE
;
1288 } else if (ch
== '#') {
1289 state
= SCE_HPHP_COMMENTLINE
;
1290 } else if (ch
== '\"') {
1291 state
= SCE_HPHP_HSTRING
;
1292 } else if (ch
== '\'') {
1293 state
= SCE_HPHP_SIMPLESTRING
;
1294 } else if (ch
== '$') {
1295 state
= SCE_HPHP_VARIABLE
;
1296 } else if (isoperator(ch
)) {
1297 state
= SCE_HPHP_OPERATOR
;
1298 } else if ((state
== SCE_HPHP_OPERATOR
) && (isspacechar(ch
))) {
1299 state
= SCE_HPHP_DEFAULT
;
1302 ///////////// end - PHP state handling
1305 // Some of the above terminated their lexeme but since the same character starts
1306 // the same class again, only reenter if non empty segment.
1307 bool nonEmptySegment
= i
>= static_cast<int>(styler
.GetStartSegment());
1308 if (state
== SCE_HB_DEFAULT
) { // One of the above succeeded
1309 if ((ch
== '\"') && (nonEmptySegment
)) {
1310 state
= SCE_HB_STRING
;
1311 } else if (ch
== '\'') {
1312 state
= SCE_HB_COMMENTLINE
;
1313 } else if (iswordstart(ch
)) {
1314 state
= SCE_HB_WORD
;
1315 } else if (isoperator(ch
)) {
1316 styler
.ColourTo(i
, SCE_HB_DEFAULT
);
1318 } else if (state
== SCE_HBA_DEFAULT
) { // One of the above succeeded
1319 if ((ch
== '\"') && (nonEmptySegment
)) {
1320 state
= SCE_HBA_STRING
;
1321 } else if (ch
== '\'') {
1322 state
= SCE_HBA_COMMENTLINE
;
1323 } else if (iswordstart(ch
)) {
1324 state
= SCE_HBA_WORD
;
1325 } else if (isoperator(ch
)) {
1326 styler
.ColourTo(i
, SCE_HBA_DEFAULT
);
1328 } else if (state
== SCE_HJ_DEFAULT
) { // One of the above succeeded
1329 if (ch
== '/' && chNext
== '*') {
1330 if (styler
.SafeGetCharAt(i
+ 2) == '*')
1331 state
= SCE_HJ_COMMENTDOC
;
1333 state
= SCE_HJ_COMMENT
;
1334 } else if (ch
== '/' && chNext
== '/') {
1335 state
= SCE_HJ_COMMENTLINE
;
1336 } else if ((ch
== '\"') && (nonEmptySegment
)) {
1337 state
= SCE_HJ_DOUBLESTRING
;
1338 } else if ((ch
== '\'') && (nonEmptySegment
)) {
1339 state
= SCE_HJ_SINGLESTRING
;
1340 } else if (iswordstart(ch
)) {
1341 state
= SCE_HJ_WORD
;
1342 } else if (isoperator(ch
)) {
1343 styler
.ColourTo(i
, statePrintForState(SCE_HJ_SYMBOLS
, inScriptType
));
1348 StateToPrint
= statePrintForState(state
, inScriptType
);
1349 styler
.ColourTo(lengthDoc
- 1, StateToPrint
);
1351 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
1353 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
1354 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
1358 LexerModule
lmHTML(SCLEX_HTML
, ColouriseHyperTextDoc
, "hypertext");
1359 LexerModule
lmXML(SCLEX_XML
, ColouriseHyperTextDoc
, "xml");