1 // Scintilla source code edit control
3 ** Lexer for Inno Setup scripts.
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.
16 #include "Scintilla.h"
20 #include "LexAccessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
27 using namespace Scintilla
;
30 static void ColouriseInnoDoc(unsigned int startPos
, int length
, int, WordList
*keywordLists
[], Accessor
&styler
) {
31 int state
= SCE_INNO_DEFAULT
;
34 char chNext
= styler
[startPos
];
35 int lengthDoc
= startPos
+ length
;
36 char *buffer
= new char[length
];
38 bool isBOL
, isEOL
, isWS
, isBOLWS
= 0;
39 bool isCStyleComment
= false;
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];
48 int curLine
= styler
.GetLine(startPos
);
49 int curLineState
= curLine
> 0 ? styler
.GetLineState(curLine
- 1) : 0;
50 bool isCode
= (curLineState
== 1);
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
++) {
59 chNext
= styler
.SafeGetCharAt(i
+ 1);
61 if (styler
.IsLeadByte(ch
)) {
62 chNext
= styler
.SafeGetCharAt(i
+ 2);
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');
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));
79 case SCE_INNO_DEFAULT
:
80 if (!isCode
&& ch
== ';' && isBOLWS
) {
82 state
= SCE_INNO_COMMENT
;
83 } else if (ch
== '[' && isBOLWS
) {
84 // Start of a section name
86 state
= SCE_INNO_SECTION
;
87 } else if (ch
== '#' && isBOLWS
) {
88 // Start of a preprocessor directive
89 state
= SCE_INNO_PREPROC
;
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
== '*'))) {
94 // Start of a Pascal comment
95 state
= SCE_INNO_COMMENT_PASCAL
;
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;
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
110 buffer
[bufferCount
++] = static_cast<char>(tolower(ch
));
111 state
= SCE_INNO_IDENTIFIER
;
113 // Style it the default style
114 styler
.ColourTo(i
,SCE_INNO_DEFAULT
);
118 case SCE_INNO_COMMENT
:
120 state
= SCE_INNO_DEFAULT
;
121 styler
.ColourTo(i
,SCE_INNO_COMMENT
);
125 case SCE_INNO_IDENTIFIER
:
126 if (isascii(ch
) && (isalnum(ch
) || (ch
== '_'))) {
127 buffer
[bufferCount
++] = static_cast<char>(tolower(ch
));
129 state
= SCE_INNO_DEFAULT
;
130 buffer
[bufferCount
] = '\0';
132 // Check if the buffer contains a keyword
133 if (!isCode
&& standardKeywords
.InList(buffer
)) {
134 styler
.ColourTo(i
-1,SCE_INNO_KEYWORD
);
135 } else if (!isCode
&& parameterKeywords
.InList(buffer
)) {
136 styler
.ColourTo(i
-1,SCE_INNO_PARAMETER
);
137 } else if (isCode
&& pascalKeywords
.InList(buffer
)) {
138 styler
.ColourTo(i
-1,SCE_INNO_KEYWORD_PASCAL
);
139 } else if (!isCode
&& userKeywords
.InList(buffer
)) {
140 styler
.ColourTo(i
-1,SCE_INNO_KEYWORD_USER
);
142 styler
.ColourTo(i
-1,SCE_INNO_DEFAULT
);
145 // Push back the faulty character
146 chNext
= styler
[i
--];
151 case SCE_INNO_SECTION
:
153 state
= SCE_INNO_DEFAULT
;
154 buffer
[bufferCount
] = '\0';
156 // Check if the buffer contains a section name
157 if (sectionKeywords
.InList(buffer
)) {
158 styler
.ColourTo(i
,SCE_INNO_SECTION
);
159 isCode
= !CompareCaseInsensitive(buffer
, "code");
161 styler
.ColourTo(i
,SCE_INNO_DEFAULT
);
163 } else if (isascii(ch
) && (isalnum(ch
) || (ch
== '_'))) {
164 buffer
[bufferCount
++] = static_cast<char>(tolower(ch
));
166 state
= SCE_INNO_DEFAULT
;
167 styler
.ColourTo(i
,SCE_INNO_DEFAULT
);
171 case SCE_INNO_PREPROC
:
173 if (isascii(chPrev
) && isalpha(chPrev
)) {
174 state
= SCE_INNO_DEFAULT
;
175 buffer
[bufferCount
] = '\0';
177 // Check if the buffer contains a preprocessor directive
178 if (preprocessorKeywords
.InList(buffer
)) {
179 styler
.ColourTo(i
-1,SCE_INNO_PREPROC
);
181 styler
.ColourTo(i
-1,SCE_INNO_DEFAULT
);
184 // Push back the faulty character
185 chNext
= styler
[i
--];
188 } else if (isascii(ch
) && isalpha(ch
)) {
189 if (chPrev
== '#' || chPrev
== ' ' || chPrev
== '\t')
191 buffer
[bufferCount
++] = static_cast<char>(tolower(ch
));
195 case SCE_INNO_STRING_DOUBLE
:
196 if (ch
== '"' || isEOL
) {
197 state
= SCE_INNO_DEFAULT
;
198 styler
.ColourTo(i
,SCE_INNO_STRING_DOUBLE
);
202 case SCE_INNO_STRING_SINGLE
:
203 if (ch
== '\'' || isEOL
) {
204 state
= SCE_INNO_DEFAULT
;
205 styler
.ColourTo(i
,SCE_INNO_STRING_SINGLE
);
209 case SCE_INNO_INLINE_EXPANSION
:
211 state
= SCE_INNO_DEFAULT
;
212 styler
.ColourTo(i
,SCE_INNO_INLINE_EXPANSION
);
214 state
= SCE_INNO_DEFAULT
;
215 styler
.ColourTo(i
,SCE_INNO_DEFAULT
);
219 case SCE_INNO_COMMENT_PASCAL
:
220 if (isCStyleComment
) {
222 state
= SCE_INNO_DEFAULT
;
223 styler
.ColourTo(i
,SCE_INNO_COMMENT_PASCAL
);
226 if (ch
== '}' || (ch
== ')' && chPrev
== '*')) {
227 state
= SCE_INNO_DEFAULT
;
228 styler
.ColourTo(i
,SCE_INNO_COMMENT_PASCAL
);
230 state
= SCE_INNO_DEFAULT
;
231 styler
.ColourTo(i
,SCE_INNO_DEFAULT
);
241 static const char * const innoWordListDesc
[] = {
245 "Preprocessor directives",
247 "User defined keywords",
251 static void FoldInnoDoc(unsigned int startPos
, int length
, int, WordList
*[], Accessor
&styler
) {
252 unsigned int endPos
= startPos
+ length
;
253 char chNext
= styler
[startPos
];
255 int lineCurrent
= styler
.GetLine(startPos
);
257 bool sectionFlag
= false;
258 int levelPrev
= lineCurrent
> 0 ? styler
.LevelAt(lineCurrent
- 1) : SC_FOLDLEVELBASE
;
261 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
263 chNext
= styler
[i
+1];
264 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
265 int style
= styler
.StyleAt(i
);
267 if (style
== SCE_INNO_SECTION
)
270 if (atEOL
|| i
== endPos
- 1) {
272 level
= SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
;
273 if (level
== levelPrev
)
274 styler
.SetLevel(lineCurrent
- 1, levelPrev
& ~SC_FOLDLEVELHEADERFLAG
);
276 level
= levelPrev
& SC_FOLDLEVELNUMBERMASK
;
277 if (levelPrev
& SC_FOLDLEVELHEADERFLAG
)
281 styler
.SetLevel(lineCurrent
, level
);
290 LexerModule
lmInno(SCLEX_INNOSETUP
, ColouriseInnoDoc
, "inno", FoldInnoDoc
, innoWordListDesc
);