]>
Commit | Line | Data |
---|---|---|
b8193d80 RD |
1 | // Scintilla source code edit control |
2 | /** @file LexInno.cxx | |
3 | ** Lexer for Inno Setup scripts. | |
4 | **/ | |
5 | // Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx. | |
6 | // The License.txt file describes the conditions under which this software may be distributed. | |
7 | ||
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
b8193d80 RD |
10 | #include <stdio.h> |
11 | #include <stdarg.h> | |
1dcf666d RD |
12 | #include <assert.h> |
13 | #include <ctype.h> | |
b8193d80 | 14 | |
1dcf666d RD |
15 | #include "ILexer.h" |
16 | #include "Scintilla.h" | |
17 | #include "SciLexer.h" | |
b8193d80 | 18 | |
1dcf666d RD |
19 | #include "WordList.h" |
20 | #include "LexAccessor.h" | |
b8193d80 RD |
21 | #include "Accessor.h" |
22 | #include "StyleContext.h" | |
1dcf666d RD |
23 | #include "CharacterSet.h" |
24 | #include "LexerModule.h" | |
b8193d80 | 25 | |
7e0c58e9 RD |
26 | #ifdef SCI_NAMESPACE |
27 | using namespace Scintilla; | |
28 | #endif | |
29 | ||
b8193d80 RD |
30 | static void ColouriseInnoDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler) { |
31 | int state = SCE_INNO_DEFAULT; | |
32 | char chPrev; | |
33 | char ch = 0; | |
34 | char chNext = styler[startPos]; | |
35 | int lengthDoc = startPos + length; | |
36 | char *buffer = new char[length]; | |
37 | int bufferCount = 0; | |
38 | bool isBOL, isEOL, isWS, isBOLWS = 0; | |
9e96e16f | 39 | bool isCStyleComment = false; |
b8193d80 RD |
40 | |
41 | WordList §ionKeywords = *keywordLists[0]; | |
42 | WordList &standardKeywords = *keywordLists[1]; | |
43 | WordList ¶meterKeywords = *keywordLists[2]; | |
44 | WordList &preprocessorKeywords = *keywordLists[3]; | |
45 | WordList &pascalKeywords = *keywordLists[4]; | |
46 | WordList &userKeywords = *keywordLists[5]; | |
47 | ||
1dcf666d RD |
48 | int curLine = styler.GetLine(startPos); |
49 | int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0; | |
50 | bool isCode = (curLineState == 1); | |
51 | ||
b8193d80 RD |
52 | // Go through all provided text segment |
53 | // using the hand-written state machine shown below | |
54 | styler.StartAt(startPos); | |
55 | styler.StartSegment(startPos); | |
56 | for (int i = startPos; i < lengthDoc; i++) { | |
57 | chPrev = ch; | |
58 | ch = chNext; | |
59 | chNext = styler.SafeGetCharAt(i + 1); | |
60 | ||
61 | if (styler.IsLeadByte(ch)) { | |
62 | chNext = styler.SafeGetCharAt(i + 2); | |
63 | i++; | |
64 | continue; | |
65 | } | |
66 | ||
67 | isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n'); | |
68 | isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t')); | |
69 | isEOL = (ch == '\n' || ch == '\r'); | |
70 | isWS = (ch == ' ' || ch == '\t'); | |
71 | ||
1dcf666d RD |
72 | if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { |
73 | // Remember the line state for future incremental lexing | |
74 | curLine = styler.GetLine(i); | |
75 | styler.SetLineState(curLine, (isCode ? 1 : 0)); | |
76 | } | |
77 | ||
b8193d80 RD |
78 | switch(state) { |
79 | case SCE_INNO_DEFAULT: | |
9e96e16f | 80 | if (!isCode && ch == ';' && isBOLWS) { |
b8193d80 RD |
81 | // Start of a comment |
82 | state = SCE_INNO_COMMENT; | |
83 | } else if (ch == '[' && isBOLWS) { | |
84 | // Start of a section name | |
85 | bufferCount = 0; | |
86 | state = SCE_INNO_SECTION; | |
87 | } else if (ch == '#' && isBOLWS) { | |
88 | // Start of a preprocessor directive | |
89 | state = SCE_INNO_PREPROC; | |
9e96e16f RD |
90 | } else if (!isCode && ch == '{' && chNext != '{' && chPrev != '{') { |
91 | // Start of an inline expansion | |
92 | state = SCE_INNO_INLINE_EXPANSION; | |
93 | } else if (isCode && (ch == '{' || (ch == '(' && chNext == '*'))) { | |
b8193d80 RD |
94 | // Start of a Pascal comment |
95 | state = SCE_INNO_COMMENT_PASCAL; | |
9e96e16f RD |
96 | isCStyleComment = false; |
97 | } else if (isCode && ch == '/' && chNext == '/') { | |
98 | // Apparently, C-style comments are legal, too | |
99 | state = SCE_INNO_COMMENT_PASCAL; | |
100 | isCStyleComment = true; | |
b8193d80 RD |
101 | } else if (ch == '"') { |
102 | // Start of a double-quote string | |
103 | state = SCE_INNO_STRING_DOUBLE; | |
104 | } else if (ch == '\'') { | |
105 | // Start of a single-quote string | |
106 | state = SCE_INNO_STRING_SINGLE; | |
107 | } else if (isascii(ch) && (isalpha(ch) || (ch == '_'))) { | |
108 | // Start of an identifier | |
109 | bufferCount = 0; | |
110 | buffer[bufferCount++] = static_cast<char>(tolower(ch)); | |
111 | state = SCE_INNO_IDENTIFIER; | |
112 | } else { | |
113 | // Style it the default style | |
114 | styler.ColourTo(i,SCE_INNO_DEFAULT); | |
115 | } | |
116 | break; | |
117 | ||
118 | case SCE_INNO_COMMENT: | |
119 | if (isEOL) { | |
120 | state = SCE_INNO_DEFAULT; | |
121 | styler.ColourTo(i,SCE_INNO_COMMENT); | |
122 | } | |
123 | break; | |
124 | ||
125 | case SCE_INNO_IDENTIFIER: | |
126 | if (isascii(ch) && (isalnum(ch) || (ch == '_'))) { | |
127 | buffer[bufferCount++] = static_cast<char>(tolower(ch)); | |
128 | } else { | |
129 | state = SCE_INNO_DEFAULT; | |
130 | buffer[bufferCount] = '\0'; | |
131 | ||
132 | // Check if the buffer contains a keyword | |
9e96e16f | 133 | if (!isCode && standardKeywords.InList(buffer)) { |
b8193d80 | 134 | styler.ColourTo(i-1,SCE_INNO_KEYWORD); |
9e96e16f | 135 | } else if (!isCode && parameterKeywords.InList(buffer)) { |
b8193d80 | 136 | styler.ColourTo(i-1,SCE_INNO_PARAMETER); |
9e96e16f | 137 | } else if (isCode && pascalKeywords.InList(buffer)) { |
b8193d80 | 138 | styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL); |
9e96e16f | 139 | } else if (!isCode && userKeywords.InList(buffer)) { |
b8193d80 RD |
140 | styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER); |
141 | } else { | |
142 | styler.ColourTo(i-1,SCE_INNO_DEFAULT); | |
143 | } | |
144 | ||
145 | // Push back the faulty character | |
146 | chNext = styler[i--]; | |
147 | ch = chPrev; | |
148 | } | |
149 | break; | |
150 | ||
151 | case SCE_INNO_SECTION: | |
152 | if (ch == ']') { | |
153 | state = SCE_INNO_DEFAULT; | |
154 | buffer[bufferCount] = '\0'; | |
155 | ||
156 | // Check if the buffer contains a section name | |
157 | if (sectionKeywords.InList(buffer)) { | |
158 | styler.ColourTo(i,SCE_INNO_SECTION); | |
9e96e16f | 159 | isCode = !CompareCaseInsensitive(buffer, "code"); |
b8193d80 RD |
160 | } else { |
161 | styler.ColourTo(i,SCE_INNO_DEFAULT); | |
162 | } | |
163 | } else if (isascii(ch) && (isalnum(ch) || (ch == '_'))) { | |
164 | buffer[bufferCount++] = static_cast<char>(tolower(ch)); | |
165 | } else { | |
166 | state = SCE_INNO_DEFAULT; | |
167 | styler.ColourTo(i,SCE_INNO_DEFAULT); | |
168 | } | |
169 | break; | |
170 | ||
171 | case SCE_INNO_PREPROC: | |
172 | if (isWS || isEOL) { | |
173 | if (isascii(chPrev) && isalpha(chPrev)) { | |
174 | state = SCE_INNO_DEFAULT; | |
175 | buffer[bufferCount] = '\0'; | |
176 | ||
177 | // Check if the buffer contains a preprocessor directive | |
178 | if (preprocessorKeywords.InList(buffer)) { | |
179 | styler.ColourTo(i-1,SCE_INNO_PREPROC); | |
180 | } else { | |
181 | styler.ColourTo(i-1,SCE_INNO_DEFAULT); | |
182 | } | |
183 | ||
184 | // Push back the faulty character | |
185 | chNext = styler[i--]; | |
186 | ch = chPrev; | |
187 | } | |
188 | } else if (isascii(ch) && isalpha(ch)) { | |
189 | if (chPrev == '#' || chPrev == ' ' || chPrev == '\t') | |
190 | bufferCount = 0; | |
191 | buffer[bufferCount++] = static_cast<char>(tolower(ch)); | |
192 | } | |
193 | break; | |
194 | ||
195 | case SCE_INNO_STRING_DOUBLE: | |
196 | if (ch == '"' || isEOL) { | |
197 | state = SCE_INNO_DEFAULT; | |
7e0c58e9 | 198 | styler.ColourTo(i,SCE_INNO_STRING_DOUBLE); |
b8193d80 RD |
199 | } |
200 | break; | |
201 | ||
202 | case SCE_INNO_STRING_SINGLE: | |
203 | if (ch == '\'' || isEOL) { | |
204 | state = SCE_INNO_DEFAULT; | |
7e0c58e9 | 205 | styler.ColourTo(i,SCE_INNO_STRING_SINGLE); |
b8193d80 RD |
206 | } |
207 | break; | |
208 | ||
9e96e16f | 209 | case SCE_INNO_INLINE_EXPANSION: |
b8193d80 RD |
210 | if (ch == '}') { |
211 | state = SCE_INNO_DEFAULT; | |
9e96e16f | 212 | styler.ColourTo(i,SCE_INNO_INLINE_EXPANSION); |
b8193d80 RD |
213 | } else if (isEOL) { |
214 | state = SCE_INNO_DEFAULT; | |
215 | styler.ColourTo(i,SCE_INNO_DEFAULT); | |
216 | } | |
217 | break; | |
218 | ||
219 | case SCE_INNO_COMMENT_PASCAL: | |
9e96e16f RD |
220 | if (isCStyleComment) { |
221 | if (isEOL) { | |
222 | state = SCE_INNO_DEFAULT; | |
223 | styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL); | |
224 | } | |
225 | } else { | |
226 | if (ch == '}' || (ch == ')' && chPrev == '*')) { | |
227 | state = SCE_INNO_DEFAULT; | |
228 | styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL); | |
229 | } else if (isEOL) { | |
230 | state = SCE_INNO_DEFAULT; | |
231 | styler.ColourTo(i,SCE_INNO_DEFAULT); | |
232 | } | |
b8193d80 RD |
233 | } |
234 | break; | |
235 | ||
236 | } | |
237 | } | |
238 | delete []buffer; | |
239 | } | |
240 | ||
241 | static const char * const innoWordListDesc[] = { | |
242 | "Sections", | |
243 | "Keywords", | |
244 | "Parameters", | |
245 | "Preprocessor directives", | |
246 | "Pascal keywords", | |
247 | "User defined keywords", | |
248 | 0 | |
249 | }; | |
250 | ||
251 | static void FoldInnoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { | |
b8193d80 | 252 | unsigned int endPos = startPos + length; |
9e96e16f RD |
253 | char chNext = styler[startPos]; |
254 | ||
b8193d80 RD |
255 | int lineCurrent = styler.GetLine(startPos); |
256 | ||
9e96e16f RD |
257 | bool sectionFlag = false; |
258 | int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) : SC_FOLDLEVELBASE; | |
259 | int level; | |
b8193d80 RD |
260 | |
261 | for (unsigned int i = startPos; i < endPos; i++) { | |
262 | char ch = chNext; | |
263 | chNext = styler[i+1]; | |
b8193d80 | 264 | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); |
9e96e16f | 265 | int style = styler.StyleAt(i); |
b8193d80 RD |
266 | |
267 | if (style == SCE_INNO_SECTION) | |
9e96e16f RD |
268 | sectionFlag = true; |
269 | ||
270 | if (atEOL || i == endPos - 1) { | |
271 | if (sectionFlag) { | |
272 | level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; | |
273 | if (level == levelPrev) | |
274 | styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG); | |
275 | } else { | |
276 | level = levelPrev & SC_FOLDLEVELNUMBERMASK; | |
277 | if (levelPrev & SC_FOLDLEVELHEADERFLAG) | |
278 | level++; | |
b8193d80 RD |
279 | } |
280 | ||
9e96e16f | 281 | styler.SetLevel(lineCurrent, level); |
b8193d80 | 282 | |
9e96e16f | 283 | levelPrev = level; |
b8193d80 | 284 | lineCurrent++; |
9e96e16f | 285 | sectionFlag = false; |
b8193d80 | 286 | } |
b8193d80 | 287 | } |
b8193d80 RD |
288 | } |
289 | ||
290 | LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc); |