]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexAVS.cxx
wxRTC: extracted XML utilities into a separate class for potential reuse.
[wxWidgets.git] / src / stc / scintilla / lexers / LexAVS.cxx
1 // Scintilla source code edit control
2 /** @file LexAVS.cxx
3 ** Lexer for AviSynth.
4 **/
5 // Copyright 2012 by Bruno Barbieri <brunorex@gmail.com>
6 // Heavily based on LexPOV by Neil Hodgson
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
30
31 static inline bool IsAWordChar(const int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '_');
33 }
34
35 static inline bool IsAWordStart(int ch) {
36 return isalpha(ch) || (ch != ' ' && ch != '\n' && ch != '(' && ch != '.' && ch != ',');
37 }
38
39 static inline bool IsANumberChar(int ch) {
40 // Not exactly following number definition (several dots are seen as OK, etc.)
41 // but probably enough in most cases.
42 return (ch < 0x80) &&
43 (isdigit(ch) || ch == '.' || ch == '-' || ch == '+');
44 }
45
46 static void ColouriseAvsDoc(
47 unsigned int startPos,
48 int length,
49 int initStyle,
50 WordList *keywordlists[],
51 Accessor &styler) {
52
53 WordList &keywords = *keywordlists[0];
54 WordList &filters = *keywordlists[1];
55 WordList &plugins = *keywordlists[2];
56 WordList &functions = *keywordlists[3];
57 WordList &clipProperties = *keywordlists[4];
58 WordList &userDefined = *keywordlists[5];
59
60 int currentLine = styler.GetLine(startPos);
61 // Initialize the block comment nesting level, if we are inside such a comment.
62 int blockCommentLevel = 0;
63 if (initStyle == SCE_AVS_COMMENTBLOCK || initStyle == SCE_AVS_COMMENTBLOCKN) {
64 blockCommentLevel = styler.GetLineState(currentLine - 1);
65 }
66
67 // Do not leak onto next line
68 if (initStyle == SCE_AVS_COMMENTLINE) {
69 initStyle = SCE_AVS_DEFAULT;
70 }
71
72 StyleContext sc(startPos, length, initStyle, styler);
73
74 for (; sc.More(); sc.Forward()) {
75 if (sc.atLineEnd) {
76 // Update the line state, so it can be seen by next line
77 currentLine = styler.GetLine(sc.currentPos);
78 if (sc.state == SCE_AVS_COMMENTBLOCK || sc.state == SCE_AVS_COMMENTBLOCKN) {
79 // Inside a block comment, we set the line state
80 styler.SetLineState(currentLine, blockCommentLevel);
81 } else {
82 // Reset the line state
83 styler.SetLineState(currentLine, 0);
84 }
85 }
86
87 // Determine if the current state should terminate.
88 if (sc.state == SCE_AVS_OPERATOR) {
89 sc.SetState(SCE_AVS_DEFAULT);
90 } else if (sc.state == SCE_AVS_NUMBER) {
91 // We stop the number definition on non-numerical non-dot non-sign char
92 if (!IsANumberChar(sc.ch)) {
93 sc.SetState(SCE_AVS_DEFAULT);
94 }
95 } else if (sc.state == SCE_AVS_IDENTIFIER) {
96 if (!IsAWordChar(sc.ch)) {
97 char s[100];
98 sc.GetCurrentLowered(s, sizeof(s));
99
100 if (keywords.InList(s)) {
101 sc.ChangeState(SCE_AVS_KEYWORD);
102 } else if (filters.InList(s)) {
103 sc.ChangeState(SCE_AVS_FILTER);
104 } else if (plugins.InList(s)) {
105 sc.ChangeState(SCE_AVS_PLUGIN);
106 } else if (functions.InList(s)) {
107 sc.ChangeState(SCE_AVS_FUNCTION);
108 } else if (clipProperties.InList(s)) {
109 sc.ChangeState(SCE_AVS_CLIPPROP);
110 } else if (userDefined.InList(s)) {
111 sc.ChangeState(SCE_AVS_USERDFN);
112 }
113 sc.SetState(SCE_AVS_DEFAULT);
114 }
115 } else if (sc.state == SCE_AVS_COMMENTBLOCK) {
116 if (sc.Match('/', '*')) {
117 blockCommentLevel++;
118 sc.Forward();
119 } else if (sc.Match('*', '/') && blockCommentLevel > 0) {
120 blockCommentLevel--;
121 sc.Forward();
122 if (blockCommentLevel == 0) {
123 sc.ForwardSetState(SCE_AVS_DEFAULT);
124 }
125 }
126 } else if (sc.state == SCE_AVS_COMMENTBLOCKN) {
127 if (sc.Match('[', '*')) {
128 blockCommentLevel++;
129 sc.Forward();
130 } else if (sc.Match('*', ']') && blockCommentLevel > 0) {
131 blockCommentLevel--;
132 sc.Forward();
133 if (blockCommentLevel == 0) {
134 sc.ForwardSetState(SCE_AVS_DEFAULT);
135 }
136 }
137 } else if (sc.state == SCE_AVS_COMMENTLINE) {
138 if (sc.atLineEnd) {
139 sc.ForwardSetState(SCE_AVS_DEFAULT);
140 }
141 } else if (sc.state == SCE_AVS_STRING) {
142 if (sc.ch == '\"') {
143 sc.ForwardSetState(SCE_AVS_DEFAULT);
144 }
145 } else if (sc.state == SCE_AVS_TRIPLESTRING) {
146 if (sc.Match("\"\"\"")) {
147 sc.Forward();
148 sc.Forward();
149 sc.ForwardSetState(SCE_AVS_DEFAULT);
150 }
151 }
152
153 // Determine if a new state should be entered.
154 if (sc.state == SCE_AVS_DEFAULT) {
155 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
156 sc.SetState(SCE_AVS_NUMBER);
157 } else if (IsADigit(sc.ch) || (sc.ch == ',' && IsADigit(sc.chNext))) {
158 sc.Forward();
159 sc.SetState(SCE_AVS_NUMBER);
160 } else if (sc.Match('/', '*')) {
161 blockCommentLevel = 1;
162 sc.SetState(SCE_AVS_COMMENTBLOCK);
163 sc.Forward(); // Eat the * so it isn't used for the end of the comment
164 } else if (sc.Match('[', '*')) {
165 blockCommentLevel = 1;
166 sc.SetState(SCE_AVS_COMMENTBLOCKN);
167 sc.Forward(); // Eat the * so it isn't used for the end of the comment
168 } else if (sc.ch == '#') {
169 sc.SetState(SCE_AVS_COMMENTLINE);
170 } else if (sc.ch == '\"') {
171 if (sc.Match("\"\"\"")) {
172 sc.SetState(SCE_AVS_TRIPLESTRING);
173 } else {
174 sc.SetState(SCE_AVS_STRING);
175 }
176 } else if (isoperator(static_cast<char>(sc.ch))) {
177 sc.SetState(SCE_AVS_OPERATOR);
178 } else if (IsAWordStart(sc.ch)) {
179 sc.SetState(SCE_AVS_IDENTIFIER);
180 }
181 }
182 }
183
184 // End of file: complete any pending changeState
185 if (sc.state == SCE_AVS_IDENTIFIER) {
186 if (!IsAWordChar(sc.ch)) {
187 char s[100];
188 sc.GetCurrentLowered(s, sizeof(s));
189
190 if (keywords.InList(s)) {
191 sc.ChangeState(SCE_AVS_KEYWORD);
192 } else if (filters.InList(s)) {
193 sc.ChangeState(SCE_AVS_FILTER);
194 } else if (plugins.InList(s)) {
195 sc.ChangeState(SCE_AVS_PLUGIN);
196 } else if (functions.InList(s)) {
197 sc.ChangeState(SCE_AVS_FUNCTION);
198 } else if (clipProperties.InList(s)) {
199 sc.ChangeState(SCE_AVS_CLIPPROP);
200 } else if (userDefined.InList(s)) {
201 sc.ChangeState(SCE_AVS_USERDFN);
202 }
203 sc.SetState(SCE_AVS_DEFAULT);
204 }
205 }
206
207 sc.Complete();
208 }
209
210 static void FoldAvsDoc(
211 unsigned int startPos,
212 int length,
213 int initStyle,
214 WordList *[],
215 Accessor &styler) {
216
217 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
218 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
219 unsigned int endPos = startPos + length;
220 int visibleChars = 0;
221 int lineCurrent = styler.GetLine(startPos);
222 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
223 int levelCurrent = levelPrev;
224 char chNext = styler[startPos];
225 int styleNext = styler.StyleAt(startPos);
226 int style = initStyle;
227
228 for (unsigned int i = startPos; i < endPos; i++) {
229 char ch = chNext;
230 chNext = styler.SafeGetCharAt(i + 1);
231 int stylePrev = style;
232 style = styleNext;
233 styleNext = styler.StyleAt(i + 1);
234 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
235 if (foldComment && style == SCE_AVS_COMMENTBLOCK) {
236 if (stylePrev != SCE_AVS_COMMENTBLOCK) {
237 levelCurrent++;
238 } else if ((styleNext != SCE_AVS_COMMENTBLOCK) && !atEOL) {
239 // Comments don't end at end of line and the next character may be unstyled.
240 levelCurrent--;
241 }
242 }
243
244 if (foldComment && style == SCE_AVS_COMMENTBLOCKN) {
245 if (stylePrev != SCE_AVS_COMMENTBLOCKN) {
246 levelCurrent++;
247 } else if ((styleNext != SCE_AVS_COMMENTBLOCKN) && !atEOL) {
248 // Comments don't end at end of line and the next character may be unstyled.
249 levelCurrent--;
250 }
251 }
252
253 if (style == SCE_AVS_OPERATOR) {
254 if (ch == '{') {
255 levelCurrent++;
256 } else if (ch == '}') {
257 levelCurrent--;
258 }
259 }
260
261 if (atEOL) {
262 int lev = levelPrev;
263 if (visibleChars == 0 && foldCompact)
264 lev |= SC_FOLDLEVELWHITEFLAG;
265 if ((levelCurrent > levelPrev) && (visibleChars > 0))
266 lev |= SC_FOLDLEVELHEADERFLAG;
267 if (lev != styler.LevelAt(lineCurrent)) {
268 styler.SetLevel(lineCurrent, lev);
269 }
270 lineCurrent++;
271 levelPrev = levelCurrent;
272 visibleChars = 0;
273 }
274
275 if (!isspacechar(ch))
276 visibleChars++;
277 }
278 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
279 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
280 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
281 }
282
283 static const char * const avsWordLists[] = {
284 "Keywords",
285 "Filters",
286 "Plugins",
287 "Functions",
288 "Clip properties",
289 "User defined functions",
290 0,
291 };
292
293 LexerModule lmAVS(SCLEX_AVS, ColouriseAvsDoc, "avs", FoldAvsDoc, avsWordLists);