PageRenderTime 33ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/wx.mod/wxscintilla.mod/src/scintilla/src/LexHTML.cxx

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