LexHTML.cpp 69 KB

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