]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexRuby.cxx
1 // Scintilla source code edit control
5 // Copyright 2001- by Clemens Wyss <wys@helbling.ch>
6 // The License.txt file describes the conditions under which this software may be distributed.
19 #include "Scintilla.h"
22 static void ClassifyWordRb(unsigned int start
, unsigned int end
, WordList
&keywords
, Accessor
&styler
, char *prevWord
) {
24 bool wordIsNumber
= isdigit(styler
[start
]);
25 for (unsigned int i
= 0; i
< end
- start
+ 1 && i
< 30; i
++) {
26 s
[i
] = styler
[start
+ i
];
29 char chAttr
= SCE_P_IDENTIFIER
;
30 if (0 == strcmp(prevWord
, "class"))
31 chAttr
= SCE_P_CLASSNAME
;
32 else if (0 == strcmp(prevWord
, "module"))
33 chAttr
= SCE_P_CLASSNAME
;
34 else if (0 == strcmp(prevWord
, "def"))
35 chAttr
= SCE_P_DEFNAME
;
36 else if (wordIsNumber
)
37 chAttr
= SCE_P_NUMBER
;
38 else if (keywords
.InList(s
))
40 // make sure that dot-qualifiers inside the word are lexed correct
41 else for (unsigned int i
= 0; i
< end
- start
+ 1; i
++) {
42 if (styler
[start
+ i
] == '.') {
43 styler
.ColourTo(start
+ i
- 1, chAttr
);
44 styler
.ColourTo(start
+ i
, SCE_P_OPERATOR
);
47 styler
.ColourTo(end
, chAttr
);
51 static bool IsRbComment(Accessor
&styler
, int pos
, int len
) {
52 return len
>0 && styler
[pos
]=='#';
55 static bool IsRbStringStart(char ch
, char chNext
, char chNext2
) {
56 if (ch
== '\'' || ch
== '"')
58 if (ch
== 'u' || ch
== 'U') {
59 if (chNext
== '"' || chNext
== '\'')
61 if ((chNext
== 'r' || chNext
== 'R') && (chNext2
== '"' || chNext2
== '\''))
64 if ((ch
== 'r' || ch
== 'R') && (chNext
== '"' || chNext
== '\''))
70 static bool IsRbWordStart(char ch
, char chNext
, char chNext2
) {
71 return (iswordchar(ch
) && !IsRbStringStart(ch
, chNext
, chNext2
));
74 /* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */
75 static int GetRbStringState(Accessor
&styler
, int i
, int *nextIndex
) {
76 char ch
= styler
.SafeGetCharAt(i
);
77 char chNext
= styler
.SafeGetCharAt(i
+ 1);
79 // Advance beyond r, u, or ur prefix, but bail if there are any unexpected chars
80 if (ch
== 'r' || ch
== 'R') {
82 ch
= styler
.SafeGetCharAt(i
);
83 chNext
= styler
.SafeGetCharAt(i
+ 1);
85 else if (ch
== 'u' || ch
== 'U') {
86 if (chNext
== 'r' || chNext
== 'R')
90 ch
= styler
.SafeGetCharAt(i
);
91 chNext
= styler
.SafeGetCharAt(i
+ 1);
94 if (ch
!= '"' && ch
!= '\'') {
99 if (ch
== chNext
&& ch
== styler
.SafeGetCharAt(i
+ 2)) {
103 return SCE_P_TRIPLEDOUBLE
;
112 return SCE_P_CHARACTER
;
116 static void ColouriseRbDoc(unsigned int startPos
, int length
, int initStyle
,
117 WordList
*keywordlists
[], Accessor
&styler
) {
119 int lengthDoc
= startPos
+ length
;
121 // Backtrack to previous line in case need to fix its tab whinging
123 int lineCurrent
= styler
.GetLine(startPos
);
124 if (lineCurrent
> 0) {
125 startPos
= styler
.LineStart(lineCurrent
-1);
127 initStyle
= SCE_P_DEFAULT
;
129 initStyle
= styler
.StyleAt(startPos
-1);
133 // Ruby uses a different mask because bad indentation is marked by oring with 32
134 styler
.StartAt(startPos
, 127);
136 WordList
&keywords
= *keywordlists
[0];
138 int whingeLevel
= styler
.GetPropertyInt("tab.timmy.whinge.level");
144 int state
= initStyle
& 31;
149 char chNext
= styler
[startPos
];
150 styler
.StartSegment(startPos
);
151 bool atStartLine
= true;
153 for (int i
= startPos
; i
< lengthDoc
; i
++) {
156 char chBad
= static_cast<char>(64);
157 char chGood
= static_cast<char>(0);
158 char chFlags
= chGood
;
159 if (whingeLevel
== 1) {
160 chFlags
= (spaceFlags
& wsInconsistent
) ? chBad
: chGood
;
161 } else if (whingeLevel
== 2) {
162 chFlags
= (spaceFlags
& wsSpaceTab
) ? chBad
: chGood
;
163 } else if (whingeLevel
== 3) {
164 chFlags
= (spaceFlags
& wsSpace
) ? chBad
: chGood
;
165 } else if (whingeLevel
== 4) {
166 chFlags
= (spaceFlags
& wsTab
) ? chBad
: chGood
;
168 styler
.SetFlags(chFlags
, static_cast<char>(state
));
173 chNext
= styler
.SafeGetCharAt(i
+ 1);
174 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
176 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== lengthDoc
)) {
177 if ((state
== SCE_P_DEFAULT
) || (state
== SCE_P_TRIPLE
) || (state
== SCE_P_TRIPLEDOUBLE
)) {
178 // Perform colourisation of white space and triple quoted strings at end of each line to allow
179 // tab marking to work inside white space and triple quoted strings
180 styler
.ColourTo(i
, state
);
185 if (styler
.IsLeadByte(ch
)) {
186 chNext
= styler
.SafeGetCharAt(i
+ 2);
193 if (state
== SCE_P_STRINGEOL
) {
194 if (ch
!= '\r' && ch
!= '\n') {
195 styler
.ColourTo(i
- 1, state
);
196 state
= SCE_P_DEFAULT
;
199 if (state
== SCE_P_DEFAULT
) {
200 if (IsRbWordStart(ch
, chNext
, chNext2
)) {
201 styler
.ColourTo(i
- 1, state
);
203 } else if (ch
== '#') {
204 styler
.ColourTo(i
- 1, state
);
205 state
= chNext
== '#' ? SCE_P_COMMENTBLOCK
: SCE_P_COMMENTLINE
;
206 } else if (ch
== '=' && chNext
== 'b') {
207 // =begin indicates the start of a comment (doc) block
208 if(styler
.SafeGetCharAt(i
+ 2) == 'e' && styler
.SafeGetCharAt(i
+ 3) == 'g' && styler
.SafeGetCharAt(i
+ 4) == 'i' && styler
.SafeGetCharAt(i
+ 5) == 'n') {
209 styler
.ColourTo(i
- 1, state
);
210 state
= SCE_P_TRIPLEDOUBLE
; //SCE_C_COMMENT;
212 } else if (IsRbStringStart(ch
, chNext
, chNext2
)) {
213 styler
.ColourTo(i
- 1, state
);
214 state
= GetRbStringState(styler
, i
, &nextIndex
);
215 if (nextIndex
!= i
+ 1) {
219 chNext
= styler
.SafeGetCharAt(i
+ 1);
221 } else if (isoperator(ch
)) {
222 styler
.ColourTo(i
- 1, state
);
223 styler
.ColourTo(i
, SCE_P_OPERATOR
);
225 } else if (state
== SCE_P_WORD
) {
226 if (!iswordchar(ch
)) {
227 ClassifyWordRb(styler
.GetStartSegment(), i
- 1, keywords
, styler
, prevWord
);
228 state
= SCE_P_DEFAULT
;
230 state
= chNext
== '#' ? SCE_P_COMMENTBLOCK
: SCE_P_COMMENTLINE
;
231 } else if (IsRbStringStart(ch
, chNext
, chNext2
)) {
232 styler
.ColourTo(i
- 1, state
);
233 state
= GetRbStringState(styler
, i
, &nextIndex
);
234 if (nextIndex
!= i
+ 1) {
238 chNext
= styler
.SafeGetCharAt(i
+ 1);
240 } else if (isoperator(ch
)) {
241 styler
.ColourTo(i
, SCE_P_OPERATOR
);
245 if (state
== SCE_P_COMMENTLINE
|| state
== SCE_P_COMMENTBLOCK
) {
246 if (ch
== '\r' || ch
== '\n') {
247 styler
.ColourTo(i
- 1, state
);
248 state
= SCE_P_DEFAULT
;
250 } else if (state
== SCE_P_STRING
) {
251 if ((ch
== '\r' || ch
== '\n') && (chPrev
!= '\\')) {
252 styler
.ColourTo(i
- 1, state
);
253 state
= SCE_P_STRINGEOL
;
254 } else if (ch
== '\\') {
255 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
258 chNext
= styler
.SafeGetCharAt(i
+ 1);
260 } else if (ch
== '\"') {
261 styler
.ColourTo(i
, state
);
262 state
= SCE_P_DEFAULT
;
264 } else if (state
== SCE_P_CHARACTER
) {
265 if ((ch
== '\r' || ch
== '\n') && (chPrev
!= '\\')) {
266 styler
.ColourTo(i
- 1, state
);
267 state
= SCE_P_STRINGEOL
;
268 } else if (ch
== '\\') {
269 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
272 chNext
= styler
.SafeGetCharAt(i
+ 1);
274 } else if (ch
== '\'') {
275 styler
.ColourTo(i
, state
);
276 state
= SCE_P_DEFAULT
;
278 } else if (state
== SCE_P_TRIPLE
) {
279 if (ch
== '\'' && chPrev
== '\'' && chPrev2
== '\'') {
280 styler
.ColourTo(i
, state
);
281 state
= SCE_P_DEFAULT
;
283 } else if (state
== SCE_P_TRIPLEDOUBLE
) {
284 // =end terminates the comment block
285 if (ch
== 'd' && chPrev
== 'n' && chPrev2
== 'e') {
286 if (styler
.SafeGetCharAt(i
- 3) == '=') {
287 styler
.ColourTo(i
, state
);
288 state
= SCE_P_DEFAULT
;
296 if (state
== SCE_P_WORD
) {
297 ClassifyWordRb(styler
.GetStartSegment(), lengthDoc
, keywords
, styler
, prevWord
);
299 styler
.ColourTo(lengthDoc
, state
);
303 static void FoldRbDoc(unsigned int startPos
, int length
, int initStyle
,
304 WordList
*[], Accessor
&styler
) {
305 int lengthDoc
= startPos
+ length
;
307 // Backtrack to previous line in case need to fix its fold status
308 int lineCurrent
= styler
.GetLine(startPos
);
310 if (lineCurrent
> 0) {
312 startPos
= styler
.LineStart(lineCurrent
);
314 initStyle
= SCE_P_DEFAULT
;
316 initStyle
= styler
.StyleAt(startPos
-1);
319 int state
= initStyle
& 31;
321 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsRbComment
);
322 if ((state
== SCE_P_TRIPLE
) || (state
== SCE_P_TRIPLEDOUBLE
))
323 indentCurrent
|= SC_FOLDLEVELWHITEFLAG
;
324 char chNext
= styler
[startPos
];
325 for (int i
= startPos
; i
< lengthDoc
; i
++) {
327 chNext
= styler
.SafeGetCharAt(i
+ 1);
328 int style
= styler
.StyleAt(i
) & 31;
330 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== lengthDoc
)) {
331 int lev
= indentCurrent
;
332 int indentNext
= styler
.IndentAmount(lineCurrent
+ 1, &spaceFlags
, IsRbComment
);
333 if ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
))
334 indentNext
|= SC_FOLDLEVELWHITEFLAG
;
335 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
)) {
336 // Only non whitespace lines can be headers
337 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
)) {
338 lev
|= SC_FOLDLEVELHEADERFLAG
;
339 } else if (indentNext
& SC_FOLDLEVELWHITEFLAG
) {
340 // Line after is blank so check the next - maybe should continue further?
342 int indentNext2
= styler
.IndentAmount(lineCurrent
+ 2, &spaceFlags2
, IsRbComment
);
343 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext2
& SC_FOLDLEVELNUMBERMASK
)) {
344 lev
|= SC_FOLDLEVELHEADERFLAG
;
348 indentCurrent
= indentNext
;
349 styler
.SetLevel(lineCurrent
, lev
);
355 LexerModule
lmRuby(SCLEX_RUBY
, ColouriseRbDoc
, "ruby", FoldRbDoc
);