2512 lines
81 KiB
C++
Executable File
2512 lines
81 KiB
C++
Executable File
// Scintilla source code edit control
|
|
/** @file LexHTML.cxx
|
|
** Lexer for HTML.
|
|
**/
|
|
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
|
|
// The License.txt file describes the conditions under which this software may be distributed.
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <string>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
#include "ILexer.h"
|
|
#include "Scintilla.h"
|
|
#include "SciLexer.h"
|
|
#include "StringCopy.h"
|
|
#include "WordList.h"
|
|
#include "LexAccessor.h"
|
|
#include "Accessor.h"
|
|
#include "StyleContext.h"
|
|
#include "CharacterSet.h"
|
|
#include "LexerModule.h"
|
|
#include "OptionSet.h"
|
|
#include "DefaultLexer.h"
|
|
|
|
using namespace Scintilla;
|
|
|
|
namespace {
|
|
|
|
#define SCE_HA_JS (SCE_HJA_START - SCE_HJ_START)
|
|
#define SCE_HA_VBS (SCE_HBA_START - SCE_HB_START)
|
|
#define SCE_HA_PYTHON (SCE_HPA_START - SCE_HP_START)
|
|
|
|
enum script_type { eScriptNone = 0, eScriptJS, eScriptVBS, eScriptPython, eScriptPHP, eScriptXML, eScriptSGML, eScriptSGMLblock, eScriptComment };
|
|
enum script_mode { eHtml = 0, eNonHtmlScript, eNonHtmlPreProc, eNonHtmlScriptPreProc };
|
|
|
|
inline bool IsAWordChar(const int ch) {
|
|
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
|
|
}
|
|
|
|
inline bool IsAWordStart(const int ch) {
|
|
return (ch < 0x80) && (isalnum(ch) || ch == '_');
|
|
}
|
|
|
|
inline bool IsOperator(int ch) {
|
|
if (IsASCII(ch) && isalnum(ch))
|
|
return false;
|
|
// '.' left out as it is used to make up numbers
|
|
if (ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
|
|
ch == '(' || ch == ')' || ch == '-' || ch == '+' ||
|
|
ch == '=' || ch == '|' || ch == '{' || ch == '}' ||
|
|
ch == '[' || ch == ']' || ch == ':' || ch == ';' ||
|
|
ch == '<' || ch == '>' || ch == ',' || ch == '/' ||
|
|
ch == '?' || ch == '!' || ch == '.' || ch == '~')
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void GetTextSegment(Accessor &styler, Sci_PositionU start, Sci_PositionU end, char *s, size_t len) {
|
|
Sci_PositionU i = 0;
|
|
for (; (i < end - start + 1) && (i < len-1); i++) {
|
|
s[i] = MakeLowerCase(styler[start + i]);
|
|
}
|
|
s[i] = '\0';
|
|
}
|
|
|
|
std::string GetStringSegment(Accessor &styler, Sci_PositionU start, Sci_PositionU end) {
|
|
std::string s;
|
|
Sci_PositionU i = 0;
|
|
for (; (i < end - start + 1); i++) {
|
|
s.push_back(MakeLowerCase(styler[start + i]));
|
|
}
|
|
return s;
|
|
}
|
|
|
|
std::string GetNextWord(Accessor &styler, Sci_PositionU start) {
|
|
std::string ret;
|
|
Sci_PositionU i = 0;
|
|
for (; i < 200; i++) { // Put an upper limit to bound time taken for unexpected text.
|
|
const char ch = styler.SafeGetCharAt(start + i);
|
|
if ((i == 0) && !IsAWordStart(ch))
|
|
break;
|
|
if ((i > 0) && !IsAWordChar(ch))
|
|
break;
|
|
ret.push_back(ch);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
script_type segIsScriptingIndicator(Accessor &styler, Sci_PositionU start, Sci_PositionU end, script_type prevValue) {
|
|
char s[100];
|
|
GetTextSegment(styler, start, end, s, sizeof(s));
|
|
//Platform::DebugPrintf("Scripting indicator [%s]\n", s);
|
|
if (strstr(s, "src")) // External script
|
|
return eScriptNone;
|
|
if (strstr(s, "vbs"))
|
|
return eScriptVBS;
|
|
if (strstr(s, "pyth"))
|
|
return eScriptPython;
|
|
if (strstr(s, "javas"))
|
|
return eScriptJS;
|
|
if (strstr(s, "jscr"))
|
|
return eScriptJS;
|
|
if (strstr(s, "php"))
|
|
return eScriptPHP;
|
|
if (strstr(s, "xml")) {
|
|
const char *xml = strstr(s, "xml");
|
|
for (const char *t=s; t<xml; t++) {
|
|
if (!IsASpace(*t)) {
|
|
return prevValue;
|
|
}
|
|
}
|
|
return eScriptXML;
|
|
}
|
|
|
|
return prevValue;
|
|
}
|
|
|
|
int PrintScriptingIndicatorOffset(Accessor &styler, Sci_PositionU start, Sci_PositionU end) {
|
|
int iResult = 0;
|
|
std::string s = GetStringSegment(styler, start, end);
|
|
if (0 == strncmp(s.c_str(), "php", 3)) {
|
|
iResult = 3;
|
|
}
|
|
return iResult;
|
|
}
|
|
|
|
script_type ScriptOfState(int state) {
|
|
if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
|
|
return eScriptPython;
|
|
} else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
|
|
return eScriptVBS;
|
|
} else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
|
|
return eScriptJS;
|
|
} else if ((state >= SCE_HPHP_DEFAULT) && (state <= SCE_HPHP_COMMENTLINE)) {
|
|
return eScriptPHP;
|
|
} else if ((state >= SCE_H_SGML_DEFAULT) && (state < SCE_H_SGML_BLOCK_DEFAULT)) {
|
|
return eScriptSGML;
|
|
} else if (state == SCE_H_SGML_BLOCK_DEFAULT) {
|
|
return eScriptSGMLblock;
|
|
} else {
|
|
return eScriptNone;
|
|
}
|
|
}
|
|
|
|
int statePrintForState(int state, script_mode inScriptType) {
|
|
int StateToPrint = state;
|
|
|
|
if (state >= SCE_HJ_START) {
|
|
if ((state >= SCE_HP_START) && (state <= SCE_HP_IDENTIFIER)) {
|
|
StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_PYTHON);
|
|
} else if ((state >= SCE_HB_START) && (state <= SCE_HB_STRINGEOL)) {
|
|
StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_VBS);
|
|
} else if ((state >= SCE_HJ_START) && (state <= SCE_HJ_REGEX)) {
|
|
StateToPrint = state + ((inScriptType == eNonHtmlScript) ? 0 : SCE_HA_JS);
|
|
}
|
|
}
|
|
|
|
return StateToPrint;
|
|
}
|
|
|
|
int stateForPrintState(int StateToPrint) {
|
|
int state;
|
|
|
|
if ((StateToPrint >= SCE_HPA_START) && (StateToPrint <= SCE_HPA_IDENTIFIER)) {
|
|
state = StateToPrint - SCE_HA_PYTHON;
|
|
} else if ((StateToPrint >= SCE_HBA_START) && (StateToPrint <= SCE_HBA_STRINGEOL)) {
|
|
state = StateToPrint - SCE_HA_VBS;
|
|
} else if ((StateToPrint >= SCE_HJA_START) && (StateToPrint <= SCE_HJA_REGEX)) {
|
|
state = StateToPrint - SCE_HA_JS;
|
|
} else {
|
|
state = StateToPrint;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
inline bool IsNumber(Sci_PositionU start, Accessor &styler) {
|
|
return IsADigit(styler[start]) || (styler[start] == '.') ||
|
|
(styler[start] == '-') || (styler[start] == '#');
|
|
}
|
|
|
|
inline bool isStringState(int state) {
|
|
bool bResult;
|
|
|
|
switch (state) {
|
|
case SCE_HJ_DOUBLESTRING:
|
|
case SCE_HJ_SINGLESTRING:
|
|
case SCE_HJA_DOUBLESTRING:
|
|
case SCE_HJA_SINGLESTRING:
|
|
case SCE_HB_STRING:
|
|
case SCE_HBA_STRING:
|
|
case SCE_HP_STRING:
|
|
case SCE_HP_CHARACTER:
|
|
case SCE_HP_TRIPLE:
|
|
case SCE_HP_TRIPLEDOUBLE:
|
|
case SCE_HPA_STRING:
|
|
case SCE_HPA_CHARACTER:
|
|
case SCE_HPA_TRIPLE:
|
|
case SCE_HPA_TRIPLEDOUBLE:
|
|
case SCE_HPHP_HSTRING:
|
|
case SCE_HPHP_SIMPLESTRING:
|
|
case SCE_HPHP_HSTRING_VARIABLE:
|
|
case SCE_HPHP_COMPLEX_VARIABLE:
|
|
bResult = true;
|
|
break;
|
|
default :
|
|
bResult = false;
|
|
break;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
inline bool stateAllowsTermination(int state) {
|
|
bool allowTermination = !isStringState(state);
|
|
if (allowTermination) {
|
|
switch (state) {
|
|
case SCE_HB_COMMENTLINE:
|
|
case SCE_HPHP_COMMENT:
|
|
case SCE_HP_COMMENTLINE:
|
|
case SCE_HPA_COMMENTLINE:
|
|
allowTermination = false;
|
|
}
|
|
}
|
|
return allowTermination;
|
|
}
|
|
|
|
// not really well done, since it's only comments that should lex the %> and <%
|
|
inline bool isCommentASPState(int state) {
|
|
bool bResult;
|
|
|
|
switch (state) {
|
|
case SCE_HJ_COMMENT:
|
|
case SCE_HJ_COMMENTLINE:
|
|
case SCE_HJ_COMMENTDOC:
|
|
case SCE_HB_COMMENTLINE:
|
|
case SCE_HP_COMMENTLINE:
|
|
case SCE_HPHP_COMMENT:
|
|
case SCE_HPHP_COMMENTLINE:
|
|
bResult = true;
|
|
break;
|
|
default :
|
|
bResult = false;
|
|
break;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
void classifyAttribHTML(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) {
|
|
const bool wordIsNumber = IsNumber(start, styler);
|
|
char chAttr = SCE_H_ATTRIBUTEUNKNOWN;
|
|
if (wordIsNumber) {
|
|
chAttr = SCE_H_NUMBER;
|
|
} else {
|
|
std::string s = GetStringSegment(styler, start, end);
|
|
if (keywords.InList(s.c_str()))
|
|
chAttr = SCE_H_ATTRIBUTE;
|
|
}
|
|
if ((chAttr == SCE_H_ATTRIBUTEUNKNOWN) && !keywords)
|
|
// No keywords -> all are known
|
|
chAttr = SCE_H_ATTRIBUTE;
|
|
styler.ColourTo(end, chAttr);
|
|
}
|
|
|
|
// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-core-concepts
|
|
bool isHTMLCustomElement(const std::string &tag) {
|
|
// check valid HTML custom element name: starts with an ASCII lower alpha and contains hyphen.
|
|
// IsUpperOrLowerCase() is used for `html.tags.case.sensitive=1`.
|
|
if (tag.length() < 2 || !IsUpperOrLowerCase(tag[0])) {
|
|
return false;
|
|
}
|
|
if (tag.find('-') == std::string::npos) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int classifyTagHTML(Sci_PositionU start, Sci_PositionU end,
|
|
const WordList &keywords, Accessor &styler, bool &tagDontFold,
|
|
bool caseSensitive, bool isXml, bool allowScripts,
|
|
const std::set<std::string> &nonFoldingTags) {
|
|
std::string tag;
|
|
// Copy after the '<' and stop before ' '
|
|
for (Sci_PositionU cPos = start; cPos <= end; cPos++) {
|
|
const char ch = styler[cPos];
|
|
if (IsASpace(ch)) {
|
|
break;
|
|
}
|
|
if ((ch != '<') && (ch != '/')) {
|
|
tag.push_back(caseSensitive ? ch : MakeLowerCase(ch));
|
|
}
|
|
}
|
|
// if the current language is XML, I can fold any tag
|
|
// if the current language is HTML, I don't want to fold certain tags (input, meta, etc.)
|
|
//...to find it in the list of no-container-tags
|
|
tagDontFold = (!isXml) && (nonFoldingTags.count(tag) > 0);
|
|
// No keywords -> all are known
|
|
char chAttr = SCE_H_TAGUNKNOWN;
|
|
if (!tag.empty() && (tag[0] == '!')) {
|
|
chAttr = SCE_H_SGML_DEFAULT;
|
|
} else if (!keywords || keywords.InList(tag.c_str())) {
|
|
chAttr = SCE_H_TAG;
|
|
} else if (!isXml && isHTMLCustomElement(tag)) {
|
|
chAttr = SCE_H_TAG;
|
|
}
|
|
if (chAttr != SCE_H_TAGUNKNOWN) {
|
|
styler.ColourTo(end, chAttr);
|
|
}
|
|
if (chAttr == SCE_H_TAG) {
|
|
if (allowScripts && (tag == "script")) {
|
|
// check to see if this is a self-closing tag by sniffing ahead
|
|
bool isSelfClose = false;
|
|
for (Sci_PositionU cPos = end; cPos <= end + 200; cPos++) {
|
|
const char ch = styler.SafeGetCharAt(cPos, '\0');
|
|
if (ch == '\0' || ch == '>')
|
|
break;
|
|
else if (ch == '/' && styler.SafeGetCharAt(cPos + 1, '\0') == '>') {
|
|
isSelfClose = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// do not enter a script state if the tag self-closed
|
|
if (!isSelfClose)
|
|
chAttr = SCE_H_SCRIPT;
|
|
} else if (!isXml && (tag == "comment")) {
|
|
chAttr = SCE_H_COMMENT;
|
|
}
|
|
}
|
|
return chAttr;
|
|
}
|
|
|
|
void classifyWordHTJS(Sci_PositionU start, Sci_PositionU end,
|
|
const WordList &keywords, Accessor &styler, script_mode inScriptType) {
|
|
char s[30 + 1];
|
|
Sci_PositionU i = 0;
|
|
for (; i < end - start + 1 && i < 30; i++) {
|
|
s[i] = styler[start + i];
|
|
}
|
|
s[i] = '\0';
|
|
|
|
char chAttr = SCE_HJ_WORD;
|
|
const bool wordIsNumber = IsADigit(s[0]) || ((s[0] == '.') && IsADigit(s[1]));
|
|
if (wordIsNumber) {
|
|
chAttr = SCE_HJ_NUMBER;
|
|
} else if (keywords.InList(s)) {
|
|
chAttr = SCE_HJ_KEYWORD;
|
|
}
|
|
styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
|
|
}
|
|
|
|
int classifyWordHTVB(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, script_mode inScriptType) {
|
|
char chAttr = SCE_HB_IDENTIFIER;
|
|
const bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.');
|
|
if (wordIsNumber) {
|
|
chAttr = SCE_HB_NUMBER;
|
|
} else {
|
|
std::string s = GetStringSegment(styler, start, end);
|
|
if (keywords.InList(s.c_str())) {
|
|
chAttr = SCE_HB_WORD;
|
|
if (s == "rem")
|
|
chAttr = SCE_HB_COMMENTLINE;
|
|
}
|
|
}
|
|
styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
|
|
if (chAttr == SCE_HB_COMMENTLINE)
|
|
return SCE_HB_COMMENTLINE;
|
|
else
|
|
return SCE_HB_DEFAULT;
|
|
}
|
|
|
|
void classifyWordHTPy(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler, std::string &prevWord, script_mode inScriptType, bool isMako) {
|
|
const bool wordIsNumber = IsADigit(styler[start]);
|
|
std::string s;
|
|
for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) {
|
|
s.push_back(styler[start + i]);
|
|
}
|
|
char chAttr = SCE_HP_IDENTIFIER;
|
|
if (prevWord == "class")
|
|
chAttr = SCE_HP_CLASSNAME;
|
|
else if (prevWord == "def")
|
|
chAttr = SCE_HP_DEFNAME;
|
|
else if (wordIsNumber)
|
|
chAttr = SCE_HP_NUMBER;
|
|
else if (keywords.InList(s.c_str()))
|
|
chAttr = SCE_HP_WORD;
|
|
else if (isMako && (s == "block"))
|
|
chAttr = SCE_HP_WORD;
|
|
styler.ColourTo(end, statePrintForState(chAttr, inScriptType));
|
|
prevWord = s;
|
|
}
|
|
|
|
// Update the word colour to default or keyword
|
|
// Called when in a PHP word
|
|
void classifyWordHTPHP(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) {
|
|
char chAttr = SCE_HPHP_DEFAULT;
|
|
const bool wordIsNumber = IsADigit(styler[start]) || (styler[start] == '.' && start+1 <= end && IsADigit(styler[start+1]));
|
|
if (wordIsNumber) {
|
|
chAttr = SCE_HPHP_NUMBER;
|
|
} else {
|
|
std::string s = GetStringSegment(styler, start, end);
|
|
if (keywords.InList(s.c_str()))
|
|
chAttr = SCE_HPHP_WORD;
|
|
}
|
|
styler.ColourTo(end, chAttr);
|
|
}
|
|
|
|
bool isWordHSGML(Sci_PositionU start, Sci_PositionU end, const WordList &keywords, Accessor &styler) {
|
|
std::string s;
|
|
for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) {
|
|
s.push_back(styler[start + i]);
|
|
}
|
|
return keywords.InList(s.c_str());
|
|
}
|
|
|
|
bool isWordCdata(Sci_PositionU start, Sci_PositionU end, Accessor &styler) {
|
|
std::string s;
|
|
for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++) {
|
|
s.push_back(styler[start + i]);
|
|
}
|
|
return s == "[CDATA[";
|
|
}
|
|
|
|
// Return the first state to reach when entering a scripting language
|
|
int StateForScript(script_type scriptLanguage) {
|
|
int Result;
|
|
switch (scriptLanguage) {
|
|
case eScriptVBS:
|
|
Result = SCE_HB_START;
|
|
break;
|
|
case eScriptPython:
|
|
Result = SCE_HP_START;
|
|
break;
|
|
case eScriptPHP:
|
|
Result = SCE_HPHP_DEFAULT;
|
|
break;
|
|
case eScriptXML:
|
|
Result = SCE_H_TAGUNKNOWN;
|
|
break;
|
|
case eScriptSGML:
|
|
Result = SCE_H_SGML_DEFAULT;
|
|
break;
|
|
case eScriptComment:
|
|
Result = SCE_H_COMMENT;
|
|
break;
|
|
default :
|
|
Result = SCE_HJ_START;
|
|
break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
inline bool issgmlwordchar(int ch) {
|
|
return !IsASCII(ch) ||
|
|
(isalnum(ch) || ch == '.' || ch == '_' || ch == ':' || ch == '!' || ch == '#' || ch == '[');
|
|
}
|
|
|
|
inline bool IsPhpWordStart(int ch) {
|
|
return (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) || (ch >= 0x7f);
|
|
}
|
|
|
|
inline bool IsPhpWordChar(int ch) {
|
|
return IsADigit(ch) || IsPhpWordStart(ch);
|
|
}
|
|
|
|
bool InTagState(int state) {
|
|
return state == SCE_H_TAG || state == SCE_H_TAGUNKNOWN ||
|
|
state == SCE_H_SCRIPT ||
|
|
state == SCE_H_ATTRIBUTE || state == SCE_H_ATTRIBUTEUNKNOWN ||
|
|
state == SCE_H_NUMBER || state == SCE_H_OTHER ||
|
|
state == SCE_H_DOUBLESTRING || state == SCE_H_SINGLESTRING;
|
|
}
|
|
|
|
bool IsCommentState(const int state) {
|
|
return state == SCE_H_COMMENT || state == SCE_H_SGML_COMMENT;
|
|
}
|
|
|
|
bool IsScriptCommentState(const int state) {
|
|
return state == SCE_HJ_COMMENT || state == SCE_HJ_COMMENTLINE || state == SCE_HJA_COMMENT ||
|
|
state == SCE_HJA_COMMENTLINE || state == SCE_HB_COMMENTLINE || state == SCE_HBA_COMMENTLINE;
|
|
}
|
|
|
|
bool isLineEnd(int ch) {
|
|
return ch == '\r' || ch == '\n';
|
|
}
|
|
|
|
bool isMakoBlockEnd(const int ch, const int chNext, const std::string &blockType) {
|
|
if (blockType.empty()) {
|
|
return ((ch == '%') && (chNext == '>'));
|
|
} else if ((blockType == "inherit") ||
|
|
(blockType == "namespace") ||
|
|
(blockType == "include") ||
|
|
(blockType == "page")) {
|
|
return ((ch == '/') && (chNext == '>'));
|
|
} else if (blockType == "%") {
|
|
if (ch == '/' && isLineEnd(chNext))
|
|
return true;
|
|
else
|
|
return isLineEnd(ch);
|
|
} else if (blockType == "{") {
|
|
return ch == '}';
|
|
} else {
|
|
return (ch == '>');
|
|
}
|
|
}
|
|
|
|
bool isDjangoBlockEnd(const int ch, const int chNext, const std::string &blockType) {
|
|
if (blockType.empty()) {
|
|
return false;
|
|
} else if (blockType == "%") {
|
|
return ((ch == '%') && (chNext == '}'));
|
|
} else if (blockType == "{") {
|
|
return ((ch == '}') && (chNext == '}'));
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isPHPStringState(int state) {
|
|
return
|
|
(state == SCE_HPHP_HSTRING) ||
|
|
(state == SCE_HPHP_SIMPLESTRING) ||
|
|
(state == SCE_HPHP_HSTRING_VARIABLE) ||
|
|
(state == SCE_HPHP_COMPLEX_VARIABLE);
|
|
}
|
|
|
|
Sci_Position FindPhpStringDelimiter(std::string &phpStringDelimiter, Sci_Position i, const Sci_Position lengthDoc, Accessor &styler, bool &isSimpleString) {
|
|
Sci_Position j;
|
|
const Sci_Position beginning = i - 1;
|
|
bool isValidSimpleString = false;
|
|
|
|
while (i < lengthDoc && (styler[i] == ' ' || styler[i] == '\t'))
|
|
i++;
|
|
char ch = styler.SafeGetCharAt(i);
|
|
const char chNext = styler.SafeGetCharAt(i + 1);
|
|
phpStringDelimiter.clear();
|
|
if (!IsPhpWordStart(ch)) {
|
|
if (ch == '\'' && IsPhpWordStart(chNext)) {
|
|
i++;
|
|
ch = chNext;
|
|
isSimpleString = true;
|
|
} else {
|
|
return beginning;
|
|
}
|
|
}
|
|
phpStringDelimiter.push_back(ch);
|
|
i++;
|
|
for (j = i; j < lengthDoc && !isLineEnd(styler[j]); j++) {
|
|
if (!IsPhpWordChar(styler[j])) {
|
|
if (isSimpleString && (styler[j] == '\'') && isLineEnd(styler.SafeGetCharAt(j + 1))) {
|
|
isValidSimpleString = true;
|
|
j++;
|
|
break;
|
|
} else {
|
|
phpStringDelimiter.clear();
|
|
return beginning;
|
|
}
|
|
}
|
|
phpStringDelimiter.push_back(styler[j]);
|
|
}
|
|
if (isSimpleString && !isValidSimpleString) {
|
|
phpStringDelimiter.clear();
|
|
return beginning;
|
|
}
|
|
return j - 1;
|
|
}
|
|
|
|
// Options used for LexerHTML
|
|
struct OptionsHTML {
|
|
int aspDefaultLanguage = eScriptJS;
|
|
bool caseSensitive = false;
|
|
bool allowScripts = true;
|
|
bool isMako = false;
|
|
bool isDjango = false;
|
|
bool fold = false;
|
|
bool foldHTML = false;
|
|
bool foldHTMLPreprocessor = true;
|
|
bool foldCompact = true;
|
|
bool foldComment = false;
|
|
bool foldHeredoc = false;
|
|
bool foldXmlAtTagOpen = false;
|
|
OptionsHTML() noexcept {
|
|
}
|
|
};
|
|
|
|
const char * const htmlWordListDesc[] = {
|
|
"HTML elements and attributes",
|
|
"JavaScript keywords",
|
|
"VBScript keywords",
|
|
"Python keywords",
|
|
"PHP keywords",
|
|
"SGML and DTD keywords",
|
|
0,
|
|
};
|
|
|
|
const char * const phpscriptWordListDesc[] = {
|
|
"", //Unused
|
|
"", //Unused
|
|
"", //Unused
|
|
"", //Unused
|
|
"PHP keywords",
|
|
"", //Unused
|
|
0,
|
|
};
|
|
|
|
struct OptionSetHTML : public OptionSet<OptionsHTML> {
|
|
OptionSetHTML(bool isPHPScript_) {
|
|
|
|
DefineProperty("asp.default.language", &OptionsHTML::aspDefaultLanguage,
|
|
"Script in ASP code is initially assumed to be in JavaScript. "
|
|
"To change this to VBScript set asp.default.language to 2. Python is 3.");
|
|
|
|
DefineProperty("html.tags.case.sensitive", &OptionsHTML::caseSensitive,
|
|
"For XML and HTML, setting this property to 1 will make tags match in a case "
|
|
"sensitive way which is the expected behaviour for XML and XHTML.");
|
|
|
|
DefineProperty("lexer.xml.allow.scripts", &OptionsHTML::allowScripts,
|
|
"Set to 0 to disable scripts in XML.");
|
|
|
|
DefineProperty("lexer.html.mako", &OptionsHTML::isMako,
|
|
"Set to 1 to enable the mako template language.");
|
|
|
|
DefineProperty("lexer.html.django", &OptionsHTML::isDjango,
|
|
"Set to 1 to enable the django template language.");
|
|
|
|
DefineProperty("fold", &OptionsHTML::fold);
|
|
|
|
DefineProperty("fold.html", &OptionsHTML::foldHTML,
|
|
"Folding is turned on or off for HTML and XML files with this option. "
|
|
"The fold option must also be on for folding to occur.");
|
|
|
|
DefineProperty("fold.html.preprocessor", &OptionsHTML::foldHTMLPreprocessor,
|
|
"Folding is turned on or off for scripts embedded in HTML files with this option. "
|
|
"The default is on.");
|
|
|
|
DefineProperty("fold.compact", &OptionsHTML::foldCompact);
|
|
|
|
DefineProperty("fold.hypertext.comment", &OptionsHTML::foldComment,
|
|
"Allow folding for comments in scripts embedded in HTML. "
|
|
"The default is off.");
|
|
|
|
DefineProperty("fold.hypertext.heredoc", &OptionsHTML::foldHeredoc,
|
|
"Allow folding for heredocs in scripts embedded in HTML. "
|
|
"The default is off.");
|
|
|
|
DefineProperty("fold.xml.at.tag.open", &OptionsHTML::foldXmlAtTagOpen,
|
|
"Enable folding for XML at the start of open tag. "
|
|
"The default is off.");
|
|
|
|
DefineWordListSets(isPHPScript_ ? phpscriptWordListDesc : htmlWordListDesc);
|
|
}
|
|
};
|
|
|
|
LexicalClass lexicalClassesHTML[] = {
|
|
// Lexer HTML SCLEX_HTML SCE_H_ SCE_HJ_ SCE_HJA_ SCE_HB_ SCE_HBA_ SCE_HP_ SCE_HPHP_ SCE_HPA_:
|
|
0, "SCE_H_DEFAULT", "default", "Text",
|
|
1, "SCE_H_TAG", "tag", "Tags",
|
|
2, "SCE_H_ERRORTAGUNKNOWN", "error tag", "Unknown Tags",
|
|
3, "SCE_H_ATTRIBUTE", "attribute", "Attributes",
|
|
4, "SCE_H_ATTRIBUTEUNKNOWN", "error attribute", "Unknown Attributes",
|
|
5, "SCE_H_NUMBER", "literal numeric", "Numbers",
|
|
6, "SCE_H_DOUBLESTRING", "literal string", "Double quoted strings",
|
|
7, "SCE_H_SINGLESTRING", "literal string", "Single quoted strings",
|
|
8, "SCE_H_OTHER", "tag operator", "Other inside tag, including space and '='",
|
|
9, "SCE_H_COMMENT", "comment", "Comment",
|
|
10, "SCE_H_ENTITY", "literal", "Entities",
|
|
11, "SCE_H_TAGEND", "tag", "XML style tag ends '/>'",
|
|
12, "SCE_H_XMLSTART", "identifier", "XML identifier start '<?'",
|
|
13, "SCE_H_XMLEND", "identifier", "XML identifier end '?>'",
|
|
14, "SCE_H_SCRIPT", "error", "Internal state which should never be visible",
|
|
15, "SCE_H_ASP", "preprocessor", "ASP <% ... %>",
|
|
16, "SCE_H_ASPAT", "preprocessor", "ASP <% ... %>",
|
|
17, "SCE_H_CDATA", "literal", "CDATA",
|
|
18, "SCE_H_QUESTION", "preprocessor", "PHP",
|
|
19, "SCE_H_VALUE", "literal string", "Unquoted values",
|
|
20, "SCE_H_XCCOMMENT", "comment", "JSP Comment <%-- ... --%>",
|
|
21, "SCE_H_SGML_DEFAULT", "default", "SGML tags <! ... >",
|
|
22, "SCE_H_SGML_COMMAND", "preprocessor", "SGML command",
|
|
23, "SCE_H_SGML_1ST_PARAM", "preprocessor", "SGML 1st param",
|
|
24, "SCE_H_SGML_DOUBLESTRING", "literal string", "SGML double string",
|
|
25, "SCE_H_SGML_SIMPLESTRING", "literal string", "SGML single string",
|
|
26, "SCE_H_SGML_ERROR", "error", "SGML error",
|
|
27, "SCE_H_SGML_SPECIAL", "literal", "SGML special (#XXXX type)",
|
|
28, "SCE_H_SGML_ENTITY", "literal", "SGML entity",
|
|
29, "SCE_H_SGML_COMMENT", "comment", "SGML comment",
|
|
30, "SCE_H_SGML_1ST_PARAM_COMMENT", "error comment", "SGML first parameter - lexer internal. It is an error if any text is in this style.",
|
|
31, "SCE_H_SGML_BLOCK_DEFAULT", "default", "SGML block",
|
|
32, "", "predefined", "",
|
|
33, "", "predefined", "",
|
|
34, "", "predefined", "",
|
|
35, "", "predefined", "",
|
|
36, "", "predefined", "",
|
|
37, "", "predefined", "",
|
|
38, "", "predefined", "",
|
|
39, "", "predefined", "",
|
|
40, "SCE_HJ_START", "client javascript default", "JS Start - allows eol filled background to not start on same line as SCRIPT tag",
|
|
41, "SCE_HJ_DEFAULT", "client javascript default", "JS Default",
|
|
42, "SCE_HJ_COMMENT", "client javascript comment", "JS Comment",
|
|
43, "SCE_HJ_COMMENTLINE", "client javascript comment line", "JS Line Comment",
|
|
44, "SCE_HJ_COMMENTDOC", "client javascript comment documentation", "JS Doc comment",
|
|
45, "SCE_HJ_NUMBER", "client javascript literal numeric", "JS Number",
|
|
46, "SCE_HJ_WORD", "client javascript identifier", "JS Word",
|
|
47, "SCE_HJ_KEYWORD", "client javascript keyword", "JS Keyword",
|
|
48, "SCE_HJ_DOUBLESTRING", "client javascript literal string", "JS Double quoted string",
|
|
49, "SCE_HJ_SINGLESTRING", "client javascript literal string", "JS Single quoted string",
|
|
50, "SCE_HJ_SYMBOLS", "client javascript operator", "JS Symbols",
|
|
51, "SCE_HJ_STRINGEOL", "client javascript error literal string", "JavaScript EOL",
|
|
52, "SCE_HJ_REGEX", "client javascript literal regex", "JavaScript RegEx",
|
|
53, "", "unused", "",
|
|
54, "", "unused", "",
|
|
55, "SCE_HJA_START", "server javascript default", "JS Start - allows eol filled background to not start on same line as SCRIPT tag",
|
|
56, "SCE_HJA_DEFAULT", "server javascript default", "JS Default",
|
|
57, "SCE_HJA_COMMENT", "server javascript comment", "JS Comment",
|
|
58, "SCE_HJA_COMMENTLINE", "server javascript comment line", "JS Line Comment",
|
|
59, "SCE_HJA_COMMENTDOC", "server javascript comment documentation", "JS Doc comment",
|
|
60, "SCE_HJA_NUMBER", "server javascript literal numeric", "JS Number",
|
|
61, "SCE_HJA_WORD", "server javascript identifier", "JS Word",
|
|
62, "SCE_HJA_KEYWORD", "server javascript keyword", "JS Keyword",
|
|
63, "SCE_HJA_DOUBLESTRING", "server javascript literal string", "JS Double quoted string",
|
|
64, "SCE_HJA_SINGLESTRING", "server javascript literal string", "JS Single quoted string",
|
|
65, "SCE_HJA_SYMBOLS", "server javascript operator", "JS Symbols",
|
|
66, "SCE_HJA_STRINGEOL", "server javascript error literal string", "JavaScript EOL",
|
|
67, "SCE_HJA_REGEX", "server javascript literal regex", "JavaScript RegEx",
|
|
68, "", "unused", "",
|
|
69, "", "unused", "",
|
|
70, "SCE_HB_START", "client basic default", "Start",
|
|
71, "SCE_HB_DEFAULT", "client basic default", "Default",
|
|
72, "SCE_HB_COMMENTLINE", "client basic comment line", "Comment",
|
|
73, "SCE_HB_NUMBER", "client basic literal numeric", "Number",
|
|
74, "SCE_HB_WORD", "client basic keyword", "KeyWord",
|
|
75, "SCE_HB_STRING", "client basic literal string", "String",
|
|
76, "SCE_HB_IDENTIFIER", "client basic identifier", "Identifier",
|
|
77, "SCE_HB_STRINGEOL", "client basic literal string", "Unterminated string",
|
|
78, "", "unused", "",
|
|
79, "", "unused", "",
|
|
80, "SCE_HBA_START", "server basic default", "Start",
|
|
81, "SCE_HBA_DEFAULT", "server basic default", "Default",
|
|
82, "SCE_HBA_COMMENTLINE", "server basic comment line", "Comment",
|
|
83, "SCE_HBA_NUMBER", "server basic literal numeric", "Number",
|
|
84, "SCE_HBA_WORD", "server basic keyword", "KeyWord",
|
|
85, "SCE_HBA_STRING", "server basic literal string", "String",
|
|
86, "SCE_HBA_IDENTIFIER", "server basic identifier", "Identifier",
|
|
87, "SCE_HBA_STRINGEOL", "server basic literal string", "Unterminated string",
|
|
88, "", "unused", "",
|
|
89, "", "unused", "",
|
|
90, "SCE_HP_START", "client python default", "Embedded Python",
|
|
91, "SCE_HP_DEFAULT", "client python default", "Embedded Python",
|
|
92, "SCE_HP_COMMENTLINE", "client python comment line", "Comment",
|
|
93, "SCE_HP_NUMBER", "client python literal numeric", "Number",
|
|
94, "SCE_HP_STRING", "client python literal string", "String",
|
|
95, "SCE_HP_CHARACTER", "client python literal string character", "Single quoted string",
|
|
96, "SCE_HP_WORD", "client python keyword", "Keyword",
|
|
97, "SCE_HP_TRIPLE", "client python literal string", "Triple quotes",
|
|
98, "SCE_HP_TRIPLEDOUBLE", "client python literal string", "Triple double quotes",
|
|
99, "SCE_HP_CLASSNAME", "client python identifier", "Class name definition",
|
|
100, "SCE_HP_DEFNAME", "client python identifier", "Function or method name definition",
|
|
101, "SCE_HP_OPERATOR", "client python operator", "Operators",
|
|
102, "SCE_HP_IDENTIFIER", "client python identifier", "Identifiers",
|
|
103, "", "unused", "",
|
|
104, "SCE_HPHP_COMPLEX_VARIABLE", "server php identifier", "PHP complex variable",
|
|
105, "SCE_HPA_START", "server python default", "ASP Python",
|
|
106, "SCE_HPA_DEFAULT", "server python default", "ASP Python",
|
|
107, "SCE_HPA_COMMENTLINE", "server python comment line", "Comment",
|
|
108, "SCE_HPA_NUMBER", "server python literal numeric", "Number",
|
|
109, "SCE_HPA_STRING", "server python literal string", "String",
|
|
110, "SCE_HPA_CHARACTER", "server python literal string character", "Single quoted string",
|
|
111, "SCE_HPA_WORD", "server python keyword", "Keyword",
|
|
112, "SCE_HPA_TRIPLE", "server python literal string", "Triple quotes",
|
|
113, "SCE_HPA_TRIPLEDOUBLE", "server python literal string", "Triple double quotes",
|
|
114, "SCE_HPA_CLASSNAME", "server python identifier", "Class name definition",
|
|
115, "SCE_HPA_DEFNAME", "server python identifier", "Function or method name definition",
|
|
116, "SCE_HPA_OPERATOR", "server python operator", "Operators",
|
|
117, "SCE_HPA_IDENTIFIER", "server python identifier", "Identifiers",
|
|
118, "SCE_HPHP_DEFAULT", "server php default", "Default",
|
|
119, "SCE_HPHP_HSTRING", "server php literal string", "Double quoted String",
|
|
120, "SCE_HPHP_SIMPLESTRING", "server php literal string", "Single quoted string",
|
|
121, "SCE_HPHP_WORD", "server php keyword", "Keyword",
|
|
122, "SCE_HPHP_NUMBER", "server php literal numeric", "Number",
|
|
123, "SCE_HPHP_VARIABLE", "server php identifier", "Variable",
|
|
124, "SCE_HPHP_COMMENT", "server php comment", "Comment",
|
|
125, "SCE_HPHP_COMMENTLINE", "server php comment line", "One line comment",
|
|
126, "SCE_HPHP_HSTRING_VARIABLE", "server php literal string identifier", "PHP variable in double quoted string",
|
|
127, "SCE_HPHP_OPERATOR", "server php operator", "PHP operator",
|
|
};
|
|
|
|
LexicalClass lexicalClassesXML[] = {
|
|
// Lexer.Secondary XML SCLEX_XML SCE_H_:
|
|
0, "SCE_H_DEFAULT", "default", "Default",
|
|
1, "SCE_H_TAG", "tag", "Tags",
|
|
2, "SCE_H_TAGUNKNOWN", "error tag", "Unknown Tags",
|
|
3, "SCE_H_ATTRIBUTE", "attribute", "Attributes",
|
|
4, "SCE_H_ERRORATTRIBUTEUNKNOWN", "error attribute", "Unknown Attributes",
|
|
5, "SCE_H_NUMBER", "literal numeric", "Numbers",
|
|
6, "SCE_H_DOUBLESTRING", "literal string", "Double quoted strings",
|
|
7, "SCE_H_SINGLESTRING", "literal string", "Single quoted strings",
|
|
8, "SCE_H_OTHER", "tag operator", "Other inside tag, including space and '='",
|
|
9, "SCE_H_COMMENT", "comment", "Comment",
|
|
10, "SCE_H_ENTITY", "literal", "Entities",
|
|
11, "SCE_H_TAGEND", "tag", "XML style tag ends '/>'",
|
|
12, "SCE_H_XMLSTART", "identifier", "XML identifier start '<?'",
|
|
13, "SCE_H_XMLEND", "identifier", "XML identifier end '?>'",
|
|
14, "", "unused", "",
|
|
15, "", "unused", "",
|
|
16, "", "unused", "",
|
|
17, "SCE_H_CDATA", "literal", "CDATA",
|
|
18, "SCE_H_QUESTION", "preprocessor", "Question",
|
|
19, "SCE_H_VALUE", "literal string", "Unquoted Value",
|
|
20, "", "unused", "",
|
|
21, "SCE_H_SGML_DEFAULT", "default", "SGML tags <! ... >",
|
|
22, "SCE_H_SGML_COMMAND", "preprocessor", "SGML command",
|
|
23, "SCE_H_SGML_1ST_PARAM", "preprocessor", "SGML 1st param",
|
|
24, "SCE_H_SGML_DOUBLESTRING", "literal string", "SGML double string",
|
|
25, "SCE_H_SGML_SIMPLESTRING", "literal string", "SGML single string",
|
|
26, "SCE_H_SGML_ERROR", "error", "SGML error",
|
|
27, "SCE_H_SGML_SPECIAL", "literal", "SGML special (#XXXX type)",
|
|
28, "SCE_H_SGML_ENTITY", "literal", "SGML entity",
|
|
29, "SCE_H_SGML_COMMENT", "comment", "SGML comment",
|
|
30, "", "unused", "",
|
|
31, "SCE_H_SGML_BLOCK_DEFAULT", "default", "SGML block",
|
|
};
|
|
|
|
const char *tagsThatDoNotFold[] = {
|
|
"area",
|
|
"base",
|
|
"basefont",
|
|
"br",
|
|
"col",
|
|
"command",
|
|
"embed",
|
|
"frame",
|
|
"hr",
|
|
"img",
|
|
"input",
|
|
"isindex",
|
|
"keygen",
|
|
"link",
|
|
"meta",
|
|
"param",
|
|
"source",
|
|
"track",
|
|
"wbr"
|
|
};
|
|
|
|
}
|
|
|
|
class LexerHTML : public DefaultLexer {
|
|
bool isXml;
|
|
bool isPHPScript;
|
|
WordList keywords;
|
|
WordList keywords2;
|
|
WordList keywords3;
|
|
WordList keywords4;
|
|
WordList keywords5;
|
|
WordList keywords6; // SGML (DTD) keywords
|
|
OptionsHTML options;
|
|
OptionSetHTML osHTML;
|
|
std::set<std::string> nonFoldingTags;
|
|
public:
|
|
explicit LexerHTML(bool isXml_, bool isPHPScript_) :
|
|
DefaultLexer(isXml_ ? lexicalClassesHTML : lexicalClassesXML,
|
|
isXml_ ? ELEMENTS(lexicalClassesHTML) : ELEMENTS(lexicalClassesXML)),
|
|
isXml(isXml_),
|
|
isPHPScript(isPHPScript_),
|
|
osHTML(isPHPScript_),
|
|
nonFoldingTags(std::begin(tagsThatDoNotFold), std::end(tagsThatDoNotFold)) {
|
|
}
|
|
~LexerHTML() override {
|
|
}
|
|
void SCI_METHOD Release() override {
|
|
delete this;
|
|
}
|
|
const char *SCI_METHOD PropertyNames() override {
|
|
return osHTML.PropertyNames();
|
|
}
|
|
int SCI_METHOD PropertyType(const char *name) override {
|
|
return osHTML.PropertyType(name);
|
|
}
|
|
const char *SCI_METHOD DescribeProperty(const char *name) override {
|
|
return osHTML.DescribeProperty(name);
|
|
}
|
|
Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
|
|
const char *SCI_METHOD DescribeWordListSets() override {
|
|
return osHTML.DescribeWordListSets();
|
|
}
|
|
Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
|
|
void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
|
|
// No Fold as all folding performs in Lex.
|
|
|
|
static ILexer *LexerFactoryHTML() {
|
|
return new LexerHTML(false, false);
|
|
}
|
|
static ILexer *LexerFactoryXML() {
|
|
return new LexerHTML(true, false);
|
|
}
|
|
static ILexer *LexerFactoryPHPScript() {
|
|
return new LexerHTML(false, true);
|
|
}
|
|
};
|
|
|
|
Sci_Position SCI_METHOD LexerHTML::PropertySet(const char *key, const char *val) {
|
|
if (osHTML.PropertySet(&options, key, val)) {
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
Sci_Position SCI_METHOD LexerHTML::WordListSet(int n, const char *wl) {
|
|
WordList *wordListN = 0;
|
|
switch (n) {
|
|
case 0:
|
|
wordListN = &keywords;
|
|
break;
|
|
case 1:
|
|
wordListN = &keywords2;
|
|
break;
|
|
case 2:
|
|
wordListN = &keywords3;
|
|
break;
|
|
case 3:
|
|
wordListN = &keywords4;
|
|
break;
|
|
case 4:
|
|
wordListN = &keywords5;
|
|
break;
|
|
case 5:
|
|
wordListN = &keywords6;
|
|
break;
|
|
}
|
|
Sci_Position firstModification = -1;
|
|
if (wordListN) {
|
|
WordList wlNew;
|
|
wlNew.Set(wl);
|
|
if (*wordListN != wlNew) {
|
|
wordListN->Set(wl);
|
|
firstModification = 0;
|
|
}
|
|
}
|
|
return firstModification;
|
|
}
|
|
|
|
void SCI_METHOD LexerHTML::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
|
|
Accessor styler(pAccess, nullptr);
|
|
if (isPHPScript && (startPos == 0)) {
|
|
initStyle = SCE_HPHP_DEFAULT;
|
|
}
|
|
styler.StartAt(startPos);
|
|
std::string prevWord;
|
|
std::string phpStringDelimiter;
|
|
int StateToPrint = initStyle;
|
|
int state = stateForPrintState(StateToPrint);
|
|
std::string makoBlockType;
|
|
int makoComment = 0;
|
|
std::string djangoBlockType;
|
|
// 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
|
|
if (InTagState(state)) {
|
|
while ((startPos > 0) && (InTagState(styler.StyleAt(startPos - 1)))) {
|
|
const Sci_Position backLineStart = styler.LineStart(styler.GetLine(startPos-1));
|
|
length += startPos - backLineStart;
|
|
startPos = backLineStart;
|
|
}
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
// String can be heredoc, must find a delimiter first. Reread from beginning of line containing the string, to get the correct lineState
|
|
if (isPHPStringState(state)) {
|
|
while (startPos > 0 && (isPHPStringState(state) || !isLineEnd(styler[startPos - 1]))) {
|
|
startPos--;
|
|
length++;
|
|
state = styler.StyleAt(startPos);
|
|
}
|
|
if (startPos == 0)
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
styler.StartAt(startPos);
|
|
|
|
/* Nothing handles getting out of these, so we need not start in any of them.
|
|
* As we're at line start and they can't span lines, we'll re-detect them anyway */
|
|
switch (state) {
|
|
case SCE_H_QUESTION:
|
|
case SCE_H_XMLSTART:
|
|
case SCE_H_XMLEND:
|
|
case SCE_H_ASP:
|
|
state = SCE_H_DEFAULT;
|
|
break;
|
|
}
|
|
|
|
Sci_Position lineCurrent = styler.GetLine(startPos);
|
|
int lineState;
|
|
if (lineCurrent > 0) {
|
|
lineState = styler.GetLineState(lineCurrent-1);
|
|
} else {
|
|
// Default client and ASP scripting language is JavaScript
|
|
lineState = eScriptJS << 8;
|
|
lineState |= options.aspDefaultLanguage << 4;
|
|
}
|
|
script_mode inScriptType = static_cast<script_mode>((lineState >> 0) & 0x03); // 2 bits of scripting mode
|
|
|
|
bool tagOpened = (lineState >> 2) & 0x01; // 1 bit to know if we are in an opened tag
|
|
bool tagClosing = (lineState >> 3) & 0x01; // 1 bit to know if we are in a closing tag
|
|
bool tagDontFold = false; //some HTML tags should not be folded
|
|
script_type aspScript = static_cast<script_type>((lineState >> 4) & 0x0F); // 4 bits of script name
|
|
script_type clientScript = static_cast<script_type>((lineState >> 8) & 0x0F); // 4 bits of script name
|
|
int beforePreProc = (lineState >> 12) & 0xFF; // 8 bits of state
|
|
|
|
script_type scriptLanguage = ScriptOfState(state);
|
|
// If eNonHtmlScript coincides with SCE_H_COMMENT, assume eScriptComment
|
|
if (inScriptType == eNonHtmlScript && state == SCE_H_COMMENT) {
|
|
scriptLanguage = eScriptComment;
|
|
}
|
|
script_type beforeLanguage = ScriptOfState(beforePreProc);
|
|
const bool foldHTML = options.foldHTML;
|
|
const bool fold = foldHTML && options.fold;
|
|
const bool foldHTMLPreprocessor = foldHTML && options.foldHTMLPreprocessor;
|
|
const bool foldCompact = options.foldCompact;
|
|
const bool foldComment = fold && options.foldComment;
|
|
const bool foldHeredoc = fold && options.foldHeredoc;
|
|
const bool foldXmlAtTagOpen = isXml && fold && options.foldXmlAtTagOpen;
|
|
const bool caseSensitive = options.caseSensitive;
|
|
const bool allowScripts = options.allowScripts;
|
|
const bool isMako = options.isMako;
|
|
const bool isDjango = options.isDjango;
|
|
const CharacterSet setHTMLWord(CharacterSet::setAlphaNum, ".-_:!#", 0x80, true);
|
|
const CharacterSet setTagContinue(CharacterSet::setAlphaNum, ".-_:!#[", 0x80, true);
|
|
const CharacterSet setAttributeContinue(CharacterSet::setAlphaNum, ".-_:!#/", 0x80, true);
|
|
// TODO: also handle + and - (except if they're part of ++ or --) and return keywords
|
|
const CharacterSet setOKBeforeJSRE(CharacterSet::setNone, "([{=,:;!%^&*|?~");
|
|
|
|
int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
|
|
int levelCurrent = levelPrev;
|
|
int visibleChars = 0;
|
|
int lineStartVisibleChars = 0;
|
|
|
|
int chPrev = ' ';
|
|
int ch = ' ';
|
|
int chPrevNonWhite = ' ';
|
|
// look back to set chPrevNonWhite properly for better regex colouring
|
|
if (scriptLanguage == eScriptJS && startPos > 0) {
|
|
Sci_Position back = startPos;
|
|
int style = 0;
|
|
while (--back) {
|
|
style = styler.StyleAt(back);
|
|
if (style < SCE_HJ_DEFAULT || style > SCE_HJ_COMMENTDOC)
|
|
// includes SCE_HJ_COMMENT & SCE_HJ_COMMENTLINE
|
|
break;
|
|
}
|
|
if (style == SCE_HJ_SYMBOLS) {
|
|
chPrevNonWhite = static_cast<unsigned char>(styler.SafeGetCharAt(back));
|
|
}
|
|
}
|
|
|
|
styler.StartSegment(startPos);
|
|
const Sci_Position lengthDoc = startPos + length;
|
|
for (Sci_Position i = startPos; i < lengthDoc; i++) {
|
|
const int chPrev2 = chPrev;
|
|
chPrev = ch;
|
|
if (!IsASpace(ch) && state != SCE_HJ_COMMENT &&
|
|
state != SCE_HJ_COMMENTLINE && state != SCE_HJ_COMMENTDOC)
|
|
chPrevNonWhite = ch;
|
|
ch = static_cast<unsigned char>(styler[i]);
|
|
int chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
const int chNext2 = static_cast<unsigned char>(styler.SafeGetCharAt(i + 2));
|
|
|
|
// Handle DBCS codepages
|
|
if (styler.IsLeadByte(static_cast<char>(ch))) {
|
|
chPrev = ' ';
|
|
i += 1;
|
|
continue;
|
|
}
|
|
|
|
if ((!IsASpace(ch) || !foldCompact) && fold)
|
|
visibleChars++;
|
|
if (!IsASpace(ch))
|
|
lineStartVisibleChars++;
|
|
|
|
// decide what is the current state to print (depending of the script tag)
|
|
StateToPrint = statePrintForState(state, inScriptType);
|
|
|
|
// handle script folding
|
|
if (fold) {
|
|
switch (scriptLanguage) {
|
|
case eScriptJS:
|
|
case eScriptPHP:
|
|
//not currently supported case eScriptVBS:
|
|
|
|
if ((state != SCE_HPHP_COMMENT) && (state != SCE_HPHP_COMMENTLINE) && (state != SCE_HJ_COMMENT) && (state != SCE_HJ_COMMENTLINE) && (state != SCE_HJ_COMMENTDOC) && (!isStringState(state))) {
|
|
//Platform::DebugPrintf("state=%d, StateToPrint=%d, initStyle=%d\n", state, StateToPrint, initStyle);
|
|
//if ((state == SCE_HPHP_OPERATOR) || (state == SCE_HPHP_DEFAULT) || (state == SCE_HJ_SYMBOLS) || (state == SCE_HJ_START) || (state == SCE_HJ_DEFAULT)) {
|
|
if (ch == '#') {
|
|
Sci_Position j = i + 1;
|
|
while ((j < lengthDoc) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
|
|
j++;
|
|
}
|
|
if (styler.Match(j, "region") || styler.Match(j, "if")) {
|
|
levelCurrent++;
|
|
} else if (styler.Match(j, "end")) {
|
|
levelCurrent--;
|
|
}
|
|
} else if ((ch == '{') || (ch == '}') || (foldComment && (ch == '/') && (chNext == '*'))) {
|
|
levelCurrent += (((ch == '{') || (ch == '/')) ? 1 : -1);
|
|
}
|
|
} else if (((state == SCE_HPHP_COMMENT) || (state == SCE_HJ_COMMENT)) && foldComment && (ch == '*') && (chNext == '/')) {
|
|
levelCurrent--;
|
|
}
|
|
break;
|
|
case eScriptPython:
|
|
if (state != SCE_HP_COMMENTLINE && !isMako) {
|
|
if ((ch == ':') && ((chNext == '\n') || (chNext == '\r' && chNext2 == '\n'))) {
|
|
levelCurrent++;
|
|
} else if ((ch == '\n') && !((chNext == '\r') && (chNext2 == '\n')) && (chNext != '\n')) {
|
|
// check if the number of tabs is lower than the level
|
|
int Findlevel = (levelCurrent & ~SC_FOLDLEVELBASE) * 8;
|
|
for (Sci_Position j = 0; Findlevel > 0; j++) {
|
|
const char chTmp = styler.SafeGetCharAt(i + j + 1);
|
|
if (chTmp == '\t') {
|
|
Findlevel -= 8;
|
|
} else if (chTmp == ' ') {
|
|
Findlevel--;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Findlevel > 0) {
|
|
levelCurrent -= Findlevel / 8;
|
|
if (Findlevel % 8)
|
|
levelCurrent--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
|
|
// Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
|
|
// Avoid triggering two times on Dos/Win
|
|
// New line -> record any line state onto /next/ line
|
|
if (fold) {
|
|
int lev = levelPrev;
|
|
if (visibleChars == 0)
|
|
lev |= SC_FOLDLEVELWHITEFLAG;
|
|
if ((levelCurrent > levelPrev) && (visibleChars > 0))
|
|
lev |= SC_FOLDLEVELHEADERFLAG;
|
|
|
|
styler.SetLevel(lineCurrent, lev);
|
|
visibleChars = 0;
|
|
levelPrev = levelCurrent;
|
|
}
|
|
styler.SetLineState(lineCurrent,
|
|
((inScriptType & 0x03) << 0) |
|
|
((tagOpened ? 1 : 0) << 2) |
|
|
((tagClosing ? 1 : 0) << 3) |
|
|
((aspScript & 0x0F) << 4) |
|
|
((clientScript & 0x0F) << 8) |
|
|
((beforePreProc & 0xFF) << 12));
|
|
lineCurrent++;
|
|
lineStartVisibleChars = 0;
|
|
}
|
|
|
|
// handle start of Mako comment line
|
|
if (isMako && ch == '#' && chNext == '#') {
|
|
makoComment = 1;
|
|
state = SCE_HP_COMMENTLINE;
|
|
}
|
|
|
|
// handle end of Mako comment line
|
|
else if (isMako && makoComment && (ch == '\r' || ch == '\n')) {
|
|
makoComment = 0;
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (scriptLanguage == eScriptPython) {
|
|
state = SCE_HP_DEFAULT;
|
|
} else {
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
}
|
|
// Allow falling through to mako handling code if newline is going to end a block
|
|
if (((ch == '\r' && chNext != '\n') || (ch == '\n')) &&
|
|
(!isMako || (makoBlockType != "%"))) {
|
|
}
|
|
// Ignore everything in mako comment until the line ends
|
|
else if (isMako && makoComment) {
|
|
}
|
|
|
|
// generic end of script processing
|
|
else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) {
|
|
// Check if it's the end of the script tag (or any other HTML tag)
|
|
switch (state) {
|
|
// in these cases, you can embed HTML tags (to confirm !!!!!!!!!!!!!!!!!!!!!!)
|
|
case SCE_H_DOUBLESTRING:
|
|
case SCE_H_SINGLESTRING:
|
|
case SCE_HJ_COMMENT:
|
|
case SCE_HJ_COMMENTDOC:
|
|
//case SCE_HJ_COMMENTLINE: // removed as this is a common thing done to hide
|
|
// the end of script marker from some JS interpreters.
|
|
case SCE_HB_COMMENTLINE:
|
|
case SCE_HBA_COMMENTLINE:
|
|
case SCE_HJ_DOUBLESTRING:
|
|
case SCE_HJ_SINGLESTRING:
|
|
case SCE_HJ_REGEX:
|
|
case SCE_HB_STRING:
|
|
case SCE_HBA_STRING:
|
|
case SCE_HP_STRING:
|
|
case SCE_HP_TRIPLE:
|
|
case SCE_HP_TRIPLEDOUBLE:
|
|
case SCE_HPHP_HSTRING:
|
|
case SCE_HPHP_SIMPLESTRING:
|
|
case SCE_HPHP_COMMENT:
|
|
case SCE_HPHP_COMMENTLINE:
|
|
break;
|
|
default :
|
|
// check if the closing tag is a script tag
|
|
if (const char *tag =
|
|
state == SCE_HJ_COMMENTLINE || isXml ? "script" :
|
|
state == SCE_H_COMMENT ? "comment" : 0) {
|
|
Sci_Position j = i + 2;
|
|
int chr;
|
|
do {
|
|
chr = static_cast<int>(*tag++);
|
|
} while (chr != 0 && chr == MakeLowerCase(styler.SafeGetCharAt(j++)));
|
|
if (chr != 0) break;
|
|
}
|
|
// closing tag of the script (it's a closing HTML tag anyway)
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_TAGUNKNOWN;
|
|
inScriptType = eHtml;
|
|
scriptLanguage = eScriptNone;
|
|
clientScript = eScriptJS;
|
|
i += 2;
|
|
visibleChars += 2;
|
|
tagClosing = true;
|
|
if (foldXmlAtTagOpen) {
|
|
levelCurrent--;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// handle the start of PHP pre-processor = Non-HTML
|
|
else if ((state != SCE_H_ASPAT) &&
|
|
!isStringState(state) &&
|
|
(state != SCE_HPHP_COMMENT) &&
|
|
(state != SCE_HPHP_COMMENTLINE) &&
|
|
(ch == '<') &&
|
|
(chNext == '?') &&
|
|
!IsScriptCommentState(state)) {
|
|
beforeLanguage = scriptLanguage;
|
|
scriptLanguage = segIsScriptingIndicator(styler, i + 2, i + 6, isXml ? eScriptXML : eScriptPHP);
|
|
if ((scriptLanguage != eScriptPHP) && (isStringState(state) || (state==SCE_H_COMMENT))) continue;
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
beforePreProc = state;
|
|
i++;
|
|
visibleChars++;
|
|
i += PrintScriptingIndicatorOffset(styler, styler.GetStartSegment() + 2, i + 6);
|
|
if (scriptLanguage == eScriptXML)
|
|
styler.ColourTo(i, SCE_H_XMLSTART);
|
|
else
|
|
styler.ColourTo(i, SCE_H_QUESTION);
|
|
state = StateForScript(scriptLanguage);
|
|
if (inScriptType == eNonHtmlScript)
|
|
inScriptType = eNonHtmlScriptPreProc;
|
|
else
|
|
inScriptType = eNonHtmlPreProc;
|
|
// Fold whole script, but not if the XML first tag (all XML-like tags in this case)
|
|
if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) {
|
|
levelCurrent++;
|
|
}
|
|
// should be better
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
continue;
|
|
}
|
|
|
|
// handle the start Mako template Python code
|
|
else if (isMako && scriptLanguage == eScriptNone && ((ch == '<' && chNext == '%') ||
|
|
(lineStartVisibleChars == 1 && ch == '%') ||
|
|
(lineStartVisibleChars == 1 && ch == '/' && chNext == '%') ||
|
|
(ch == '$' && chNext == '{') ||
|
|
(ch == '<' && chNext == '/' && chNext2 == '%'))) {
|
|
if (ch == '%' || ch == '/')
|
|
makoBlockType = "%";
|
|
else if (ch == '$')
|
|
makoBlockType = "{";
|
|
else if (chNext == '/')
|
|
makoBlockType = GetNextWord(styler, i+3);
|
|
else
|
|
makoBlockType = GetNextWord(styler, i+2);
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
beforePreProc = state;
|
|
if (inScriptType == eNonHtmlScript)
|
|
inScriptType = eNonHtmlScriptPreProc;
|
|
else
|
|
inScriptType = eNonHtmlPreProc;
|
|
|
|
if (chNext == '/') {
|
|
i += 2;
|
|
visibleChars += 2;
|
|
} else if (ch != '%') {
|
|
i++;
|
|
visibleChars++;
|
|
}
|
|
state = SCE_HP_START;
|
|
scriptLanguage = eScriptPython;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
if (ch != '%' && ch != '$' && ch != '/') {
|
|
i += makoBlockType.length();
|
|
visibleChars += static_cast<int>(makoBlockType.length());
|
|
if (keywords4.InList(makoBlockType.c_str()))
|
|
styler.ColourTo(i, SCE_HP_WORD);
|
|
else
|
|
styler.ColourTo(i, SCE_H_TAGUNKNOWN);
|
|
}
|
|
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
continue;
|
|
}
|
|
|
|
// handle the start/end of Django comment
|
|
else if (isDjango && state != SCE_H_COMMENT && (ch == '{' && chNext == '#')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
beforePreProc = state;
|
|
beforeLanguage = scriptLanguage;
|
|
if (inScriptType == eNonHtmlScript)
|
|
inScriptType = eNonHtmlScriptPreProc;
|
|
else
|
|
inScriptType = eNonHtmlPreProc;
|
|
i += 1;
|
|
visibleChars += 1;
|
|
scriptLanguage = eScriptComment;
|
|
state = SCE_H_COMMENT;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
continue;
|
|
} else if (isDjango && state == SCE_H_COMMENT && (ch == '#' && chNext == '}')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
i += 1;
|
|
visibleChars += 1;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
state = beforePreProc;
|
|
if (inScriptType == eNonHtmlScriptPreProc)
|
|
inScriptType = eNonHtmlScript;
|
|
else
|
|
inScriptType = eHtml;
|
|
scriptLanguage = beforeLanguage;
|
|
continue;
|
|
}
|
|
|
|
// handle the start Django template code
|
|
else if (isDjango && scriptLanguage != eScriptPython && scriptLanguage != eScriptComment && (ch == '{' && (chNext == '%' || chNext == '{'))) {
|
|
if (chNext == '%')
|
|
djangoBlockType = "%";
|
|
else
|
|
djangoBlockType = "{";
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
beforePreProc = state;
|
|
if (inScriptType == eNonHtmlScript)
|
|
inScriptType = eNonHtmlScriptPreProc;
|
|
else
|
|
inScriptType = eNonHtmlPreProc;
|
|
|
|
i += 1;
|
|
visibleChars += 1;
|
|
state = SCE_HP_START;
|
|
beforeLanguage = scriptLanguage;
|
|
scriptLanguage = eScriptPython;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
continue;
|
|
}
|
|
|
|
// handle the start of ASP pre-processor = Non-HTML
|
|
else if (!isMako && !isDjango && !isCommentASPState(state) && (ch == '<') && (chNext == '%') && !isPHPStringState(state)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
beforePreProc = state;
|
|
if (inScriptType == eNonHtmlScript)
|
|
inScriptType = eNonHtmlScriptPreProc;
|
|
else
|
|
inScriptType = eNonHtmlPreProc;
|
|
|
|
if (chNext2 == '@') {
|
|
i += 2; // place as if it was the second next char treated
|
|
visibleChars += 2;
|
|
state = SCE_H_ASPAT;
|
|
} else if ((chNext2 == '-') && (styler.SafeGetCharAt(i + 3) == '-')) {
|
|
styler.ColourTo(i + 3, SCE_H_ASP);
|
|
state = SCE_H_XCCOMMENT;
|
|
scriptLanguage = eScriptVBS;
|
|
continue;
|
|
} else {
|
|
if (chNext2 == '=') {
|
|
i += 2; // place as if it was the second next char treated
|
|
visibleChars += 2;
|
|
} else {
|
|
i++; // place as if it was the next char treated
|
|
visibleChars++;
|
|
}
|
|
|
|
state = StateForScript(aspScript);
|
|
}
|
|
scriptLanguage = eScriptVBS;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
// fold whole script
|
|
if (foldHTMLPreprocessor)
|
|
levelCurrent++;
|
|
// should be better
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
continue;
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// handle the start of SGML language (DTD)
|
|
else if (((scriptLanguage == eScriptNone) || (scriptLanguage == eScriptXML)) &&
|
|
(chPrev == '<') &&
|
|
(ch == '!') &&
|
|
(StateToPrint != SCE_H_CDATA) &&
|
|
(!IsCommentState(StateToPrint)) &&
|
|
(!IsScriptCommentState(StateToPrint))) {
|
|
beforePreProc = state;
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
if ((chNext == '-') && (chNext2 == '-')) {
|
|
state = SCE_H_COMMENT; // wait for a pending command
|
|
styler.ColourTo(i + 2, SCE_H_COMMENT);
|
|
i += 2; // follow styling after the --
|
|
} else if (isWordCdata(i + 1, i + 7, styler)) {
|
|
state = SCE_H_CDATA;
|
|
} else {
|
|
styler.ColourTo(i, SCE_H_SGML_DEFAULT); // <! is default
|
|
scriptLanguage = eScriptSGML;
|
|
state = SCE_H_SGML_COMMAND; // wait for a pending command
|
|
}
|
|
// fold whole tag (-- when closing the tag)
|
|
if (foldHTMLPreprocessor || state == SCE_H_COMMENT || state == SCE_H_CDATA)
|
|
levelCurrent++;
|
|
continue;
|
|
}
|
|
|
|
// handle the end of Mako Python code
|
|
else if (isMako &&
|
|
((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) &&
|
|
(scriptLanguage != eScriptNone) && stateAllowsTermination(state) &&
|
|
isMakoBlockEnd(ch, chNext, makoBlockType)) {
|
|
if (state == SCE_H_ASPAT) {
|
|
aspScript = segIsScriptingIndicator(styler,
|
|
styler.GetStartSegment(), i - 1, aspScript);
|
|
}
|
|
if (state == SCE_HP_WORD) {
|
|
classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako);
|
|
} else {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
}
|
|
if ((makoBlockType != "%") && (makoBlockType != "{") && ch != '>') {
|
|
i++;
|
|
visibleChars++;
|
|
}
|
|
else if ((makoBlockType == "%") && ch == '/') {
|
|
i++;
|
|
visibleChars++;
|
|
}
|
|
if ((makoBlockType != "%") || ch == '/') {
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
}
|
|
state = beforePreProc;
|
|
if (inScriptType == eNonHtmlScriptPreProc)
|
|
inScriptType = eNonHtmlScript;
|
|
else
|
|
inScriptType = eHtml;
|
|
scriptLanguage = eScriptNone;
|
|
continue;
|
|
}
|
|
|
|
// handle the end of Django template code
|
|
else if (isDjango &&
|
|
((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) &&
|
|
(scriptLanguage != eScriptNone) && stateAllowsTermination(state) &&
|
|
isDjangoBlockEnd(ch, chNext, djangoBlockType)) {
|
|
if (state == SCE_H_ASPAT) {
|
|
aspScript = segIsScriptingIndicator(styler,
|
|
styler.GetStartSegment(), i - 1, aspScript);
|
|
}
|
|
if (state == SCE_HP_WORD) {
|
|
classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako);
|
|
} else {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
}
|
|
i += 1;
|
|
visibleChars += 1;
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
state = beforePreProc;
|
|
if (inScriptType == eNonHtmlScriptPreProc)
|
|
inScriptType = eNonHtmlScript;
|
|
else
|
|
inScriptType = eHtml;
|
|
scriptLanguage = beforeLanguage;
|
|
continue;
|
|
}
|
|
|
|
// handle the end of a pre-processor = Non-HTML
|
|
else if ((!isMako && !isDjango && ((inScriptType == eNonHtmlPreProc) || (inScriptType == eNonHtmlScriptPreProc)) &&
|
|
(((scriptLanguage != eScriptNone) && stateAllowsTermination(state))) &&
|
|
(((ch == '%') || (ch == '?')) && (chNext == '>'))) ||
|
|
((scriptLanguage == eScriptSGML) && (ch == '>') && (state != SCE_H_SGML_COMMENT))) {
|
|
if (state == SCE_H_ASPAT) {
|
|
aspScript = segIsScriptingIndicator(styler,
|
|
styler.GetStartSegment(), i - 1, aspScript);
|
|
}
|
|
// Bounce out of any ASP mode
|
|
switch (state) {
|
|
case SCE_HJ_WORD:
|
|
classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
|
|
break;
|
|
case SCE_HB_WORD:
|
|
classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
|
|
break;
|
|
case SCE_HP_WORD:
|
|
classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako);
|
|
break;
|
|
case SCE_HPHP_WORD:
|
|
classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
|
|
break;
|
|
case SCE_H_XCCOMMENT:
|
|
styler.ColourTo(i - 1, state);
|
|
break;
|
|
default :
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
break;
|
|
}
|
|
if (scriptLanguage != eScriptSGML) {
|
|
i++;
|
|
visibleChars++;
|
|
}
|
|
if (ch == '%')
|
|
styler.ColourTo(i, SCE_H_ASP);
|
|
else if (scriptLanguage == eScriptXML)
|
|
styler.ColourTo(i, SCE_H_XMLEND);
|
|
else if (scriptLanguage == eScriptSGML)
|
|
styler.ColourTo(i, SCE_H_SGML_DEFAULT);
|
|
else
|
|
styler.ColourTo(i, SCE_H_QUESTION);
|
|
state = beforePreProc;
|
|
if (inScriptType == eNonHtmlScriptPreProc)
|
|
inScriptType = eNonHtmlScript;
|
|
else
|
|
inScriptType = eHtml;
|
|
// Unfold all scripting languages, except for XML tag
|
|
if (foldHTMLPreprocessor && (scriptLanguage != eScriptXML)) {
|
|
levelCurrent--;
|
|
}
|
|
scriptLanguage = beforeLanguage;
|
|
continue;
|
|
}
|
|
/////////////////////////////////////
|
|
|
|
switch (state) {
|
|
case SCE_H_DEFAULT:
|
|
if (ch == '<') {
|
|
// in HTML, fold on tag open and unfold on tag close
|
|
tagOpened = true;
|
|
tagClosing = (chNext == '/');
|
|
if (foldXmlAtTagOpen && !(chNext == '/' || chNext == '?' || chNext == '!' || chNext == '-' || chNext == '%')) {
|
|
levelCurrent++;
|
|
}
|
|
if (foldXmlAtTagOpen && chNext == '/') {
|
|
levelCurrent--;
|
|
}
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (chNext != '!')
|
|
state = SCE_H_TAGUNKNOWN;
|
|
} else if (ch == '&') {
|
|
styler.ColourTo(i - 1, SCE_H_DEFAULT);
|
|
state = SCE_H_ENTITY;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_DEFAULT:
|
|
case SCE_H_SGML_BLOCK_DEFAULT:
|
|
// if (scriptLanguage == eScriptSGMLblock)
|
|
// StateToPrint = SCE_H_SGML_BLOCK_DEFAULT;
|
|
|
|
if (ch == '\"') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_SGML_DOUBLESTRING;
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_SGML_SIMPLESTRING;
|
|
} else if ((ch == '-') && (chPrev == '-')) {
|
|
if (static_cast<Sci_Position>(styler.GetStartSegment()) <= (i - 2)) {
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
}
|
|
state = SCE_H_SGML_COMMENT;
|
|
} else if (IsASCII(ch) && isalpha(ch) && (chPrev == '%')) {
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
state = SCE_H_SGML_ENTITY;
|
|
} else if (ch == '#') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_SGML_SPECIAL;
|
|
} else if (ch == '[') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
scriptLanguage = eScriptSGMLblock;
|
|
state = SCE_H_SGML_BLOCK_DEFAULT;
|
|
} else if (ch == ']') {
|
|
if (scriptLanguage == eScriptSGMLblock) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
scriptLanguage = eScriptSGML;
|
|
} else {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, SCE_H_SGML_ERROR);
|
|
}
|
|
state = SCE_H_SGML_DEFAULT;
|
|
} else if (scriptLanguage == eScriptSGMLblock) {
|
|
if ((ch == '!') && (chPrev == '<')) {
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
styler.ColourTo(i, SCE_H_SGML_DEFAULT);
|
|
state = SCE_H_SGML_COMMAND;
|
|
} else if (ch == '>') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, SCE_H_SGML_DEFAULT);
|
|
}
|
|
}
|
|
break;
|
|
case SCE_H_SGML_COMMAND:
|
|
if ((ch == '-') && (chPrev == '-')) {
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
state = SCE_H_SGML_COMMENT;
|
|
} else if (!issgmlwordchar(ch)) {
|
|
if (isWordHSGML(styler.GetStartSegment(), i - 1, keywords6, styler)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_SGML_1ST_PARAM;
|
|
} else {
|
|
state = SCE_H_SGML_ERROR;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_H_SGML_1ST_PARAM:
|
|
// wait for the beginning of the word
|
|
if ((ch == '-') && (chPrev == '-')) {
|
|
if (scriptLanguage == eScriptSGMLblock) {
|
|
styler.ColourTo(i - 2, SCE_H_SGML_BLOCK_DEFAULT);
|
|
} else {
|
|
styler.ColourTo(i - 2, SCE_H_SGML_DEFAULT);
|
|
}
|
|
state = SCE_H_SGML_1ST_PARAM_COMMENT;
|
|
} else if (issgmlwordchar(ch)) {
|
|
if (scriptLanguage == eScriptSGMLblock) {
|
|
styler.ColourTo(i - 1, SCE_H_SGML_BLOCK_DEFAULT);
|
|
} else {
|
|
styler.ColourTo(i - 1, SCE_H_SGML_DEFAULT);
|
|
}
|
|
// find the length of the word
|
|
int size = 1;
|
|
while (setHTMLWord.Contains(static_cast<unsigned char>(styler.SafeGetCharAt(i + size))))
|
|
size++;
|
|
styler.ColourTo(i + size - 1, StateToPrint);
|
|
i += size - 1;
|
|
visibleChars += size - 1;
|
|
ch = static_cast<unsigned char>(styler.SafeGetCharAt(i));
|
|
if (scriptLanguage == eScriptSGMLblock) {
|
|
state = SCE_H_SGML_BLOCK_DEFAULT;
|
|
} else {
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
continue;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_ERROR:
|
|
if ((ch == '-') && (chPrev == '-')) {
|
|
styler.ColourTo(i - 2, StateToPrint);
|
|
state = SCE_H_SGML_COMMENT;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_DOUBLESTRING:
|
|
if (ch == '\"') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_SIMPLESTRING:
|
|
if (ch == '\'') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_COMMENT:
|
|
if ((ch == '-') && (chPrev == '-')) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_H_CDATA:
|
|
if ((chPrev2 == ']') && (chPrev == ']') && (ch == '>')) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_DEFAULT;
|
|
levelCurrent--;
|
|
}
|
|
break;
|
|
case SCE_H_COMMENT:
|
|
if ((scriptLanguage != eScriptComment) && (chPrev2 == '-') && (chPrev == '-') && (ch == '>')) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_DEFAULT;
|
|
levelCurrent--;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_1ST_PARAM_COMMENT:
|
|
if ((ch == '-') && (chPrev == '-')) {
|
|
styler.ColourTo(i, SCE_H_SGML_COMMENT);
|
|
state = SCE_H_SGML_1ST_PARAM;
|
|
}
|
|
break;
|
|
case SCE_H_SGML_SPECIAL:
|
|
if (!(IsASCII(ch) && isupper(ch))) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (isalnum(ch)) {
|
|
state = SCE_H_SGML_ERROR;
|
|
} else {
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_H_SGML_ENTITY:
|
|
if (ch == ';') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_SGML_DEFAULT;
|
|
} else if (!(IsASCII(ch) && isalnum(ch)) && ch != '-' && ch != '.') {
|
|
styler.ColourTo(i, SCE_H_SGML_ERROR);
|
|
state = SCE_H_SGML_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_H_ENTITY:
|
|
if (ch == ';') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
if (ch != '#' && !(IsASCII(ch) && isalnum(ch)) // Should check that '#' follows '&', but it is unlikely anyway...
|
|
&& ch != '.' && ch != '-' && ch != '_' && ch != ':') { // valid in XML
|
|
if (!IsASCII(ch)) // Possibly start of a multibyte character so don't allow this byte to be in entity style
|
|
styler.ColourTo(i-1, SCE_H_TAGUNKNOWN);
|
|
else
|
|
styler.ColourTo(i, SCE_H_TAGUNKNOWN);
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_H_TAGUNKNOWN:
|
|
if (!setTagContinue.Contains(ch) && !((ch == '/') && (chPrev == '<'))) {
|
|
int eClass = classifyTagHTML(styler.GetStartSegment(),
|
|
i - 1, keywords, styler, tagDontFold, caseSensitive, isXml, allowScripts, nonFoldingTags);
|
|
if (eClass == SCE_H_SCRIPT || eClass == SCE_H_COMMENT) {
|
|
if (!tagClosing) {
|
|
inScriptType = eNonHtmlScript;
|
|
scriptLanguage = eClass == SCE_H_SCRIPT ? clientScript : eScriptComment;
|
|
} else {
|
|
scriptLanguage = eScriptNone;
|
|
}
|
|
eClass = SCE_H_TAG;
|
|
}
|
|
if (ch == '>') {
|
|
styler.ColourTo(i, eClass);
|
|
if (inScriptType == eNonHtmlScript) {
|
|
state = StateForScript(scriptLanguage);
|
|
} else {
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
tagOpened = false;
|
|
if (!(foldXmlAtTagOpen || tagDontFold)) {
|
|
if (tagClosing) {
|
|
levelCurrent--;
|
|
} else {
|
|
levelCurrent++;
|
|
}
|
|
}
|
|
tagClosing = false;
|
|
} else if (ch == '/' && chNext == '>') {
|
|
if (eClass == SCE_H_TAGUNKNOWN) {
|
|
styler.ColourTo(i + 1, SCE_H_TAGUNKNOWN);
|
|
} else {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i + 1, SCE_H_TAGEND);
|
|
}
|
|
i++;
|
|
ch = chNext;
|
|
state = SCE_H_DEFAULT;
|
|
tagOpened = false;
|
|
if (foldXmlAtTagOpen) {
|
|
levelCurrent--;
|
|
}
|
|
} else {
|
|
if (eClass != SCE_H_TAGUNKNOWN) {
|
|
if (eClass == SCE_H_SGML_DEFAULT) {
|
|
state = SCE_H_SGML_DEFAULT;
|
|
} else {
|
|
state = SCE_H_OTHER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCE_H_ATTRIBUTE:
|
|
if (!setAttributeContinue.Contains(ch)) {
|
|
if (inScriptType == eNonHtmlScript) {
|
|
const int scriptLanguagePrev = scriptLanguage;
|
|
clientScript = segIsScriptingIndicator(styler, styler.GetStartSegment(), i - 1, scriptLanguage);
|
|
scriptLanguage = clientScript;
|
|
if ((scriptLanguagePrev != scriptLanguage) && (scriptLanguage == eScriptNone))
|
|
inScriptType = eHtml;
|
|
}
|
|
classifyAttribHTML(styler.GetStartSegment(), i - 1, keywords, styler);
|
|
if (ch == '>') {
|
|
styler.ColourTo(i, SCE_H_TAG);
|
|
if (inScriptType == eNonHtmlScript) {
|
|
state = StateForScript(scriptLanguage);
|
|
} else {
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
tagOpened = false;
|
|
if (!(foldXmlAtTagOpen || tagDontFold)) {
|
|
if (tagClosing) {
|
|
levelCurrent--;
|
|
} else {
|
|
levelCurrent++;
|
|
}
|
|
}
|
|
tagClosing = false;
|
|
} else if (ch == '=') {
|
|
styler.ColourTo(i, SCE_H_OTHER);
|
|
state = SCE_H_VALUE;
|
|
} else {
|
|
state = SCE_H_OTHER;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_H_OTHER:
|
|
if (ch == '>') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, SCE_H_TAG);
|
|
if (inScriptType == eNonHtmlScript) {
|
|
state = StateForScript(scriptLanguage);
|
|
} else {
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
tagOpened = false;
|
|
if (!(foldXmlAtTagOpen || tagDontFold)) {
|
|
if (tagClosing) {
|
|
levelCurrent--;
|
|
} else {
|
|
levelCurrent++;
|
|
}
|
|
}
|
|
tagClosing = false;
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_DOUBLESTRING;
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_SINGLESTRING;
|
|
} else if (ch == '=') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_H_VALUE;
|
|
} else if (ch == '/' && chNext == '>') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i + 1, SCE_H_TAGEND);
|
|
i++;
|
|
ch = chNext;
|
|
state = SCE_H_DEFAULT;
|
|
tagOpened = false;
|
|
if (foldXmlAtTagOpen) {
|
|
levelCurrent--;
|
|
}
|
|
} else if (ch == '?' && chNext == '>') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i + 1, SCE_H_XMLEND);
|
|
i++;
|
|
ch = chNext;
|
|
state = SCE_H_DEFAULT;
|
|
} else if (setHTMLWord.Contains(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_H_ATTRIBUTE;
|
|
}
|
|
break;
|
|
case SCE_H_DOUBLESTRING:
|
|
if (ch == '\"') {
|
|
if (inScriptType == eNonHtmlScript) {
|
|
scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
|
|
}
|
|
styler.ColourTo(i, SCE_H_DOUBLESTRING);
|
|
state = SCE_H_OTHER;
|
|
}
|
|
break;
|
|
case SCE_H_SINGLESTRING:
|
|
if (ch == '\'') {
|
|
if (inScriptType == eNonHtmlScript) {
|
|
scriptLanguage = segIsScriptingIndicator(styler, styler.GetStartSegment(), i, scriptLanguage);
|
|
}
|
|
styler.ColourTo(i, SCE_H_SINGLESTRING);
|
|
state = SCE_H_OTHER;
|
|
}
|
|
break;
|
|
case SCE_H_VALUE:
|
|
if (!setHTMLWord.Contains(ch)) {
|
|
if (ch == '\"' && chPrev == '=') {
|
|
// Should really test for being first character
|
|
state = SCE_H_DOUBLESTRING;
|
|
} else if (ch == '\'' && chPrev == '=') {
|
|
state = SCE_H_SINGLESTRING;
|
|
} else {
|
|
if (IsNumber(styler.GetStartSegment(), styler)) {
|
|
styler.ColourTo(i - 1, SCE_H_NUMBER);
|
|
} else {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
}
|
|
if (ch == '>') {
|
|
styler.ColourTo(i, SCE_H_TAG);
|
|
if (inScriptType == eNonHtmlScript) {
|
|
state = StateForScript(scriptLanguage);
|
|
} else {
|
|
state = SCE_H_DEFAULT;
|
|
}
|
|
tagOpened = false;
|
|
if (!tagDontFold) {
|
|
if (tagClosing) {
|
|
levelCurrent--;
|
|
} else {
|
|
levelCurrent++;
|
|
}
|
|
}
|
|
tagClosing = false;
|
|
} else {
|
|
state = SCE_H_OTHER;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HJ_DEFAULT:
|
|
case SCE_HJ_START:
|
|
case SCE_HJ_SYMBOLS:
|
|
if (IsAWordStart(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_WORD;
|
|
} else if (ch == '/' && chNext == '*') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (chNext2 == '*')
|
|
state = SCE_HJ_COMMENTDOC;
|
|
else
|
|
state = SCE_HJ_COMMENT;
|
|
if (chNext2 == '/') {
|
|
// Eat the * so it isn't used for the end of the comment
|
|
i++;
|
|
}
|
|
} else if (ch == '/' && chNext == '/') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
} else if (ch == '/' && setOKBeforeJSRE.Contains(chPrevNonWhite)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_REGEX;
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_DOUBLESTRING;
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_SINGLESTRING;
|
|
} else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
|
|
styler.SafeGetCharAt(i + 3) == '-') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
} else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
i += 2;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
|
|
state = SCE_HJ_DEFAULT;
|
|
} else if ((ch == ' ') || (ch == '\t')) {
|
|
if (state == SCE_HJ_START) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HJ_WORD:
|
|
if (!IsAWordChar(ch)) {
|
|
classifyWordHTJS(styler.GetStartSegment(), i - 1, keywords2, styler, inScriptType);
|
|
//styler.ColourTo(i - 1, eHTJSKeyword);
|
|
state = SCE_HJ_DEFAULT;
|
|
if (ch == '/' && chNext == '*') {
|
|
if (chNext2 == '*')
|
|
state = SCE_HJ_COMMENTDOC;
|
|
else
|
|
state = SCE_HJ_COMMENT;
|
|
} else if (ch == '/' && chNext == '/') {
|
|
state = SCE_HJ_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
state = SCE_HJ_DOUBLESTRING;
|
|
} else if (ch == '\'') {
|
|
state = SCE_HJ_SINGLESTRING;
|
|
} else if ((ch == '-') && (chNext == '-') && (chNext2 == '>')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
i += 2;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
|
|
state = SCE_HJ_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HJ_COMMENT:
|
|
case SCE_HJ_COMMENTDOC:
|
|
if (ch == '/' && chPrev == '*') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HJ_DEFAULT;
|
|
ch = ' ';
|
|
}
|
|
break;
|
|
case SCE_HJ_COMMENTLINE:
|
|
if (ch == '\r' || ch == '\n') {
|
|
styler.ColourTo(i - 1, statePrintForState(SCE_HJ_COMMENTLINE, inScriptType));
|
|
state = SCE_HJ_DEFAULT;
|
|
ch = ' ';
|
|
}
|
|
break;
|
|
case SCE_HJ_DOUBLESTRING:
|
|
if (ch == '\\') {
|
|
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
|
|
i++;
|
|
}
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i, statePrintForState(SCE_HJ_DOUBLESTRING, inScriptType));
|
|
state = SCE_HJ_DEFAULT;
|
|
} else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
i += 2;
|
|
} else if (isLineEnd(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_STRINGEOL;
|
|
}
|
|
break;
|
|
case SCE_HJ_SINGLESTRING:
|
|
if (ch == '\\') {
|
|
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
|
|
i++;
|
|
}
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i, statePrintForState(SCE_HJ_SINGLESTRING, inScriptType));
|
|
state = SCE_HJ_DEFAULT;
|
|
} else if ((inScriptType == eNonHtmlScript) && (ch == '-') && (chNext == '-') && (chNext2 == '>')) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_COMMENTLINE;
|
|
i += 2;
|
|
} else if (isLineEnd(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (chPrev != '\\' && (chPrev2 != '\\' || chPrev != '\r' || ch != '\n')) {
|
|
state = SCE_HJ_STRINGEOL;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HJ_STRINGEOL:
|
|
if (!isLineEnd(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HJ_DEFAULT;
|
|
} else if (!isLineEnd(chNext)) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HJ_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HJ_REGEX:
|
|
if (ch == '\r' || ch == '\n' || ch == '/') {
|
|
if (ch == '/') {
|
|
while (IsASCII(chNext) && islower(chNext)) { // gobble regex flags
|
|
i++;
|
|
ch = chNext;
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
}
|
|
}
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HJ_DEFAULT;
|
|
} else if (ch == '\\') {
|
|
// Gobble up the quoted character
|
|
if (chNext == '\\' || chNext == '/') {
|
|
i++;
|
|
ch = chNext;
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HB_DEFAULT:
|
|
case SCE_HB_START:
|
|
if (IsAWordStart(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_WORD;
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_STRING;
|
|
} else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
|
|
styler.SafeGetCharAt(i + 3) == '-') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_COMMENTLINE;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
|
|
state = SCE_HB_DEFAULT;
|
|
} else if ((ch == ' ') || (ch == '\t')) {
|
|
if (state == SCE_HB_START) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HB_WORD:
|
|
if (!IsAWordChar(ch)) {
|
|
state = classifyWordHTVB(styler.GetStartSegment(), i - 1, keywords3, styler, inScriptType);
|
|
if (state == SCE_HB_DEFAULT) {
|
|
if (ch == '\"') {
|
|
state = SCE_HB_STRING;
|
|
} else if (ch == '\'') {
|
|
state = SCE_HB_COMMENTLINE;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, statePrintForState(SCE_HB_DEFAULT, inScriptType));
|
|
state = SCE_HB_DEFAULT;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HB_STRING:
|
|
if (ch == '\"') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HB_DEFAULT;
|
|
} else if (ch == '\r' || ch == '\n') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_STRINGEOL;
|
|
}
|
|
break;
|
|
case SCE_HB_COMMENTLINE:
|
|
if (ch == '\r' || ch == '\n') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HB_STRINGEOL:
|
|
if (!isLineEnd(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HB_DEFAULT;
|
|
} else if (!isLineEnd(chNext)) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HB_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HP_DEFAULT:
|
|
case SCE_HP_START:
|
|
if (IsAWordStart(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HP_WORD;
|
|
} else if ((ch == '<') && (chNext == '!') && (chNext2 == '-') &&
|
|
styler.SafeGetCharAt(i + 3) == '-') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HP_COMMENTLINE;
|
|
} else if (ch == '#') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HP_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (chNext == '\"' && chNext2 == '\"') {
|
|
i += 2;
|
|
state = SCE_HP_TRIPLEDOUBLE;
|
|
ch = ' ';
|
|
chPrev = ' ';
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
} else {
|
|
// state = statePrintForState(SCE_HP_STRING,inScriptType);
|
|
state = SCE_HP_STRING;
|
|
}
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (chNext == '\'' && chNext2 == '\'') {
|
|
i += 2;
|
|
state = SCE_HP_TRIPLE;
|
|
ch = ' ';
|
|
chPrev = ' ';
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
} else {
|
|
state = SCE_HP_CHARACTER;
|
|
}
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
|
|
} else if ((ch == ' ') || (ch == '\t')) {
|
|
if (state == SCE_HP_START) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HP_WORD:
|
|
if (!IsAWordChar(ch)) {
|
|
classifyWordHTPy(styler.GetStartSegment(), i - 1, keywords4, styler, prevWord, inScriptType, isMako);
|
|
state = SCE_HP_DEFAULT;
|
|
if (ch == '#') {
|
|
state = SCE_HP_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
if (chNext == '\"' && chNext2 == '\"') {
|
|
i += 2;
|
|
state = SCE_HP_TRIPLEDOUBLE;
|
|
ch = ' ';
|
|
chPrev = ' ';
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
} else {
|
|
state = SCE_HP_STRING;
|
|
}
|
|
} else if (ch == '\'') {
|
|
if (chNext == '\'' && chNext2 == '\'') {
|
|
i += 2;
|
|
state = SCE_HP_TRIPLE;
|
|
ch = ' ';
|
|
chPrev = ' ';
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
} else {
|
|
state = SCE_HP_CHARACTER;
|
|
}
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, statePrintForState(SCE_HP_OPERATOR, inScriptType));
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HP_COMMENTLINE:
|
|
if (ch == '\r' || ch == '\n') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HP_STRING:
|
|
if (ch == '\\') {
|
|
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
|
|
i++;
|
|
ch = chNext;
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
}
|
|
} else if (ch == '\"') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HP_CHARACTER:
|
|
if (ch == '\\') {
|
|
if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
|
|
i++;
|
|
ch = chNext;
|
|
chNext = static_cast<unsigned char>(styler.SafeGetCharAt(i + 1));
|
|
}
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HP_TRIPLE:
|
|
if (ch == '\'' && chPrev == '\'' && chPrev2 == '\'') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HP_TRIPLEDOUBLE:
|
|
if (ch == '\"' && chPrev == '\"' && chPrev2 == '\"') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HP_DEFAULT;
|
|
}
|
|
break;
|
|
///////////// start - PHP state handling
|
|
case SCE_HPHP_WORD:
|
|
if (!IsAWordChar(ch)) {
|
|
classifyWordHTPHP(styler.GetStartSegment(), i - 1, keywords5, styler);
|
|
if (ch == '/' && chNext == '*') {
|
|
i++;
|
|
state = SCE_HPHP_COMMENT;
|
|
} else if (ch == '/' && chNext == '/') {
|
|
i++;
|
|
state = SCE_HPHP_COMMENTLINE;
|
|
} else if (ch == '#') {
|
|
state = SCE_HPHP_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
state = SCE_HPHP_HSTRING;
|
|
phpStringDelimiter = "\"";
|
|
} else if (styler.Match(i, "<<<")) {
|
|
bool isSimpleString = false;
|
|
i = FindPhpStringDelimiter(phpStringDelimiter, i + 3, lengthDoc, styler, isSimpleString);
|
|
if (!phpStringDelimiter.empty()) {
|
|
state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING);
|
|
if (foldHeredoc) levelCurrent++;
|
|
}
|
|
} else if (ch == '\'') {
|
|
state = SCE_HPHP_SIMPLESTRING;
|
|
phpStringDelimiter = "\'";
|
|
} else if (ch == '$' && IsPhpWordStart(chNext)) {
|
|
state = SCE_HPHP_VARIABLE;
|
|
} else if (IsOperator(ch)) {
|
|
state = SCE_HPHP_OPERATOR;
|
|
} else {
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HPHP_NUMBER:
|
|
// recognize bases 8,10 or 16 integers OR floating-point numbers
|
|
if (!IsADigit(ch)
|
|
&& strchr(".xXabcdefABCDEF", ch) == NULL
|
|
&& ((ch != '-' && ch != '+') || (chPrev != 'e' && chPrev != 'E'))) {
|
|
styler.ColourTo(i - 1, SCE_HPHP_NUMBER);
|
|
if (IsOperator(ch))
|
|
state = SCE_HPHP_OPERATOR;
|
|
else
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HPHP_VARIABLE:
|
|
if (!IsPhpWordChar(chNext)) {
|
|
styler.ColourTo(i, SCE_HPHP_VARIABLE);
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HPHP_COMMENT:
|
|
if (ch == '/' && chPrev == '*') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HPHP_COMMENTLINE:
|
|
if (ch == '\r' || ch == '\n') {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
break;
|
|
case SCE_HPHP_HSTRING:
|
|
if (ch == '\\' && ((phpStringDelimiter == "\"") || chNext == '$' || chNext == '{')) {
|
|
// skip the next char
|
|
i++;
|
|
} else if (((ch == '{' && chNext == '$') || (ch == '$' && chNext == '{'))
|
|
&& IsPhpWordStart(chNext2)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HPHP_COMPLEX_VARIABLE;
|
|
} else if (ch == '$' && IsPhpWordStart(chNext)) {
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
state = SCE_HPHP_HSTRING_VARIABLE;
|
|
} else if (styler.Match(i, phpStringDelimiter.c_str())) {
|
|
if (phpStringDelimiter == "\"") {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
} else if (isLineEnd(chPrev)) {
|
|
const int psdLength = static_cast<int>(phpStringDelimiter.length());
|
|
const char chAfterPsd = styler.SafeGetCharAt(i + psdLength);
|
|
const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1);
|
|
if (isLineEnd(chAfterPsd) ||
|
|
(chAfterPsd == ';' && isLineEnd(chAfterPsd2))) {
|
|
i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1;
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
if (foldHeredoc) levelCurrent--;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HPHP_SIMPLESTRING:
|
|
if (phpStringDelimiter == "\'") {
|
|
if (ch == '\\') {
|
|
// skip the next char
|
|
i++;
|
|
} else if (ch == '\'') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
} else if (isLineEnd(chPrev) && styler.Match(i, phpStringDelimiter.c_str())) {
|
|
const int psdLength = static_cast<int>(phpStringDelimiter.length());
|
|
const char chAfterPsd = styler.SafeGetCharAt(i + psdLength);
|
|
const char chAfterPsd2 = styler.SafeGetCharAt(i + psdLength + 1);
|
|
if (isLineEnd(chAfterPsd) ||
|
|
(chAfterPsd == ';' && isLineEnd(chAfterPsd2))) {
|
|
i += (((i + psdLength) < lengthDoc) ? psdLength : lengthDoc) - 1;
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_DEFAULT;
|
|
if (foldHeredoc) levelCurrent--;
|
|
}
|
|
}
|
|
break;
|
|
case SCE_HPHP_HSTRING_VARIABLE:
|
|
if (!IsPhpWordChar(chNext)) {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_HSTRING;
|
|
}
|
|
break;
|
|
case SCE_HPHP_COMPLEX_VARIABLE:
|
|
if (ch == '}') {
|
|
styler.ColourTo(i, StateToPrint);
|
|
state = SCE_HPHP_HSTRING;
|
|
}
|
|
break;
|
|
case SCE_HPHP_OPERATOR:
|
|
case SCE_HPHP_DEFAULT:
|
|
styler.ColourTo(i - 1, StateToPrint);
|
|
if (IsADigit(ch) || (ch == '.' && IsADigit(chNext))) {
|
|
state = SCE_HPHP_NUMBER;
|
|
} else if (IsAWordStart(ch)) {
|
|
state = SCE_HPHP_WORD;
|
|
} else if (ch == '/' && chNext == '*') {
|
|
i++;
|
|
state = SCE_HPHP_COMMENT;
|
|
} else if (ch == '/' && chNext == '/') {
|
|
i++;
|
|
state = SCE_HPHP_COMMENTLINE;
|
|
} else if (ch == '#') {
|
|
state = SCE_HPHP_COMMENTLINE;
|
|
} else if (ch == '\"') {
|
|
state = SCE_HPHP_HSTRING;
|
|
phpStringDelimiter = "\"";
|
|
} else if (styler.Match(i, "<<<")) {
|
|
bool isSimpleString = false;
|
|
i = FindPhpStringDelimiter(phpStringDelimiter, i + 3, lengthDoc, styler, isSimpleString);
|
|
if (!phpStringDelimiter.empty()) {
|
|
state = (isSimpleString ? SCE_HPHP_SIMPLESTRING : SCE_HPHP_HSTRING);
|
|
if (foldHeredoc) levelCurrent++;
|
|
}
|
|
} else if (ch == '\'') {
|
|
state = SCE_HPHP_SIMPLESTRING;
|
|
phpStringDelimiter = "\'";
|
|
} else if (ch == '$' && IsPhpWordStart(chNext)) {
|
|
state = SCE_HPHP_VARIABLE;
|
|
} else if (IsOperator(ch)) {
|
|
state = SCE_HPHP_OPERATOR;
|
|
} else if ((state == SCE_HPHP_OPERATOR) && (IsASpace(ch))) {
|
|
state = SCE_HPHP_DEFAULT;
|
|
}
|
|
break;
|
|
///////////// end - PHP state handling
|
|
}
|
|
|
|
// Some of the above terminated their lexeme but since the same character starts
|
|
// the same class again, only reenter if non empty segment.
|
|
|
|
const bool nonEmptySegment = i >= static_cast<Sci_Position>(styler.GetStartSegment());
|
|
if (state == SCE_HB_DEFAULT) { // One of the above succeeded
|
|
if ((ch == '\"') && (nonEmptySegment)) {
|
|
state = SCE_HB_STRING;
|
|
} else if (ch == '\'') {
|
|
state = SCE_HB_COMMENTLINE;
|
|
} else if (IsAWordStart(ch)) {
|
|
state = SCE_HB_WORD;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, SCE_HB_DEFAULT);
|
|
}
|
|
} else if (state == SCE_HBA_DEFAULT) { // One of the above succeeded
|
|
if ((ch == '\"') && (nonEmptySegment)) {
|
|
state = SCE_HBA_STRING;
|
|
} else if (ch == '\'') {
|
|
state = SCE_HBA_COMMENTLINE;
|
|
} else if (IsAWordStart(ch)) {
|
|
state = SCE_HBA_WORD;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, SCE_HBA_DEFAULT);
|
|
}
|
|
} else if (state == SCE_HJ_DEFAULT) { // One of the above succeeded
|
|
if (ch == '/' && chNext == '*') {
|
|
if (styler.SafeGetCharAt(i + 2) == '*')
|
|
state = SCE_HJ_COMMENTDOC;
|
|
else
|
|
state = SCE_HJ_COMMENT;
|
|
} else if (ch == '/' && chNext == '/') {
|
|
state = SCE_HJ_COMMENTLINE;
|
|
} else if ((ch == '\"') && (nonEmptySegment)) {
|
|
state = SCE_HJ_DOUBLESTRING;
|
|
} else if ((ch == '\'') && (nonEmptySegment)) {
|
|
state = SCE_HJ_SINGLESTRING;
|
|
} else if (IsAWordStart(ch)) {
|
|
state = SCE_HJ_WORD;
|
|
} else if (IsOperator(ch)) {
|
|
styler.ColourTo(i, statePrintForState(SCE_HJ_SYMBOLS, inScriptType));
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (state) {
|
|
case SCE_HJ_WORD:
|
|
classifyWordHTJS(styler.GetStartSegment(), lengthDoc - 1, keywords2, styler, inScriptType);
|
|
break;
|
|
case SCE_HB_WORD:
|
|
classifyWordHTVB(styler.GetStartSegment(), lengthDoc - 1, keywords3, styler, inScriptType);
|
|
break;
|
|
case SCE_HP_WORD:
|
|
classifyWordHTPy(styler.GetStartSegment(), lengthDoc - 1, keywords4, styler, prevWord, inScriptType, isMako);
|
|
break;
|
|
case SCE_HPHP_WORD:
|
|
classifyWordHTPHP(styler.GetStartSegment(), lengthDoc - 1, keywords5, styler);
|
|
break;
|
|
default:
|
|
StateToPrint = statePrintForState(state, inScriptType);
|
|
if (static_cast<Sci_Position>(styler.GetStartSegment()) < lengthDoc)
|
|
styler.ColourTo(lengthDoc - 1, StateToPrint);
|
|
break;
|
|
}
|
|
|
|
// Fill in the real level of the next line, keeping the current flags as they will be filled in later
|
|
if (fold) {
|
|
const int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
|
|
styler.SetLevel(lineCurrent, levelPrev | flagsNext);
|
|
}
|
|
styler.Flush();
|
|
}
|
|
|
|
LexerModule lmHTML(SCLEX_HTML, LexerHTML::LexerFactoryHTML, "hypertext", htmlWordListDesc);
|
|
LexerModule lmXML(SCLEX_XML, LexerHTML::LexerFactoryXML, "xml", htmlWordListDesc);
|
|
LexerModule lmPHPSCRIPT(SCLEX_PHPSCRIPT, LexerHTML::LexerFactoryPHPScript, "phpscript", phpscriptWordListDesc);
|