]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexHTML.cxx
345b15edcb3b1c6c6a931d7340e8aae2fc996a1a
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexHTML.cxx
1 // Scintilla source code edit control
2 /** @file LexHTML.cxx
3 ** Lexer for HTML.
4 **/
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13
14 #include "Platform.h"
15
16 #include "PropSet.h"
17 #include "Accessor.h"
18 #include "StyleContext.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22
23 #define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START)
24 #define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START)
25 #define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START)
26
27 enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock };
28 enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc };
29
30 static inline bool IsAWordChar(const int ch) {
31 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
32 }
33
34 static inline bool IsAWordStart(const int ch) {
35 return (ch < 0x80) && (isalnum(ch) || ch == '_');
36 }
37
38 static script_type segIsScriptingIndicator(Accessor &styler, unsigned int start, unsigned int end, script_type prevValue) {
39 char s[30 + 1];
40 unsigned int i = 0;
41 for (; i < end - start + 1 && i < 30; i++) {
42 s[i] = static_cast<char>(tolower(styler[start + i]));
43 }
44 s[i] = '\0';
45 //Platform::DebugPrintf("Scripting indicator [%s]\n", s);
46 if (strstr(s, "src")) // External script
47 return eScriptNone;
48 if (strstr(s, "vbs"))
49 return eScriptVBS;
50 if (strstr(s, "pyth"))
51 return eScriptPython;
52 if (strstr(s, "javas"))
53 return eScriptJS;
54 if (strstr(s, "jscr"))
55 return eScriptJS;
56 if (strstr(s, "php"))
57 return eScriptPHP;
58 if (strstr(s, "xml"))
59 return eScriptXML;
60
61 return prevValue;
62 }
63
64 static int PrintScriptingIndicatorOffset(Accessor &styler, unsigned int start, unsigned int end) {
65 int iResult = 0;
66 char s[30 + 1];
67 unsigned int i = 0;
68 for (; i < end - start + 1 && i < 30; i++) {
69 s[i] = static_cast<char>(tolower(styler[start + i]));
70 }
71 s[i] = '\0';
72 if (0 == strncmp(s, "php", 3)) {
73 iResult = 3;
74 }
75
76 return iResult;
77 }
78
79 static script_type ScriptOfState(int state) {
80 if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
81 return eScriptPython;
82 } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
83 return eScriptVBS;
84 } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
85 return eScriptJS;
86 } else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) {
87 return eScriptPHP;
88 } else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) {
89 return eScriptSGML;
90 } else if (state == SCE_H_SGML_BLOCK_DEFAULT) {
91 return eScriptSGMLblock;
92 } else {
93 return eScriptNone;
94 }
95 }
96
97 static int statePrintForState(int state, script_mode inScriptType) {
98 int StateToPrint;
99
100 if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
101 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON);
102 } else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
103 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS);
104 } else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
105 StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS);
106 } else {
107 StateToPrint = state;
108 }
109
110 return StateToPrint;
111 }
112
113 static int stateForPrintState(int StateToPrint) {
114 int state;
115
116 if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) {
117 state = StateToPrint - SCE_HA_PYTHON;
118 } else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) {
119 state = StateToPrint - SCE_HA_VBS;
120 } else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) {
121 state = StateToPrint - SCE_HA_JS;
122 } else {
123 state = StateToPrint;
124 }
125
126 return state;
127 }
128
129 static inline bool IsNumber(unsigned int start, Accessor &styler) {
130 return isdigit(styler[start]) || (styler[start] == '.') ||
131 (styler[start] == '-') || (styler[start] == '#');
132 }
133
134 static inline bool isStringState(int state) {
135 bool bResult;
136
137 switch (state) {
138 case SCE_HJ_DOUBLESTRING:
139 case SCE_HJ_SINGLESTRING:
140 case SCE_HJA_DOUBLESTRING:
141 case SCE_HJA_SINGLESTRING:
142 case SCE_HB_STRING:
143 case SCE_HBA_STRING:
144 case SCE_HP_STRING:
145 case SCE_HPA_STRING:
146 case SCE_HPHP_HSTRING:
147 case SCE_HPHP_SIMPLESTRING:
148 bResult = true;
149 break;
150 default :
151 bResult = false;
152 break;
153 }
154 return bResult;
155 }
156
157 // not really well done, since it's only comments that should lex the %> and <%
158 static inline bool isCommentASPState(int state) {
159 bool bResult;
160
161 switch (state) {
162 case SCE_HJ_COMMENT:
163 case SCE_HJ_COMMENTLINE:
164 case SCE_HJ_COMMENTDOC:
165 case SCE_HB_COMMENTLINE:
166 case SCE_HP_COMMENTLINE:
167 case SCE_HPHP_COMMENT:
168 case SCE_HPHP_COMMENTLINE:
169 bResult = true;
170 break;
171 default :
172 bResult = false;
173 break;
174 }
175 return bResult;
176 }
177
178 static void classifyAttribHTML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
179 bool wordIsNumber = IsNumber(start, styler);
180 char chAttr = SCE_H_ATTRIBUTEUNKNOWN;
181 if (wordIsNumber) {
182 chAttr = SCE_H_NUMBER;
183 } else {
184 char s[30 + 1];
185 unsigned int i = 0;
186 for (; i < end - start + 1 && i < 30; i++) {
187 s[i] = static_cast<char>(tolower(styler[start + i]));
188 }
189 s[i] = '\0';
190 if (keywords.InList(s))
191 chAttr = SCE_H_ATTRIBUTE;
192 }
193 if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords)
194 // No keywords -> all are known
195 chAttr = SCE_H_ATTRIBUTE;
196 styler.ColourTo(end, chAttr);
197 }
198
199 static int classifyTagHTML(unsigned int start, unsigned int end,
200 WordList &keywords, Accessor &styler, bool &tagDontFold,
201 bool caseSensitive) {
202 char s[30 + 2];
203 // Copy after the '<'
204 unsigned int i = 0;
205 for (unsigned int cPos = start; cPos <= end && i < 30; cPos++) {
206 char ch = styler[cPos];
207 if ((ch != '<') && (ch != '/')) {
208 s[i++] = caseSensitive ? ch : static_cast<char>(tolower(ch));
209 }
210 }
211
212 //The following is only a quick hack, to see if this whole thing would work
213 //we first need the tagname with a trailing space...
214 s[i] = ' ';
215 s[i+1] = '\0';
216
217 //...to find it in the list of no-container-tags
218 // (There are many more. We will need a keywordlist in the property file for this)
219 tagDontFold = (NULL != strstr("meta link img area br hr input ",s));
220
221 //now we can remove the trailing space
222 s[i] = '\0';
223
224 bool isScript = false;
225 char chAttr = SCE_H_TAGUNKNOWN;
226 if (s[0] == '!') {
227 chAttr = SCE_H_SGML_DEFAULT;
228 } else if (s[0] == '/') { // Closing tag
229 if (keywords.InList(s + 1))
230 chAttr = SCE_H_TAG;
231 } else {
232 if (keywords.InList(s)) {
233 chAttr = SCE_H_TAG;
234 isScript = 0 == strcmp(s, "script");
235 }
236 }
237 if ((chAttr == SCE_H_TAGUNKNOWN) && !keywords) {
238 // No keywords -> all are known
239 chAttr = SCE_H_TAG;
240 isScript = 0 == strcmp(s, "script");
241 }
242 styler.ColourTo(end, chAttr);
243 return isScript ? SCE_H_SCRIPT : chAttr;
244 }
245
246 static void classifyWordHTJS(unsigned int start, unsigned int end,
247 WordList &keywords, Accessor &styler, script_mode inScriptType) {
248 char chAttr = SCE_HJ_WORD;
249 bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
250 if (wordIsNumber)
251 chAttr = SCE_HJ_NUMBER;
252 else {
253 char s[30 + 1];
254 unsigned int i = 0;
255 for (; i < end - start + 1 && i < 30; i++) {
256 s[i] = styler[start + i];
257 }
258 s[i] = '\0';
259 if (keywords.InList(s))
260 chAttr = SCE_HJ_KEYWORD;
261 }
262 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
263 }
264
265 static int classifyWordHTVB(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, script_mode inScriptType) {
266 char chAttr = SCE_HB_IDENTIFIER;
267 bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
268 if (wordIsNumber)
269 chAttr = SCE_HB_NUMBER;
270 else {
271 char s[30 + 1];
272 unsigned int i = 0;
273 for (; i < end - start + 1 && i < 30; i++) {
274 s[i] = static_cast<char>(tolower(styler[start + i]));
275 }
276 s[i] = '\0';
277 if (keywords.InList(s)) {
278 chAttr = SCE_HB_WORD;
279 if (strcmp(s, "rem") == 0)
280 chAttr = SCE_HB_COMMENTLINE;
281 }
282 }
283 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
284 if (chAttr == SCE_HB_COMMENTLINE)
285 return SCE_HB_COMMENTLINE;
286 else
287 return SCE_HB_DEFAULT;
288 }
289
290 static void classifyWordHTPy(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord, script_mode inScriptType) {
291 bool wordIsNumber = isdigit(styler[start]) != 0;
292 char s[30 + 1];
293 unsigned int i = 0;
294 for (; i < end - start + 1 && i < 30; i++) {
295 s[i] = styler[start + i];
296 }
297 s[i] = '\0';
298 char chAttr = SCE_HP_IDENTIFIER;
299 if (0 == strcmp(prevWord, "class"))
300 chAttr = SCE_HP_CLASSNAME;
301 else if (0 == strcmp(prevWord, "def"))
302 chAttr = SCE_HP_DEFNAME;
303 else if (wordIsNumber)
304 chAttr = SCE_HP_NUMBER;
305 else if (keywords.InList(s))
306 chAttr = SCE_HP_WORD;
307 styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
308 strcpy(prevWord, s);
309 }
310
311 // Update the word colour to default or keyword
312 // Called when in a PHP word
313 static void classifyWordHTPHP(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
314 char chAttr = SCE_HPHP_DEFAULT;
315 bool wordIsNumber = isdigit(styler[start]) != 0;
316 if (wordIsNumber)
317 chAttr = SCE_HPHP_NUMBER;
318 else {
319 char s[100 + 1];
320 unsigned int i = 0;
321 for (; i < end - start + 1 && i < 100; i++) {
322 s[i] = static_cast<char>(tolower(styler[start + i]));
323 }
324 s[i] = '\0';
325 if (keywords.InList(s))
326 chAttr = SCE_HPHP_WORD;
327 }
328 styler.ColourTo(end, chAttr);
329 }
330
331 static bool isWordHSGML(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
332 char s[30 + 1];
333 unsigned int i = 0;
334 for (; i < end - start + 1 && i < 30; i++) {
335 s[i] = styler[start + i];
336 }
337 s[i] = '\0';
338 return keywords.InList(s);
339 }
340
341 static bool isWordCdata(unsigned int start, unsigned int end, Accessor &styler) {
342 char s[30 + 1];
343 unsigned int i = 0;
344 for (; i < end - start + 1 && i < 30; i++) {
345 s[i] = styler[start + i];
346 }
347 s[i] = '\0';
348 return (0 == strcmp(s, "[CDATA["));
349 }
350
351 // Return the first state to reach when entering a scripting language
352 static int StateForScript(script_type scriptLanguage) {
353 int Result;
354 switch (scriptLanguage) {
355 case eScriptVBS:
356 Result = SCE_HB_START;
357 break;
358 case eScriptPython:
359 Result = SCE_HP_START;
360 break;
361 case eScriptPHP:
362 Result = SCE_HPHP_DEFAULT;
363 break;
364 case eScriptXML:
365 Result = SCE_H_TAGUNKNOWN;
366 break;
367 case eScriptSGML:
368 Result = SCE_H_SGML_DEFAULT;
369 break;
370 default :
371 Result = SCE_HJ_START;
372 break;
373 }
374 return Result;
375 }
376
377 static inline bool ishtmlwordchar(char ch) {
378 return isalnum(ch) || ch == '.' || ch == '-' || ch == '_' || ch == ':' || ch == '!' || ch == '#';
379 }
380
381 static inline bool issgmlwordchar(char ch) {
382 return isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '[';
383 }
384
385 static inline bool IsPhpWordStart(const unsigned char ch) {
386 return isalpha(ch) || (ch == '_') || (ch >= 0x7f);
387 }
388
389 static inline bool IsPhpWordChar(char ch) {
390 return isdigit(ch) || IsPhpWordStart(ch);
391 }
392
393 static bool InTagState(int state) {
394 return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN ||
395 state == SCE_H_SCRIPT ||
396 state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN ||
397 state == SCE_H_NUMBER || state == SCE_H_OTHER ||
398 state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING;
399 }
400
401 static bool IsCommentState(const int state) {
402 return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT;
403 }
404
405 static bool isLineEnd(char ch) {
406 return ch == '\r' || ch == '\n';
407 }
408
409 static bool isOKBeforeRE(char ch) {
410 return (ch == '(') || (ch == '=') || (ch == ',');
411 }
412
413 static bool isPHPStringState(int state) {
414 return
415 (state == SCE_HPHP_HSTRING) ||
416 (state == SCE_HPHP_SIMPLESTRING) ||
417 (state == SCE_HPHP_HSTRING_VARIABLE);
418 }
419
420 static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
421 Accessor &styler) {
422 WordList &keywords = *keywordlists[0];
423 WordList &keywords2 = *keywordlists[1];
424 WordList &keywords3 = *keywordlists[2];
425 WordList &keywords4 = *keywordlists[3];
426 WordList &keywords5 = *keywordlists[4];
427 WordList &keywords6 = *keywordlists[5]; // SGML (DTD) keywords
428
429 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
430 styler.StartAt(startPos, STYLE_MAX);
431 char prevWord[200];
432 prevWord[0] = '\0';
433 int StateToPrint = initStyle;
434 int state = stateForPrintState(StateToPrint);
435
436 // If inside a tag, it may be a script tag, so reread from the start to ensure any language tags are seen
437 if (InTagState(state)) {
438 while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) {
439 startPos--;
440 length++;
441 }
442 state = SCE_H_DEFAULT;
443 }
444 styler.StartAt(startPos, STYLE_MAX);
445
446 int lineCurrent = styler.GetLine(startPos);
447 int lineState;
448 if (lineCurrent > 0) {
449 lineState = styler.GetLineState(lineCurrent);
450 } else {
451 // Default client and ASP scripting language is JavaScript
452 lineState = eScriptJS << 8;
453 lineState |= styler.GetPropertyInt("asp.default.language", eScriptJS) << 4;
454 }
455 script_mode inScriptType = script_mode((lineState >> 0) & 0x03); // 2 bits of scripting mode
456 bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag
457 bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag
458 bool tagDontFold = false; //some HTML tags should not be folded
459 script_type aspScript = script_type((lineState >> 4) & 0x0F); // 4 bits of script name
460 script_type clientScript = script_type((lineState >> 8) & 0x0F); // 4 bits of script name
461 int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state
462
463 script_type scriptLanguage = ScriptOfState(state);
464
465 const bool foldHTML = styler.GetPropertyInt("fold.html", 0) != 0;
466 const bool fold = foldHTML && styler.GetPropertyInt("fold", 0);
467 const bool foldHTMLPreprocessor = foldHTML && styler.GetPropertyInt("fold.html.preprocessor", 1);
468 const bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
469 const bool caseSensitive = styler.GetPropertyInt("html.tags.case.sensitive", 0) != 0;
470
471 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
472 int levelCurrent = levelPrev;
473 int visibleChars = 0;
474
475 char chPrev = ' ';
476 char ch = ' ';
477 char chPrevNonWhite = ' ';
478 styler.StartSegment(startPos);
479 const int lengthDoc = startPos + length;
480 for (int i = startPos; i < lengthDoc; i++) {
481 const char chPrev2 = chPrev;
482 chPrev = ch;
483 if (ch != ' ' && ch != '\t')
484 chPrevNonWhite = ch;
485 ch = styler[i];
486 char chNext = styler.SafeGetCharAt(i + 1);
487 const char chNext2 = styler.SafeGetCharAt(i + 2);
488
489 // Handle DBCS codepages
490 if (styler.IsLeadByte(ch)) {
491 chPrev = ' ';
492 i += 1;
493 continue;
494 }
495
496 if ((!isspacechar(ch) || !foldCompact) && fold)
497 visibleChars++;
498
499 // decide what is the current state to print (depending of the script tag)
500 StateToPrint = statePrintForState(state, inScriptType);
501
502 // handle script folding
503 if (fold) {
504 switch (scriptLanguage) {
505 case eScriptJS:
506 case eScriptPHP:
507 //not currently supported case eScriptVBS:
508
509 if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) {
510 //Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle);
511 //if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) {
512 if ((ch == '{') || (ch == '}')) {
513 levelCurrent += (ch == '{') ? 1 : -1;
514 }
515 }
516 break;
517 case eScriptPython:
518 if (state != SCE_HP_COMMENTLINE) {
519 if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) {
520 levelCurrent++;
521 } else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) {
522 // check if the number of tabs is lower than the level
523 int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8;
524 for (int j = 0; Findlevel > 0; j++) {
525 char chTmp = styler.SafeGetCharAt(i + j + 1);
526 if (chTmp == '\t') {
527 Findlevel -= 8;
528 } else if (chTmp == ' ') {
529 Findlevel--;
530 } else {
531 break;
532 }
533 }
534
535 if (Findlevel > 0) {
536 levelCurrent -= Findlevel / 8;
537 if (Findlevel % 8)
538 levelCurrent--;
539 }
540 }
541 }
542 break;
543 default:
544 break;
545 }
546 }
547
548 if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
549 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
550 // Avoid triggering two times on Dos/Win
551 // New line -> record any line state onto /next/ line
552 if (fold) {
553 int lev = levelPrev;
554 if (visibleChars == 0)
555 lev |= SC_FOLDLEVELWHITEFLAG;
556 if ((levelCurrent > levelPrev) && (visibleChars > 0))
557 lev |= SC_FOLDLEVELHEADERFLAG;
558
559 styler.SetLevel(lineCurrent, lev);
560 visibleChars = 0;
561 levelPrev = levelCurrent;
562 }
563 lineCurrent++;
564 styler.SetLineState(lineCurrent,
565 ((inScriptType & 0x03) << 0) |
566 ((tagOpened & 0x01) << 2) |
567 ((tagClosing & 0x01) << 3) |
568 ((aspScript & 0x0F) << 4) |
569 ((clientScript & 0x0F) << 8) |
570 ((beforePreProc & 0xFF) << 12));
571 }
572
573 // generic end of script processing
574 else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) {
575 // Check if it's the end of the script tag (or any other HTML tag)
576 switch (state) {
577 // in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!)
578 case SCE_H_DOUBLESTRING:
579 case SCE_H_SINGLESTRING:
580 case SCE_HJ_COMMENT:
581 case SCE_HJ_COMMENTDOC:
582 // SCE_HJ_COMMENTLINE removed as this is a common thing done to hide
583 // the end of script marker from some JS interpreters.
584 //case SCE_HJ_COMMENTLINE:
585 case SCE_HJ_DOUBLESTRING:
586 case SCE_HJ_SINGLESTRING:
587 case SCE_HJ_REGEX:
588 case SCE_HB_STRING:
589 case SCE_HP_STRING:
590 case SCE_HP_TRIPLE:
591 case SCE_HP_TRIPLEDOUBLE:
592 break;
593 default :
594 // closing tag of the script (it's a closing HTML tag anyway)
595 styler.ColourTo(i - 1, StateToPrint);
596 state = SCE_H_TAGUNKNOWN;
597 inScriptType = eHtml;
598 scriptLanguage = eScriptNone;
599 clientScript = eScriptJS;
600 i += 2;
601 visibleChars += 2;
602 tagClosing = true;
603 continue;
604 }
605 }
606
607 /////////////////////////////////////
608 // handle the start of PHP pre-processor = Non-HTML
609 else if ((state != SCE_H_ASPAT) &&
610 !isPHPStringState(state) &&
611 (state != SCE_HPHP_COMMENT) &&
612 (ch == '<') &&
613 (chNext == '?')) {
614 styler.ColourTo(i - 1, StateToPrint);
615 beforePreProc = state;
616 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment() + 2, i + 10, eScriptPHP);
617 i++;
618 visibleChars++;
619 i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 10);
620 if (scriptLanguage == eScriptXML)
621 styler.ColourTo(i, SCE_H_XMLSTART);
622 else
623 styler.ColourTo(i, SCE_H_QUESTION);
624 state = StateForScript(scriptLanguage);
625 if (inScriptType == eNonHtmlScript)
626 inScriptType = eNonHtmlScriptPreProc;
627 else
628 inScriptType = eNonHtmlPreProc;
629 // fold whole script
630 if (foldHTMLPreprocessor){
631 levelCurrent++;
632 if (scriptLanguage == eScriptXML)
633 levelCurrent--; // no folding of the XML first tag (all XML-like tags in this case)
634 }
635 // should be better
636 ch = styler.SafeGetCharAt(i);
637 continue;
638 }
639
640 // handle the start of ASP pre-processor = Non-HTML
641 else if (!isCommentASPState(state) && (ch == '<') && (chNext == '%')) {
642 styler.ColourTo(i - 1, StateToPrint);
643 beforePreProc = state;
644 if (inScriptType == eNonHtmlScript)
645 inScriptType = eNonHtmlScriptPreProc;
646 else
647 inScriptType = eNonHtmlPreProc;
648
649 if (chNext2 == '@') {
650 i += 2; // place as if it was the second next char treated
651 visibleChars += 2;
652 state = SCE_H_ASPAT;
653 } else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) {
654 styler.ColourTo(i + 3, SCE_H_ASP);
655 state = SCE_H_XCCOMMENT;
656 scriptLanguage = eScriptVBS;
657 continue;
658 } else {
659 if (chNext2 == '=') {
660 i += 2; // place as if it was the second next char treated
661 visibleChars += 2;
662 } else {
663 i++; // place as if it was the next char treated
664 visibleChars++;
665 }
666
667 state = StateForScript(aspScript);
668 }
669 scriptLanguage = eScriptVBS;
670 styler.ColourTo(i, SCE_H_ASP);
671 // fold whole script
672 if (foldHTMLPreprocessor)
673 levelCurrent++;
674 // should be better
675 ch = styler.SafeGetCharAt(i);
676 continue;
677 }
678
679 /////////////////////////////////////
680 // handle the start of SGML language (DTD)
681 else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) &&
682 (chPrev == '<') &&
683 (ch == '!') &&
684 (StateToPrint != SCE_H_CDATA) && (!IsCommentState(StateToPrint))) {
685 beforePreProc = state;
686 styler.ColourTo(i - 2, StateToPrint);
687 if ((chNext == '-') && (chNext2 == '-')) {
688 state = SCE_H_COMMENT; // wait for a pending command
689 }
690 else if (isWordCdata(i + 1, i + 7, styler)) {
691 state = SCE_H_CDATA;
692 } else {
693 styler.ColourTo(i, SCE_H_SGML_DEFAULT); // <! is default
694 scriptLanguage = eScriptSGML;
695 state = SCE_H_SGML_COMMAND; // wait for a pending command
696 }
697 // fold whole tag (-- when closing the tag)
698 if (foldHTMLPreprocessor)
699 levelCurrent++;
700 continue;
701 }
702
703 // handle the end of a pre-processor = Non-HTML
704 else if ((
705 ((inScriptType == eNonHtmlPreProc)
706 || (inScriptType == eNonHtmlScriptPreProc)) && (
707 ((scriptLanguage == eScriptPHP) && (ch == '?') && !isPHPStringState(state) && (state != SCE_HPHP_COMMENT)) ||
708 ((scriptLanguage != eScriptNone) && !isStringState(state) &&
709 (ch == '%'))
710 ) && (chNext == '>')) ||
711 ((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) {
712 if (state == SCE_H_ASPAT) {
713 aspScript = segIsScriptingIndicator(styler,
714 styler.GetStartSegment(), i - 1, aspScript);
715 }
716 // Bounce out of any ASP mode
717 switch (state) {
718 case SCE_HJ_WORD:
719 classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
720 break;
721 case SCE_HB_WORD:
722 classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
723 break;
724 case SCE_HP_WORD:
725 classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType);
726 break;
727 case SCE_HPHP_WORD:
728 classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
729 break;
730 case SCE_H_XCCOMMENT:
731 styler.ColourTo(i - 1, state);
732 break;
733 default :
734 styler.ColourTo(i - 1, StateToPrint);
735 break;
736 }
737 if (scriptLanguage != eScriptSGML) {
738 i++;
739 visibleChars++;
740 }
741 if (ch == '%')
742 styler.ColourTo(i, SCE_H_ASP);
743 else if (scriptLanguage == eScriptXML)
744 styler.ColourTo(i, SCE_H_XMLEND);
745 else if (scriptLanguage == eScriptSGML)
746 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
747 else
748 styler.ColourTo(i, SCE_H_QUESTION);
749 state = beforePreProc;
750 if (inScriptType == eNonHtmlScriptPreProc)
751 inScriptType = eNonHtmlScript;
752 else
753 inScriptType = eHtml;
754 scriptLanguage = eScriptNone;
755 // unfold all scripting languages
756 if (foldHTMLPreprocessor)
757 levelCurrent--;
758 continue;
759 }
760 /////////////////////////////////////
761
762 switch (state) {
763 case SCE_H_DEFAULT:
764 if (ch == '<') {
765 // in HTML, fold on tag open and unfold on tag close
766 tagOpened = true;
767 tagClosing = (chNext == '/');
768 styler.ColourTo(i - 1, StateToPrint);
769 if (chNext != '!')
770 state = SCE_H_TAGUNKNOWN;
771 } else if (ch == '&') {
772 styler.ColourTo(i - 1, SCE_H_DEFAULT);
773 state = SCE_H_ENTITY;
774 }
775 break;
776 case SCE_H_SGML_DEFAULT:
777 case SCE_H_SGML_BLOCK_DEFAULT:
778 // if (scriptLanguage == eScriptSGMLblock)
779 // StateToPrint = SCE_H_SGML_BLOCK_DEFAULT;
780
781 if (ch == '\"') {
782 styler.ColourTo(i - 1, StateToPrint);
783 state = SCE_H_SGML_DOUBLESTRING;
784 } else if (ch == '\'') {
785 styler.ColourTo(i - 1, StateToPrint);
786 state = SCE_H_SGML_SIMPLESTRING;
787 } else if ((ch == '-') && (chPrev == '-')) {
788 styler.ColourTo(i - 2, StateToPrint);
789 state = SCE_H_SGML_COMMENT;
790 } else if (isalpha(ch) && (chPrev == '%')) {
791 styler.ColourTo(i - 2, StateToPrint);
792 state = SCE_H_SGML_ENTITY;
793 } else if (ch == '#') {
794 styler.ColourTo(i - 1, StateToPrint);
795 state = SCE_H_SGML_SPECIAL;
796 } else if (ch == '[') {
797 styler.ColourTo(i - 1, StateToPrint);
798 scriptLanguage = eScriptSGMLblock;
799 state = SCE_H_SGML_BLOCK_DEFAULT;
800 } else if (ch == ']') {
801 if (scriptLanguage == eScriptSGMLblock) {
802 styler.ColourTo(i, StateToPrint);
803 scriptLanguage = eScriptSGML;
804 } else {
805 styler.ColourTo(i - 1, StateToPrint);
806 styler.ColourTo(i, SCE_H_SGML_ERROR);
807 }
808 state = SCE_H_SGML_DEFAULT;
809 } else if (scriptLanguage == eScriptSGMLblock) {
810 if ((ch == '!') && (chPrev == '<')) {
811 styler.ColourTo(i - 2, StateToPrint);
812 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
813 state = SCE_H_SGML_COMMAND;
814 } else if (ch == '>') {
815 styler.ColourTo(i - 1, StateToPrint);
816 styler.ColourTo(i, SCE_H_SGML_DEFAULT);
817 }
818 }
819 break;
820 case SCE_H_SGML_COMMAND:
821 if ((ch == '-') && (chPrev == '-')) {
822 styler.ColourTo(i - 2, StateToPrint);
823 state = SCE_H_SGML_COMMENT;
824 } else if (!issgmlwordchar(ch)) {
825 if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) {
826 styler.ColourTo(i - 1, StateToPrint);
827 state = SCE_H_SGML_1ST_PARAM;
828 } else {
829 state = SCE_H_SGML_ERROR;
830 }
831 }
832 break;
833 case SCE_H_SGML_1ST_PARAM:
834 // wait for the beginning of the word
835 if ((ch == '-') && (chPrev == '-')) {
836 if (scriptLanguage == eScriptSGMLblock) {
837 styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT);
838 } else {
839 styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT);
840 }
841 state = SCE_H_SGML_1ST_PARAM_COMMENT;
842 } else if (issgmlwordchar(ch)) {
843 if (scriptLanguage == eScriptSGMLblock) {
844 styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT);
845 } else {
846 styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT);
847 }
848 // find the length of the word
849 int size = 1;
850 while (ishtmlwordchar(styler.SafeGetCharAt(i + size)))
851 size++;
852 styler.ColourTo(i + size - 1, StateToPrint);
853 i += size - 1;
854 visibleChars += size - 1;
855 ch = styler.SafeGetCharAt(i);
856 if (scriptLanguage == eScriptSGMLblock) {
857 state = SCE_H_SGML_BLOCK_DEFAULT;
858 } else {
859 state = SCE_H_SGML_DEFAULT;
860 }
861 continue;
862 }
863 break;
864 case SCE_H_SGML_ERROR:
865 if ((ch == '-') && (chPrev == '-')) {
866 styler.ColourTo(i - 2, StateToPrint);
867 state = SCE_H_SGML_COMMENT;
868 }
869 case SCE_H_SGML_DOUBLESTRING:
870 if (ch == '\"') {
871 styler.ColourTo(i, StateToPrint);
872 state = SCE_H_SGML_DEFAULT;
873 }
874 break;
875 case SCE_H_SGML_SIMPLESTRING:
876 if (ch == '\'') {
877 styler.ColourTo(i, StateToPrint);
878 state = SCE_H_SGML_DEFAULT;
879 }
880 break;
881 case SCE_H_SGML_COMMENT:
882 if ((ch == '-') && (chPrev == '-')) {
883 styler.ColourTo(i, StateToPrint);
884 state = SCE_H_SGML_DEFAULT;
885 }
886 break;
887 case SCE_H_CDATA:
888 if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) {
889 styler.ColourTo(i, StateToPrint);
890 state = SCE_H_DEFAULT;
891 levelCurrent--;
892 }
893 break;
894 case SCE_H_COMMENT:
895 if ((chPrev2 == '-') && (chPrev == '-') && (ch == '>')) {
896 styler.ColourTo(i, StateToPrint);
897 state = SCE_H_DEFAULT;
898 levelCurrent--;
899 }
900 break;
901 case SCE_H_SGML_1ST_PARAM_COMMENT:
902 if ((ch == '-') && (chPrev == '-')) {
903 styler.ColourTo(i, SCE_H_SGML_COMMENT);
904 state = SCE_H_SGML_1ST_PARAM;
905 }
906 break;
907 case SCE_H_SGML_SPECIAL:
908 if (!isupper(ch)) {
909 styler.ColourTo(i - 1, StateToPrint);
910 if (isalnum(ch)) {
911 state = SCE_H_SGML_ERROR;
912 } else {
913 state = SCE_H_SGML_DEFAULT;
914 }
915 }
916 break;
917 case SCE_H_SGML_ENTITY:
918 if (ch == ';') {
919 styler.ColourTo(i, StateToPrint);
920 state = SCE_H_SGML_DEFAULT;
921 } else if (!isalnum(ch) && ch != '-' && ch != '.') {
922 styler.ColourTo(i, SCE_H_SGML_ERROR);
923 state = SCE_H_SGML_DEFAULT;
924 }
925 break;
926 case SCE_H_ENTITY:
927 if (ch == ';') {
928 styler.ColourTo(i, StateToPrint);
929 state = SCE_H_DEFAULT;
930 }
931 if (ch != '#' && !isalnum(ch)) { // Should check that '#' follows '&', but it is unlikely anyway...
932 styler.ColourTo(i, SCE_H_TAGUNKNOWN);
933 state = SCE_H_DEFAULT;
934 }
935 break;
936 case SCE_H_TAGUNKNOWN:
937 if (!ishtmlwordchar(ch) && !((ch == '/') && (chPrev == '<')) && ch != '[') {
938 int eClass = classifyTagHTML(styler.GetStartSegment(),
939 i - 1, keywords, styler, tagDontFold, caseSensitive);
940 if (eClass == SCE_H_SCRIPT) {
941 if (!tagClosing) {
942 inScriptType = eNonHtmlScript;
943 scriptLanguage = clientScript;
944 eClass = SCE_H_TAG;
945 } else {
946 scriptLanguage = eScriptNone;
947 eClass = SCE_H_TAG;
948 }
949 }
950 if (ch == '>') {
951 styler.ColourTo(i, eClass);
952 if (inScriptType == eNonHtmlScript) {
953 state = StateForScript(scriptLanguage);
954 } else {
955 state = SCE_H_DEFAULT;
956 }
957 tagOpened = false;
958 if (!tagDontFold){
959 if (tagClosing) {
960 levelCurrent--;
961 } else {
962 levelCurrent++;
963 }
964 }
965 tagClosing = false;
966 } else if (ch == '/' && chNext == '>') {
967 if (eClass == SCE_H_TAGUNKNOWN) {
968 styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN);
969 } else {
970 styler.ColourTo(i - 1, StateToPrint);
971 styler.ColourTo(i + 1, SCE_H_TAGEND);
972 }
973 i++;
974 ch = chNext;
975 state = SCE_H_DEFAULT;
976 tagOpened = false;
977 } else {
978 if (eClass != SCE_H_TAGUNKNOWN) {
979 if (eClass == SCE_H_SGML_DEFAULT) {
980 state = SCE_H_SGML_DEFAULT;
981 } else {
982 state = SCE_H_OTHER;
983 }
984 }
985 }
986 }
987 break;
988 case SCE_H_ATTRIBUTE:
989 if (!ishtmlwordchar(ch) && ch != '/' && ch != '-') {
990 if (inScriptType == eNonHtmlScript) {
991 int scriptLanguagePrev = scriptLanguage;
992 clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage);
993 scriptLanguage = clientScript;
994 if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone))
995 inScriptType = eHtml;
996 }
997 classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler);
998 if (ch == '>') {
999 styler.ColourTo(i, SCE_H_TAG);
1000 if (inScriptType == eNonHtmlScript) {
1001 state = StateForScript(scriptLanguage);
1002 } else {
1003 state = SCE_H_DEFAULT;
1004 }
1005 tagOpened = false;
1006 if (!tagDontFold){
1007 if (tagClosing){
1008 levelCurrent--;
1009 } else {
1010 levelCurrent++;
1011 }
1012 }
1013 tagClosing = false;
1014 } else if (ch == '=') {
1015 styler.ColourTo(i, SCE_H_OTHER);
1016 state = SCE_H_VALUE;
1017 } else {
1018 state = SCE_H_OTHER;
1019 }
1020 }
1021 break;
1022 case SCE_H_OTHER:
1023 if (ch == '>') {
1024 styler.ColourTo(i - 1, StateToPrint);
1025 styler.ColourTo(i, SCE_H_TAG);
1026 if (inScriptType == eNonHtmlScript) {
1027 state = StateForScript(scriptLanguage);
1028 } else {
1029 state = SCE_H_DEFAULT;
1030 }
1031 tagOpened = false;
1032 if (!tagDontFold){
1033 if (tagClosing){
1034 levelCurrent--;
1035 } else {
1036 levelCurrent++;
1037 }
1038 }
1039 tagClosing = false;
1040 } else if (ch == '\"') {
1041 styler.ColourTo(i - 1, StateToPrint);
1042 state = SCE_H_DOUBLESTRING;
1043 } else if (ch == '\'') {
1044 styler.ColourTo(i - 1, StateToPrint);
1045 state = SCE_H_SINGLESTRING;
1046 } else if (ch == '=') {
1047 styler.ColourTo(i, StateToPrint);
1048 state = SCE_H_VALUE;
1049 } else if (ch == '/' && chNext == '>') {
1050 styler.ColourTo(i - 1, StateToPrint);
1051 styler.ColourTo(i + 1, SCE_H_TAGEND);
1052 i++;
1053 ch = chNext;
1054 state = SCE_H_DEFAULT;
1055 tagOpened = false;
1056 } else if (ch == '?' && chNext == '>') {
1057 styler.ColourTo(i - 1, StateToPrint);
1058 styler.ColourTo(i + 1, SCE_H_XMLEND);
1059 i++;
1060 ch = chNext;
1061 state = SCE_H_DEFAULT;
1062 } else if (ishtmlwordchar(ch)) {
1063 styler.ColourTo(i - 1, StateToPrint);
1064 state = SCE_H_ATTRIBUTE;
1065 }
1066 break;
1067 case SCE_H_DOUBLESTRING:
1068 if (ch == '\"') {
1069 if (inScriptType == eNonHtmlScript) {
1070 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
1071 }
1072 styler.ColourTo(i, SCE_H_DOUBLESTRING);
1073 state = SCE_H_OTHER;
1074 }
1075 break;
1076 case SCE_H_SINGLESTRING:
1077 if (ch == '\'') {
1078 if (inScriptType == eNonHtmlScript) {
1079 scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
1080 }
1081 styler.ColourTo(i, SCE_H_SINGLESTRING);
1082 state = SCE_H_OTHER;
1083 }
1084 break;
1085 case SCE_H_VALUE:
1086 if (!ishtmlwordchar(ch)) {
1087 if (ch == '\"' && chPrev == '=') {
1088 // Should really test for being first character
1089 state = SCE_H_DOUBLESTRING;
1090 } else if (ch == '\'' && chPrev == '=') {
1091 state = SCE_H_SINGLESTRING;
1092 } else {
1093 if (IsNumber(styler.GetStartSegment(), styler)) {
1094 styler.ColourTo(i - 1, SCE_H_NUMBER);
1095 } else {
1096 styler.ColourTo(i - 1, StateToPrint);
1097 }
1098 if (ch == '>') {
1099 styler.ColourTo(i, SCE_H_TAG);
1100 if (inScriptType == eNonHtmlScript) {
1101 state = StateForScript(scriptLanguage);
1102 } else {
1103 state = SCE_H_DEFAULT;
1104 }
1105 tagOpened = false;
1106 if (!tagDontFold){
1107 if (tagClosing){
1108 levelCurrent--;
1109 } else {
1110 levelCurrent++;
1111 }
1112 }
1113 tagClosing = false;
1114 } else {
1115 state = SCE_H_OTHER;
1116 }
1117 }
1118 }
1119 break;
1120 case SCE_HJ_DEFAULT:
1121 case SCE_HJ_START:
1122 case SCE_HJ_SYMBOLS:
1123 if (iswordstart(ch)) {
1124 styler.ColourTo(i - 1, StateToPrint);
1125 state = SCE_HJ_WORD;
1126 } else if (ch == '/' && chNext == '*') {
1127 styler.ColourTo(i - 1, StateToPrint);
1128 if (chNext2 == '*')
1129 state = SCE_HJ_COMMENTDOC;
1130 else
1131 state = SCE_HJ_COMMENT;
1132 } else if (ch == '/' && chNext == '/') {
1133 styler.ColourTo(i - 1, StateToPrint);
1134 state = SCE_HJ_COMMENTLINE;
1135 } else if (ch == '/' && isOKBeforeRE(chPrevNonWhite)) {
1136 styler.ColourTo(i - 1, StateToPrint);
1137 state = SCE_HJ_REGEX;
1138 } else if (ch == '\"') {
1139 styler.ColourTo(i - 1, StateToPrint);
1140 state = SCE_HJ_DOUBLESTRING;
1141 } else if (ch == '\'') {
1142 styler.ColourTo(i - 1, StateToPrint);
1143 state = SCE_HJ_SINGLESTRING;
1144 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1145 styler.SafeGetCharAt(i + 3) == '-') {
1146 styler.ColourTo(i - 1, StateToPrint);
1147 state = SCE_HJ_COMMENTLINE;
1148 } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1149 styler.ColourTo(i - 1, StateToPrint);
1150 state = SCE_HJ_COMMENTLINE;
1151 i += 2;
1152 } else if (isoperator(ch)) {
1153 styler.ColourTo(i - 1, StateToPrint);
1154 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1155 state = SCE_HJ_DEFAULT;
1156 } else if ((ch == ' ') || (ch == '\t')) {
1157 if (state == SCE_HJ_START) {
1158 styler.ColourTo(i - 1, StateToPrint);
1159 state = SCE_HJ_DEFAULT;
1160 }
1161 }
1162 break;
1163 case SCE_HJ_WORD:
1164 if (!iswordchar(ch)) {
1165 classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
1166 //styler.ColourTo(i - 1, eHTJSKeyword);
1167 state = SCE_HJ_DEFAULT;
1168 if (ch == '/' && chNext == '*') {
1169 if (chNext2 == '*')
1170 state = SCE_HJ_COMMENTDOC;
1171 else
1172 state = SCE_HJ_COMMENT;
1173 } else if (ch == '/' && chNext == '/') {
1174 state = SCE_HJ_COMMENTLINE;
1175 } else if (ch == '\"') {
1176 state = SCE_HJ_DOUBLESTRING;
1177 } else if (ch == '\'') {
1178 state = SCE_HJ_SINGLESTRING;
1179 } else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1180 styler.ColourTo(i - 1, StateToPrint);
1181 state = SCE_HJ_COMMENTLINE;
1182 i += 2;
1183 } else if (isoperator(ch)) {
1184 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1185 state = SCE_HJ_DEFAULT;
1186 }
1187 }
1188 break;
1189 case SCE_HJ_COMMENT:
1190 case SCE_HJ_COMMENTDOC:
1191 if (ch == '/' && chPrev == '*') {
1192 styler.ColourTo(i, StateToPrint);
1193 state = SCE_HJ_DEFAULT;
1194 }
1195 break;
1196 case SCE_HJ_COMMENTLINE:
1197 if (ch == '\r' || ch == '\n') {
1198 styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType));
1199 state = SCE_HJ_DEFAULT;
1200 }
1201 break;
1202 case SCE_HJ_DOUBLESTRING:
1203 if (ch == '\\') {
1204 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1205 i++;
1206 }
1207 } else if (ch == '\"') {
1208 styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType));
1209 state = SCE_HJ_DEFAULT;
1210 } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1211 styler.ColourTo(i - 1, StateToPrint);
1212 state = SCE_HJ_COMMENTLINE;
1213 i += 2;
1214 } else if (isLineEnd(ch)) {
1215 styler.ColourTo(i - 1, StateToPrint);
1216 state = SCE_HJ_STRINGEOL;
1217 }
1218 break;
1219 case SCE_HJ_SINGLESTRING:
1220 if (ch == '\\') {
1221 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1222 i++;
1223 }
1224 } else if (ch == '\'') {
1225 styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType));
1226 state = SCE_HJ_DEFAULT;
1227 } else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
1228 styler.ColourTo(i - 1, StateToPrint);
1229 state = SCE_HJ_COMMENTLINE;
1230 i += 2;
1231 } else if (isLineEnd(ch)) {
1232 styler.ColourTo(i - 1, StateToPrint);
1233 state = SCE_HJ_STRINGEOL;
1234 }
1235 break;
1236 case SCE_HJ_STRINGEOL:
1237 if (!isLineEnd(ch)) {
1238 styler.ColourTo(i - 1, StateToPrint);
1239 state = SCE_HJ_DEFAULT;
1240 } else if (!isLineEnd(chNext)) {
1241 styler.ColourTo(i, StateToPrint);
1242 state = SCE_HJ_DEFAULT;
1243 }
1244 break;
1245 case SCE_HJ_REGEX:
1246 if (ch == '\r' || ch == '\n' || ch == '/') {
1247 styler.ColourTo(i, StateToPrint);
1248 state = SCE_HJ_DEFAULT;
1249 } else if (ch == '\\') {
1250 // Gobble up the quoted character
1251 if (chNext == '\\' || chNext == '/') {
1252 i++;
1253 ch = chNext;
1254 chNext = styler.SafeGetCharAt(i + 1);
1255 }
1256 }
1257 break;
1258 case SCE_HB_DEFAULT:
1259 case SCE_HB_START:
1260 if (iswordstart(ch)) {
1261 styler.ColourTo(i - 1, StateToPrint);
1262 state = SCE_HB_WORD;
1263 } else if (ch == '\'') {
1264 styler.ColourTo(i - 1, StateToPrint);
1265 state = SCE_HB_COMMENTLINE;
1266 } else if (ch == '\"') {
1267 styler.ColourTo(i - 1, StateToPrint);
1268 state = SCE_HB_STRING;
1269 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1270 styler.SafeGetCharAt(i + 3) == '-') {
1271 styler.ColourTo(i - 1, StateToPrint);
1272 state = SCE_HB_COMMENTLINE;
1273 } else if (isoperator(ch)) {
1274 styler.ColourTo(i - 1, StateToPrint);
1275 styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
1276 state = SCE_HB_DEFAULT;
1277 } else if ((ch == ' ') || (ch == '\t')) {
1278 if (state == SCE_HB_START) {
1279 styler.ColourTo(i - 1, StateToPrint);
1280 state = SCE_HB_DEFAULT;
1281 }
1282 }
1283 break;
1284 case SCE_HB_WORD:
1285 if (!iswordchar(ch)) {
1286 state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
1287 if (state == SCE_HB_DEFAULT) {
1288 if (ch == '\"') {
1289 state = SCE_HB_STRING;
1290 } else if (ch == '\'') {
1291 state = SCE_HB_COMMENTLINE;
1292 } else if (isoperator(ch)) {
1293 styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
1294 state = SCE_HB_DEFAULT;
1295 }
1296 }
1297 }
1298 break;
1299 case SCE_HB_STRING:
1300 if (ch == '\"') {
1301 styler.ColourTo(i, StateToPrint);
1302 state = SCE_HB_DEFAULT;
1303 } else if (ch == '\r' || ch == '\n') {
1304 styler.ColourTo(i - 1, StateToPrint);
1305 state = SCE_HB_STRINGEOL;
1306 }
1307 break;
1308 case SCE_HB_COMMENTLINE:
1309 if (ch == '\r' || ch == '\n') {
1310 styler.ColourTo(i - 1, StateToPrint);
1311 state = SCE_HB_DEFAULT;
1312 }
1313 break;
1314 case SCE_HB_STRINGEOL:
1315 if (!isLineEnd(ch)) {
1316 styler.ColourTo(i - 1, StateToPrint);
1317 state = SCE_HB_DEFAULT;
1318 } else if (!isLineEnd(chNext)) {
1319 styler.ColourTo(i, StateToPrint);
1320 state = SCE_HB_DEFAULT;
1321 }
1322 break;
1323 case SCE_HP_DEFAULT:
1324 case SCE_HP_START:
1325 if (iswordstart(ch)) {
1326 styler.ColourTo(i - 1, StateToPrint);
1327 state = SCE_HP_WORD;
1328 } else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
1329 styler.SafeGetCharAt(i + 3) == '-') {
1330 styler.ColourTo(i - 1, StateToPrint);
1331 state = SCE_HP_COMMENTLINE;
1332 } else if (ch == '#') {
1333 styler.ColourTo(i - 1, StateToPrint);
1334 state = SCE_HP_COMMENTLINE;
1335 } else if (ch == '\"') {
1336 styler.ColourTo(i - 1, StateToPrint);
1337 if (chNext == '\"' && chNext2 == '\"') {
1338 i += 2;
1339 state = SCE_HP_TRIPLEDOUBLE;
1340 ch = ' ';
1341 chPrev = ' ';
1342 chNext = styler.SafeGetCharAt(i + 1);
1343 } else {
1344 // state = statePrintForState(SCE_HP_STRING,inScriptType);
1345 state = SCE_HP_STRING;
1346 }
1347 } else if (ch == '\'') {
1348 styler.ColourTo(i - 1, StateToPrint);
1349 if (chNext == '\'' && chNext2 == '\'') {
1350 i += 2;
1351 state = SCE_HP_TRIPLE;
1352 ch = ' ';
1353 chPrev = ' ';
1354 chNext = styler.SafeGetCharAt(i + 1);
1355 } else {
1356 state = SCE_HP_CHARACTER;
1357 }
1358 } else if (isoperator(ch)) {
1359 styler.ColourTo(i - 1, StateToPrint);
1360 styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
1361 } else if ((ch == ' ') || (ch == '\t')) {
1362 if (state == SCE_HP_START) {
1363 styler.ColourTo(i - 1, StateToPrint);
1364 state = SCE_HP_DEFAULT;
1365 }
1366 }
1367 break;
1368 case SCE_HP_WORD:
1369 if (!iswordchar(ch)) {
1370 classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType);
1371 state = SCE_HP_DEFAULT;
1372 if (ch == '#') {
1373 state = SCE_HP_COMMENTLINE;
1374 } else if (ch == '\"') {
1375 if (chNext == '\"' && chNext2 == '\"') {
1376 i += 2;
1377 state = SCE_HP_TRIPLEDOUBLE;
1378 ch = ' ';
1379 chPrev = ' ';
1380 chNext = styler.SafeGetCharAt(i + 1);
1381 } else {
1382 state = SCE_HP_STRING;
1383 }
1384 } else if (ch == '\'') {
1385 if (chNext == '\'' && chNext2 == '\'') {
1386 i += 2;
1387 state = SCE_HP_TRIPLE;
1388 ch = ' ';
1389 chPrev = ' ';
1390 chNext = styler.SafeGetCharAt(i + 1);
1391 } else {
1392 state = SCE_HP_CHARACTER;
1393 }
1394 } else if (isoperator(ch)) {
1395 styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
1396 }
1397 }
1398 break;
1399 case SCE_HP_COMMENTLINE:
1400 if (ch == '\r' || ch == '\n') {
1401 styler.ColourTo(i - 1, StateToPrint);
1402 state = SCE_HP_DEFAULT;
1403 }
1404 break;
1405 case SCE_HP_STRING:
1406 if (ch == '\\') {
1407 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1408 i++;
1409 ch = chNext;
1410 chNext = styler.SafeGetCharAt(i + 1);
1411 }
1412 } else if (ch == '\"') {
1413 styler.ColourTo(i, StateToPrint);
1414 state = SCE_HP_DEFAULT;
1415 }
1416 break;
1417 case SCE_HP_CHARACTER:
1418 if (ch == '\\') {
1419 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
1420 i++;
1421 ch = chNext;
1422 chNext = styler.SafeGetCharAt(i + 1);
1423 }
1424 } else if (ch == '\'') {
1425 styler.ColourTo(i, StateToPrint);
1426 state = SCE_HP_DEFAULT;
1427 }
1428 break;
1429 case SCE_HP_TRIPLE:
1430 if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') {
1431 styler.ColourTo(i, StateToPrint);
1432 state = SCE_HP_DEFAULT;
1433 }
1434 break;
1435 case SCE_HP_TRIPLEDOUBLE:
1436 if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') {
1437 styler.ColourTo(i, StateToPrint);
1438 state = SCE_HP_DEFAULT;
1439 }
1440 break;
1441 ///////////// start - PHP state handling
1442 case SCE_HPHP_WORD:
1443 if (!iswordchar(ch)) {
1444 classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
1445 if (ch == '/' && chNext == '*') {
1446 i++;
1447 state = SCE_HPHP_COMMENT;
1448 } else if (ch == '/' && chNext == '/') {
1449 i++;
1450 state = SCE_HPHP_COMMENTLINE;
1451 } else if (ch == '#') {
1452 state = SCE_HPHP_COMMENTLINE;
1453 } else if (ch == '\"') {
1454 state = SCE_HPHP_HSTRING;
1455 } else if (ch == '\'') {
1456 state = SCE_HPHP_SIMPLESTRING;
1457 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1458 state = SCE_HPHP_VARIABLE;
1459 } else if (isoperator(ch)) {
1460 state = SCE_HPHP_OPERATOR;
1461 } else {
1462 state = SCE_HPHP_DEFAULT;
1463 }
1464 }
1465 break;
1466 case SCE_HPHP_NUMBER:
1467 if (!isdigit(ch)) {
1468 styler.ColourTo(i - 1, SCE_HPHP_NUMBER);
1469 if (isoperator(ch))
1470 state = SCE_HPHP_OPERATOR;
1471 else
1472 state = SCE_HPHP_DEFAULT;
1473 }
1474 break;
1475 case SCE_HPHP_VARIABLE:
1476 if (!IsPhpWordChar(ch)) {
1477 styler.ColourTo(i - 1, SCE_HPHP_VARIABLE);
1478 if (isoperator(ch))
1479 state = SCE_HPHP_OPERATOR;
1480 else
1481 state = SCE_HPHP_DEFAULT;
1482 }
1483 break;
1484 case SCE_HPHP_COMMENT:
1485 if (ch == '/' && chPrev == '*') {
1486 styler.ColourTo(i, StateToPrint);
1487 state = SCE_HPHP_DEFAULT;
1488 }
1489 break;
1490 case SCE_HPHP_COMMENTLINE:
1491 if (ch == '\r' || ch == '\n') {
1492 styler.ColourTo(i - 1, StateToPrint);
1493 state = SCE_HPHP_DEFAULT;
1494 }
1495 break;
1496 case SCE_HPHP_HSTRING:
1497 if (ch == '\\') {
1498 // skip the next char
1499 i++;
1500 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1501 styler.ColourTo(i - 1, StateToPrint);
1502 state = SCE_HPHP_HSTRING_VARIABLE;
1503 } else if (ch == '\"') {
1504 styler.ColourTo(i, StateToPrint);
1505 state = SCE_HPHP_DEFAULT;
1506 }
1507 break;
1508 case SCE_HPHP_SIMPLESTRING:
1509 if (ch == '\\') {
1510 // skip the next char
1511 i++;
1512 } else if (ch == '\'') {
1513 styler.ColourTo(i, StateToPrint);
1514 state = SCE_HPHP_DEFAULT;
1515 }
1516 break;
1517 case SCE_HPHP_HSTRING_VARIABLE:
1518 if (!IsPhpWordChar(ch)) {
1519 styler.ColourTo(i - 1, StateToPrint);
1520 i--; // strange but it works
1521 state = SCE_HPHP_HSTRING;
1522 }
1523 break;
1524 case SCE_HPHP_OPERATOR:
1525 case SCE_HPHP_DEFAULT:
1526 styler.ColourTo(i - 1, StateToPrint);
1527 if (isdigit(ch)) {
1528 state = SCE_HPHP_NUMBER;
1529 } else if (iswordstart(ch)) {
1530 state = SCE_HPHP_WORD;
1531 } else if (ch == '/' && chNext == '*') {
1532 i++;
1533 state = SCE_HPHP_COMMENT;
1534 } else if (ch == '/' && chNext == '/') {
1535 i++;
1536 state = SCE_HPHP_COMMENTLINE;
1537 } else if (ch == '#') {
1538 state = SCE_HPHP_COMMENTLINE;
1539 } else if (ch == '\"') {
1540 state = SCE_HPHP_HSTRING;
1541 } else if (ch == '\'') {
1542 state = SCE_HPHP_SIMPLESTRING;
1543 } else if (ch == '$' && IsPhpWordStart(chNext)) {
1544 state = SCE_HPHP_VARIABLE;
1545 } else if (isoperator(ch)) {
1546 state = SCE_HPHP_OPERATOR;
1547 } else if ((state == SCE_HPHP_OPERATOR) && (isspacechar(ch))) {
1548 state = SCE_HPHP_DEFAULT;
1549 }
1550 break;
1551 ///////////// end - PHP state handling
1552 }
1553
1554 // Some of the above terminated their lexeme but since the same character starts
1555 // the same class again, only reenter if non empty segment.
1556
1557 bool nonEmptySegment = i >= static_cast<int>(styler.GetStartSegment());
1558 if (state == SCE_HB_DEFAULT) { // One of the above succeeded
1559 if ((ch == '\"') && (nonEmptySegment)) {
1560 state = SCE_HB_STRING;
1561 } else if (ch == '\'') {
1562 state = SCE_HB_COMMENTLINE;
1563 } else if (iswordstart(ch)) {
1564 state = SCE_HB_WORD;
1565 } else if (isoperator(ch)) {
1566 styler.ColourTo(i, SCE_HB_DEFAULT);
1567 }
1568 } else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded
1569 if ((ch == '\"') && (nonEmptySegment)) {
1570 state = SCE_HBA_STRING;
1571 } else if (ch == '\'') {
1572 state = SCE_HBA_COMMENTLINE;
1573 } else if (iswordstart(ch)) {
1574 state = SCE_HBA_WORD;
1575 } else if (isoperator(ch)) {
1576 styler.ColourTo(i, SCE_HBA_DEFAULT);
1577 }
1578 } else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded
1579 if (ch == '/' && chNext == '*') {
1580 if (styler.SafeGetCharAt(i + 2) == '*')
1581 state = SCE_HJ_COMMENTDOC;
1582 else
1583 state = SCE_HJ_COMMENT;
1584 } else if (ch == '/' && chNext == '/') {
1585 state = SCE_HJ_COMMENTLINE;
1586 } else if ((ch == '\"') && (nonEmptySegment)) {
1587 state = SCE_HJ_DOUBLESTRING;
1588 } else if ((ch == '\'') && (nonEmptySegment)) {
1589 state = SCE_HJ_SINGLESTRING;
1590 } else if (iswordstart(ch)) {
1591 state = SCE_HJ_WORD;
1592 } else if (isoperator(ch)) {
1593 styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
1594 }
1595 }
1596 }
1597
1598 StateToPrint = statePrintForState(state, inScriptType);
1599 styler.ColourTo(lengthDoc - 1, StateToPrint);
1600
1601 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
1602 if (fold) {
1603 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
1604 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
1605 }
1606 }
1607
1608 static bool isASPScript(int state) {
1609 return
1610 (state >= SCE_HJA_START && state <= SCE_HJA_REGEX) ||
1611 (state >= SCE_HBA_START && state <= SCE_HBA_STRINGEOL) ||
1612 (state >= SCE_HPA_DEFAULT && state <= SCE_HPA_IDENTIFIER);
1613 }
1614
1615 static void ColouriseHBAPiece(StyleContext &sc, WordList *keywordlists[]) {
1616 WordList &keywordsVBS = *keywordlists[2];
1617 if (sc.state == SCE_HBA_WORD) {
1618 if (!IsAWordChar(sc.ch)) {
1619 char s[100];
1620 sc.GetCurrentLowered(s, sizeof(s));
1621 if (keywordsVBS.InList(s)) {
1622 if (strcmp(s, "rem") == 0) {
1623 sc.ChangeState(SCE_HBA_COMMENTLINE);
1624 if (sc.atLineEnd) {
1625 sc.SetState(SCE_HBA_DEFAULT);
1626 }
1627 } else {
1628 sc.SetState(SCE_HBA_DEFAULT);
1629 }
1630 } else {
1631 sc.ChangeState(SCE_HBA_IDENTIFIER);
1632 sc.SetState(SCE_HBA_DEFAULT);
1633 }
1634 }
1635 } else if (sc.state == SCE_HBA_NUMBER) {
1636 if (!IsAWordChar(sc.ch)) {
1637 sc.SetState(SCE_HBA_DEFAULT);
1638 }
1639 } else if (sc.state == SCE_HBA_STRING) {
1640 if (sc.ch == '\"') {
1641 sc.ForwardSetState(SCE_HBA_DEFAULT);
1642 } else if (sc.ch == '\r' || sc.ch == '\n') {
1643 sc.ChangeState(SCE_HBA_STRINGEOL);
1644 sc.ForwardSetState(SCE_HBA_DEFAULT);
1645 }
1646 } else if (sc.state == SCE_HBA_COMMENTLINE) {
1647 if (sc.ch == '\r' || sc.ch == '\n') {
1648 sc.SetState(SCE_HBA_DEFAULT);
1649 }
1650 }
1651
1652 if (sc.state == SCE_HBA_DEFAULT) {
1653 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
1654 sc.SetState(SCE_HBA_NUMBER);
1655 } else if (IsAWordStart(sc.ch)) {
1656 sc.SetState(SCE_HBA_WORD);
1657 } else if (sc.ch == '\'') {
1658 sc.SetState(SCE_HBA_COMMENTLINE);
1659 } else if (sc.ch == '\"') {
1660 sc.SetState(SCE_HBA_STRING);
1661 }
1662 }
1663 }
1664
1665 static void ColouriseHTMLPiece(StyleContext &sc, WordList *keywordlists[]) {
1666 WordList &keywordsTags = *keywordlists[0];
1667 if (sc.state == SCE_H_COMMENT) {
1668 if (sc.Match("-->")) {
1669 sc.Forward();
1670 sc.Forward();
1671 sc.ForwardSetState(SCE_H_DEFAULT);
1672 }
1673 } else if (sc.state == SCE_H_ENTITY) {
1674 if (sc.ch == ';') {
1675 sc.ForwardSetState(SCE_H_DEFAULT);
1676 } else if (sc.ch != '#' && (sc.ch < 0x80) && !isalnum(sc.ch)) { // Should check that '#' follows '&', but it is unlikely anyway...
1677 sc.ChangeState(SCE_H_TAGUNKNOWN);
1678 sc.SetState(SCE_H_DEFAULT);
1679 }
1680 } else if (sc.state == SCE_H_TAGUNKNOWN) {
1681 if (!ishtmlwordchar(static_cast<char>(sc.ch)) && !((sc.ch == '/') && (sc.chPrev == '<')) && sc.ch != '[') {
1682 char s[100];
1683 sc.GetCurrentLowered(s, sizeof(s));
1684 if (s[1] == '/') {
1685 if (keywordsTags.InList(s + 2)) {
1686 sc.ChangeState(SCE_H_TAG);
1687 }
1688 } else {
1689 if (keywordsTags.InList(s + 1)) {
1690 sc.ChangeState(SCE_H_TAG);
1691 }
1692 }
1693 if (sc.ch == '>') {
1694 sc.ForwardSetState(SCE_H_DEFAULT);
1695 } else if (sc.Match('/', '>')) {
1696 sc.SetState(SCE_H_TAGEND);
1697 sc.Forward();
1698 sc.ForwardSetState(SCE_H_DEFAULT);
1699 } else {
1700 sc.SetState(SCE_H_OTHER);
1701 }
1702 }
1703 } else if (sc.state == SCE_H_ATTRIBUTE) {
1704 if (!ishtmlwordchar(static_cast<char>(sc.ch))) {
1705 char s[100];
1706 sc.GetCurrentLowered(s, sizeof(s));
1707 if (!keywordsTags.InList(s)) {
1708 sc.ChangeState(SCE_H_ATTRIBUTEUNKNOWN);
1709 }
1710 sc.SetState(SCE_H_OTHER);
1711 }
1712 } else if (sc.state == SCE_H_OTHER) {
1713 if (sc.ch == '>') {
1714 sc.SetState(SCE_H_TAG);
1715 sc.ForwardSetState(SCE_H_DEFAULT);
1716 } else if (sc.Match('/', '>')) {
1717 sc.SetState(SCE_H_TAG);
1718 sc.Forward();
1719 sc.ForwardSetState(SCE_H_DEFAULT);
1720 } else if (sc.chPrev == '=') {
1721 sc.SetState(SCE_H_VALUE);
1722 }
1723 } else if (sc.state == SCE_H_DOUBLESTRING) {
1724 if (sc.ch == '\"') {
1725 sc.ForwardSetState(SCE_H_OTHER);
1726 }
1727 } else if (sc.state == SCE_H_SINGLESTRING) {
1728 if (sc.ch == '\'') {
1729 sc.ForwardSetState(SCE_H_OTHER);
1730 }
1731 } else if (sc.state == SCE_H_NUMBER) {
1732 if (!IsADigit(sc.ch)) {
1733 sc.SetState(SCE_H_OTHER);
1734 }
1735 }
1736
1737 if (sc.state == SCE_H_DEFAULT) {
1738 if (sc.ch == '<') {
1739 if (sc.Match("<!--"))
1740 sc.SetState(SCE_H_COMMENT);
1741 else
1742 sc.SetState(SCE_H_TAGUNKNOWN);
1743 } else if (sc.ch == '&') {
1744 sc.SetState(SCE_H_ENTITY);
1745 }
1746 } else if ((sc.state == SCE_H_OTHER) || (sc.state == SCE_H_VALUE)) {
1747 if (sc.ch == '\"' && sc.chPrev == '=') {
1748 sc.SetState(SCE_H_DOUBLESTRING);
1749 } else if (sc.ch == '\'' && sc.chPrev == '=') {
1750 sc.SetState(SCE_H_SINGLESTRING);
1751 } else if (IsADigit(sc.ch)) {
1752 sc.SetState(SCE_H_NUMBER);
1753 } else if (sc.ch == '>') {
1754 sc.SetState(SCE_H_TAG);
1755 sc.ForwardSetState(SCE_H_DEFAULT);
1756 } else if (ishtmlwordchar(static_cast<char>(sc.ch))) {
1757 sc.SetState(SCE_H_ATTRIBUTE);
1758 }
1759 }
1760 }
1761
1762 static void ColouriseASPPiece(StyleContext &sc, WordList *keywordlists[]) {
1763 // Possibly exit current state to either SCE_H_DEFAULT or SCE_HBA_DEFAULT
1764 if ((sc.state == SCE_H_ASPAT || isASPScript(sc.state)) && sc.Match('%', '>')) {
1765 sc.SetState(SCE_H_ASP);
1766 sc.Forward();
1767 sc.ForwardSetState(SCE_H_DEFAULT);
1768 }
1769
1770 // Handle some ASP script
1771 if (sc.state >= SCE_HBA_START && sc.state <= SCE_HBA_STRINGEOL) {
1772 ColouriseHBAPiece(sc, keywordlists);
1773 } else if (sc.state >= SCE_H_DEFAULT && sc.state <= SCE_H_SGML_BLOCK_DEFAULT) {
1774 ColouriseHTMLPiece(sc, keywordlists);
1775 }
1776
1777 // Enter new sc.state
1778 if ((sc.state == SCE_H_DEFAULT) || (sc.state == SCE_H_TAGUNKNOWN)) {
1779 if (sc.Match('<', '%')) {
1780 if (sc.state == SCE_H_TAGUNKNOWN)
1781 sc.ChangeState(SCE_H_ASP);
1782 else
1783 sc.SetState(SCE_H_ASP);
1784 sc.Forward();
1785 sc.Forward();
1786 if (sc.ch == '@') {
1787 sc.ForwardSetState(SCE_H_ASPAT);
1788 } else {
1789 if (sc.ch == '=') {
1790 sc.Forward();
1791 }
1792 sc.SetState(SCE_HBA_DEFAULT);
1793 }
1794 }
1795 }
1796 }
1797
1798 static void ColouriseASPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
1799 Accessor &styler) {
1800 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
1801 StyleContext sc(startPos, length, initStyle, styler, 0x7f);
1802 for (; sc.More(); sc.Forward()) {
1803 ColouriseASPPiece(sc, keywordlists);
1804 }
1805 sc.Complete();
1806 }
1807
1808 static void ColourisePHPPiece(StyleContext &sc, WordList *keywordlists[]) {
1809 // Possibly exit current state to either SCE_H_DEFAULT or SCE_HBA_DEFAULT
1810 if (sc.state >= SCE_HPHP_DEFAULT && sc.state <= SCE_HPHP_OPERATOR) {
1811 if (!isPHPStringState(sc.state) &&
1812 (sc.state != SCE_HPHP_COMMENT) &&
1813 (sc.Match('?', '>'))) {
1814 sc.SetState(SCE_H_QUESTION);
1815 sc.Forward();
1816 sc.ForwardSetState(SCE_H_DEFAULT);
1817 }
1818 }
1819
1820 if (sc.state >= SCE_H_DEFAULT && sc.state <= SCE_H_SGML_BLOCK_DEFAULT) {
1821 ColouriseHTMLPiece(sc, keywordlists);
1822 }
1823
1824 // Handle some PHP script
1825 if (sc.state == SCE_HPHP_WORD) {
1826 if (!IsPhpWordChar(static_cast<char>(sc.ch))) {
1827 sc.SetState(SCE_HPHP_DEFAULT);
1828 }
1829 } else if (sc.state == SCE_HPHP_COMMENTLINE) {
1830 if (sc.ch == '\r' || sc.ch == '\n') {
1831 sc.SetState(SCE_HPHP_DEFAULT);
1832 }
1833 } else if (sc.state == SCE_HPHP_COMMENT) {
1834 if (sc.Match('*', '/')) {
1835 sc.Forward();
1836 sc.Forward();
1837 sc.SetState(SCE_HPHP_DEFAULT);
1838 }
1839 } else if (sc.state == SCE_HPHP_HSTRING) {
1840 if (sc.ch == '\"') {
1841 sc.ForwardSetState(SCE_HPHP_DEFAULT);
1842 }
1843 } else if (sc.state == SCE_HPHP_SIMPLESTRING) {
1844 if (sc.ch == '\'') {
1845 sc.ForwardSetState(SCE_HPHP_DEFAULT);
1846 }
1847 } else if (sc.state == SCE_HPHP_VARIABLE) {
1848 if (!IsPhpWordChar(static_cast<char>(sc.ch))) {
1849 sc.SetState(SCE_HPHP_DEFAULT);
1850 }
1851 } else if (sc.state == SCE_HPHP_OPERATOR) {
1852 sc.SetState(SCE_HPHP_DEFAULT);
1853 }
1854
1855 // Enter new sc.state
1856 if ((sc.state == SCE_H_DEFAULT) || (sc.state == SCE_H_TAGUNKNOWN)) {
1857 if (sc.Match("<?php")) {
1858 sc.SetState(SCE_H_QUESTION);
1859 sc.Forward();
1860 sc.Forward();
1861 sc.Forward();
1862 sc.Forward();
1863 sc.Forward();
1864 sc.SetState(SCE_HPHP_DEFAULT);
1865 }
1866 }
1867 if (sc.state == SCE_HPHP_DEFAULT) {
1868 if (IsPhpWordStart(static_cast<char>(sc.ch))) {
1869 sc.SetState(SCE_HPHP_WORD);
1870 } else if (sc.ch == '#') {
1871 sc.SetState(SCE_HPHP_COMMENTLINE);
1872 } else if (sc.Match("<!--")) {
1873 sc.SetState(SCE_HPHP_COMMENTLINE);
1874 } else if (sc.Match('/', '/')) {
1875 sc.SetState(SCE_HPHP_COMMENTLINE);
1876 } else if (sc.Match('/', '*')) {
1877 sc.SetState(SCE_HPHP_COMMENT);
1878 } else if (sc.ch == '\"') {
1879 sc.SetState(SCE_HPHP_HSTRING);
1880 } else if (sc.ch == '\'') {
1881 sc.SetState(SCE_HPHP_SIMPLESTRING);
1882 } else if (sc.ch == '$' && IsPhpWordStart(static_cast<char>(sc.chNext))) {
1883 sc.SetState(SCE_HPHP_VARIABLE);
1884 } else if (isoperator(static_cast<char>(sc.ch))) {
1885 sc.SetState(SCE_HPHP_OPERATOR);
1886 }
1887 }
1888 }
1889
1890 static void ColourisePHPDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
1891 Accessor &styler) {
1892 // Lexer for HTML requires more lexical states (7 bits worth) than most lexers
1893 StyleContext sc(startPos, length, initStyle, styler, 0x7f);
1894 for (; sc.More(); sc.Forward()) {
1895 ColourisePHPPiece(sc, keywordlists);
1896 }
1897 sc.Complete();
1898 }
1899
1900 static const char * const htmlWordListDesc[] = {
1901 "HTML elements and attributes",
1902 "JavaScript keywords",
1903 "VBScript keywords",
1904 "Python keywords",
1905 "PHP keywords",
1906 "SGML and DTD keywords",
1907 0,
1908 };
1909
1910 LexerModule lmHTML(SCLEX_HTML, ColouriseHyperTextDoc, "hypertext", 0, htmlWordListDesc);
1911 LexerModule lmXML(SCLEX_XML, ColouriseHyperTextDoc, "xml", 0, htmlWordListDesc);
1912 LexerModule lmASP(SCLEX_ASP, ColouriseASPDoc, "asp", 0, htmlWordListDesc);
1913 LexerModule lmPHP(SCLEX_PHP, ColourisePHPDoc, "php", 0, htmlWordListDesc);