1 // Scintilla source code edit control
2 /** @file LexESCRIPT.cxx
5 // Copyright 2003 by Patrizio Bekerle (patrizio@bekerle.com)
15 #include "Scintilla.h"
19 #include "LexAccessor.h"
21 #include "StyleContext.h"
22 #include "CharacterSet.h"
23 #include "LexerModule.h"
25 using namespace Scintilla
;
28 static inline bool IsAWordChar(const int ch
) {
29 return (ch
< 0x80) && (isalnum(ch
) || ch
== '.' || ch
== '_');
32 static inline bool IsAWordStart(const int ch
) {
33 return (ch
< 0x80) && (isalnum(ch
) || ch
== '_');
38 static void ColouriseESCRIPTDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*keywordlists
[],
41 WordList
&keywords
= *keywordlists
[0];
42 WordList
&keywords2
= *keywordlists
[1];
43 WordList
&keywords3
= *keywordlists
[2];
45 // Do not leak onto next line
46 /*if (initStyle == SCE_ESCRIPT_STRINGEOL)
47 initStyle = SCE_ESCRIPT_DEFAULT;*/
49 StyleContext
sc(startPos
, length
, initStyle
, styler
);
51 bool caseSensitive
= styler
.GetPropertyInt("escript.case.sensitive", 0) != 0;
53 for (; sc
.More(); sc
.Forward()) {
55 /*if (sc.atLineStart && (sc.state == SCE_ESCRIPT_STRING)) {
56 // Prevent SCE_ESCRIPT_STRINGEOL from leaking back to previous line
57 sc.SetState(SCE_ESCRIPT_STRING);
60 // Handle line continuation generically.
62 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
64 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
71 // Determine if the current state should terminate.
72 if (sc
.state
== SCE_ESCRIPT_OPERATOR
|| sc
.state
== SCE_ESCRIPT_BRACE
) {
73 sc
.SetState(SCE_ESCRIPT_DEFAULT
);
74 } else if (sc
.state
== SCE_ESCRIPT_NUMBER
) {
75 if (!IsADigit(sc
.ch
) || sc
.ch
!= '.') {
76 sc
.SetState(SCE_ESCRIPT_DEFAULT
);
78 } else if (sc
.state
== SCE_ESCRIPT_IDENTIFIER
) {
79 if (!IsAWordChar(sc
.ch
) || (sc
.ch
== '.')) {
82 sc
.GetCurrent(s
, sizeof(s
));
84 sc
.GetCurrentLowered(s
, sizeof(s
));
87 // sc.GetCurrentLowered(s, sizeof(s));
89 if (keywords
.InList(s
)) {
90 sc
.ChangeState(SCE_ESCRIPT_WORD
);
91 } else if (keywords2
.InList(s
)) {
92 sc
.ChangeState(SCE_ESCRIPT_WORD2
);
93 } else if (keywords3
.InList(s
)) {
94 sc
.ChangeState(SCE_ESCRIPT_WORD3
);
95 // sc.state = SCE_ESCRIPT_IDENTIFIER;
97 sc
.SetState(SCE_ESCRIPT_DEFAULT
);
99 } else if (sc
.state
== SCE_ESCRIPT_COMMENT
) {
100 if (sc
.Match('*', '/')) {
102 sc
.ForwardSetState(SCE_ESCRIPT_DEFAULT
);
104 } else if (sc
.state
== SCE_ESCRIPT_COMMENTDOC
) {
105 if (sc
.Match('*', '/')) {
107 sc
.ForwardSetState(SCE_ESCRIPT_DEFAULT
);
109 } else if (sc
.state
== SCE_ESCRIPT_COMMENTLINE
) {
111 sc
.SetState(SCE_ESCRIPT_DEFAULT
);
113 } else if (sc
.state
== SCE_ESCRIPT_STRING
) {
115 if (sc
.chNext
== '\"' || sc
.chNext
== '\\') {
118 } else if (sc
.ch
== '\"') {
119 sc
.ForwardSetState(SCE_ESCRIPT_DEFAULT
);
123 // Determine if a new state should be entered.
124 if (sc
.state
== SCE_ESCRIPT_DEFAULT
) {
125 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
126 sc
.SetState(SCE_ESCRIPT_NUMBER
);
127 } else if (IsAWordStart(sc
.ch
) || (sc
.ch
== '#')) {
128 sc
.SetState(SCE_ESCRIPT_IDENTIFIER
);
129 } else if (sc
.Match('/', '*')) {
130 sc
.SetState(SCE_ESCRIPT_COMMENT
);
131 sc
.Forward(); // Eat the * so it isn't used for the end of the comment
132 } else if (sc
.Match('/', '/')) {
133 sc
.SetState(SCE_ESCRIPT_COMMENTLINE
);
134 } else if (sc
.ch
== '\"') {
135 sc
.SetState(SCE_ESCRIPT_STRING
);
136 //} else if (isoperator(static_cast<char>(sc.ch))) {
137 } else if (sc
.ch
== '+' || sc
.ch
== '-' || sc
.ch
== '*' || sc
.ch
== '/' || sc
.ch
== '=' || sc
.ch
== '<' || sc
.ch
== '>' || sc
.ch
== '&' || sc
.ch
== '|' || sc
.ch
== '!' || sc
.ch
== '?' || sc
.ch
== ':') {
138 sc
.SetState(SCE_ESCRIPT_OPERATOR
);
139 } else if (sc
.ch
== '{' || sc
.ch
== '}') {
140 sc
.SetState(SCE_ESCRIPT_BRACE
);
149 static int classifyFoldPointESCRIPT(const char* s
, const char* prevWord
) {
151 if (strcmp(prevWord
, "end") == 0) return lev
;
152 if ((strcmp(prevWord
, "else") == 0 && strcmp(s
, "if") == 0) || strcmp(s
, "elseif") == 0)
155 if (strcmp(s
, "for") == 0 || strcmp(s
, "foreach") == 0
156 || strcmp(s
, "program") == 0 || strcmp(s
, "function") == 0
157 || strcmp(s
, "while") == 0 || strcmp(s
, "case") == 0
158 || strcmp(s
, "if") == 0 ) {
160 } else if ( strcmp(s
, "endfor") == 0 || strcmp(s
, "endforeach") == 0
161 || strcmp(s
, "endprogram") == 0 || strcmp(s
, "endfunction") == 0
162 || strcmp(s
, "endwhile") == 0 || strcmp(s
, "endcase") == 0
163 || strcmp(s
, "endif") == 0 ) {
171 static bool IsStreamCommentStyle(int style
) {
172 return style
== SCE_ESCRIPT_COMMENT
||
173 style
== SCE_ESCRIPT_COMMENTDOC
||
174 style
== SCE_ESCRIPT_COMMENTLINE
;
177 static void FoldESCRIPTDoc(Sci_PositionU startPos
, Sci_Position length
, int initStyle
, WordList
*[], Accessor
&styler
) {
178 //~ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
179 // Do not know how to fold the comment at the moment.
180 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
181 bool foldComment
= true;
182 Sci_PositionU endPos
= startPos
+ length
;
183 int visibleChars
= 0;
184 Sci_Position lineCurrent
= styler
.GetLine(startPos
);
185 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
186 int levelCurrent
= levelPrev
;
187 char chNext
= styler
[startPos
];
188 int styleNext
= styler
.StyleAt(startPos
);
189 int style
= initStyle
;
191 Sci_Position lastStart
= 0;
192 char prevWord
[32] = "";
194 for (Sci_PositionU i
= startPos
; i
< endPos
; i
++) {
196 chNext
= styler
.SafeGetCharAt(i
+ 1);
197 int stylePrev
= style
;
199 styleNext
= styler
.StyleAt(i
+ 1);
200 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
203 if (foldComment
&& IsStreamCommentStyle(style
)) {
204 if (!IsStreamCommentStyle(stylePrev
)) {
206 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
207 // Comments don't end at end of line and the next character may be unstyled.
212 if (foldComment
&& (style
== SCE_ESCRIPT_COMMENTLINE
)) {
213 if ((ch
== '/') && (chNext
== '/')) {
214 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
215 if (chNext2
== '{') {
217 } else if (chNext2
== '}') {
223 if (stylePrev
== SCE_ESCRIPT_DEFAULT
&& style
== SCE_ESCRIPT_WORD3
)
225 // Store last word start point.
229 if (style
== SCE_ESCRIPT_WORD3
) {
230 if(iswordchar(ch
) && !iswordchar(chNext
)) {
233 for(j
= 0; ( j
< 31 ) && ( j
< i
-lastStart
+1 ); j
++) {
234 s
[j
] = static_cast<char>(tolower(styler
[lastStart
+ j
]));
237 levelCurrent
+= classifyFoldPointESCRIPT(s
, prevWord
);
243 if (visibleChars
== 0 && foldCompact
)
244 lev
|= SC_FOLDLEVELWHITEFLAG
;
245 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0))
246 lev
|= SC_FOLDLEVELHEADERFLAG
;
247 if (lev
!= styler
.LevelAt(lineCurrent
)) {
248 styler
.SetLevel(lineCurrent
, lev
);
251 levelPrev
= levelCurrent
;
253 strcpy(prevWord
, "");
256 if (!isspacechar(ch
))
260 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
261 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
262 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
267 static const char * const ESCRIPTWordLists
[] = {
268 "Primary keywords and identifiers",
269 "Intrinsic functions",
270 "Extended and user defined functions",
274 LexerModule
lmESCRIPT(SCLEX_ESCRIPT
, ColouriseESCRIPTDoc
, "escript", FoldESCRIPTDoc
, ESCRIPTWordLists
);