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