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