]>
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
]) != 0;
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 (i
>0 && styler
.SafeGetCharAt(i
-1) == '$') {
101 return SCE_P_DEFAULT
;
104 if (ch
== chNext
&& ch
== styler
.SafeGetCharAt(i
+ 2)) {
108 return SCE_P_TRIPLEDOUBLE
;
117 return SCE_P_CHARACTER
;
121 static void ColouriseRbDoc(unsigned int startPos
, int length
, int initStyle
,
122 WordList
*keywordlists
[], Accessor
&styler
) {
124 int lengthDoc
= startPos
+ length
;
126 // Backtrack to previous line in case need to fix its tab whinging
128 int lineCurrent
= styler
.GetLine(startPos
);
129 if (lineCurrent
> 0) {
130 startPos
= styler
.LineStart(lineCurrent
-1);
132 initStyle
= SCE_P_DEFAULT
;
134 initStyle
= styler
.StyleAt(startPos
-1);
138 // Ruby uses a different mask because bad indentation is marked by oring with 32
139 styler
.StartAt(startPos
, 127);
141 WordList
&keywords
= *keywordlists
[0];
143 int whingeLevel
= styler
.GetPropertyInt("tab.timmy.whinge.level");
149 int state
= initStyle
& 31;
154 char chNext
= styler
[startPos
];
155 styler
.StartSegment(startPos
);
156 bool atStartLine
= true;
158 for (int i
= startPos
; i
< lengthDoc
; i
++) {
161 char chBad
= static_cast<char>(64);
162 char chGood
= static_cast<char>(0);
163 char chFlags
= chGood
;
164 if (whingeLevel
== 1) {
165 chFlags
= (spaceFlags
& wsInconsistent
) ? chBad
: chGood
;
166 } else if (whingeLevel
== 2) {
167 chFlags
= (spaceFlags
& wsSpaceTab
) ? chBad
: chGood
;
168 } else if (whingeLevel
== 3) {
169 chFlags
= (spaceFlags
& wsSpace
) ? chBad
: chGood
;
170 } else if (whingeLevel
== 4) {
171 chFlags
= (spaceFlags
& wsTab
) ? chBad
: chGood
;
173 styler
.SetFlags(chFlags
, static_cast<char>(state
));
178 chNext
= styler
.SafeGetCharAt(i
+ 1);
179 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
181 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== lengthDoc
)) {
182 if ((state
== SCE_P_DEFAULT
) || (state
== SCE_P_TRIPLE
) || (state
== SCE_P_TRIPLEDOUBLE
)) {
183 // Perform colourisation of white space and triple quoted strings at end of each line to allow
184 // tab marking to work inside white space and triple quoted strings
185 styler
.ColourTo(i
, state
);
190 if (styler
.IsLeadByte(ch
)) {
191 chNext
= styler
.SafeGetCharAt(i
+ 2);
198 if (state
== SCE_P_STRINGEOL
) {
199 if (ch
!= '\r' && ch
!= '\n') {
200 styler
.ColourTo(i
- 1, state
);
201 state
= SCE_P_DEFAULT
;
204 if (state
== SCE_P_DEFAULT
) {
205 if (IsRbWordStart(ch
, chNext
, chNext2
)) {
206 styler
.ColourTo(i
- 1, state
);
208 } else if (ch
== '#') {
209 styler
.ColourTo(i
- 1, state
);
210 state
= chNext
== '#' ? SCE_P_COMMENTBLOCK
: SCE_P_COMMENTLINE
;
211 } else if (ch
== '=' && chNext
== 'b') {
212 // =begin indicates the start of a comment (doc) block
213 if(styler
.SafeGetCharAt(i
+ 2) == 'e' && styler
.SafeGetCharAt(i
+ 3) == 'g' && styler
.SafeGetCharAt(i
+ 4) == 'i' && styler
.SafeGetCharAt(i
+ 5) == 'n') {
214 styler
.ColourTo(i
- 1, state
);
215 state
= SCE_P_TRIPLEDOUBLE
; //SCE_C_COMMENT;
217 } else if (IsRbStringStart(ch
, chNext
, chNext2
)) {
218 styler
.ColourTo(i
- 1, state
);
219 state
= GetRbStringState(styler
, i
, &nextIndex
);
220 if (nextIndex
!= i
+ 1) {
224 chNext
= styler
.SafeGetCharAt(i
+ 1);
226 } else if (isoperator(ch
)) {
227 styler
.ColourTo(i
- 1, state
);
228 styler
.ColourTo(i
, SCE_P_OPERATOR
);
230 } else if (state
== SCE_P_WORD
) {
231 if (!iswordchar(ch
)) {
232 ClassifyWordRb(styler
.GetStartSegment(), i
- 1, keywords
, styler
, prevWord
);
233 state
= SCE_P_DEFAULT
;
235 state
= chNext
== '#' ? SCE_P_COMMENTBLOCK
: SCE_P_COMMENTLINE
;
236 } else if (IsRbStringStart(ch
, chNext
, chNext2
)) {
237 styler
.ColourTo(i
- 1, state
);
238 state
= GetRbStringState(styler
, i
, &nextIndex
);
239 if (nextIndex
!= i
+ 1) {
243 chNext
= styler
.SafeGetCharAt(i
+ 1);
245 } else if (isoperator(ch
)) {
246 styler
.ColourTo(i
, SCE_P_OPERATOR
);
250 if (state
== SCE_P_COMMENTLINE
|| state
== SCE_P_COMMENTBLOCK
) {
251 if (ch
== '\r' || ch
== '\n') {
252 styler
.ColourTo(i
- 1, state
);
253 state
= SCE_P_DEFAULT
;
255 } else if (state
== SCE_P_STRING
) {
256 if ((ch
== '\r' || ch
== '\n') && (chPrev
!= '\\')) {
257 styler
.ColourTo(i
- 1, state
);
258 state
= SCE_P_STRINGEOL
;
259 } else if (ch
== '\\') {
260 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
263 chNext
= styler
.SafeGetCharAt(i
+ 1);
265 } else if (ch
== '\"') {
266 styler
.ColourTo(i
, state
);
267 state
= SCE_P_DEFAULT
;
269 } else if (state
== SCE_P_CHARACTER
) {
270 if ((ch
== '\r' || ch
== '\n') && (chPrev
!= '\\')) {
271 styler
.ColourTo(i
- 1, state
);
272 state
= SCE_P_STRINGEOL
;
273 } else if (ch
== '\\') {
274 if (chNext
== '\"' || chNext
== '\'' || chNext
== '\\') {
277 chNext
= styler
.SafeGetCharAt(i
+ 1);
279 } else if (ch
== '\'') {
280 styler
.ColourTo(i
, state
);
281 state
= SCE_P_DEFAULT
;
283 } else if (state
== SCE_P_TRIPLE
) {
284 if (ch
== '\'' && chPrev
== '\'' && chPrev2
== '\'') {
285 styler
.ColourTo(i
, state
);
286 state
= SCE_P_DEFAULT
;
288 } else if (state
== SCE_P_TRIPLEDOUBLE
) {
289 // =end terminates the comment block
290 if (ch
== 'd' && chPrev
== 'n' && chPrev2
== 'e') {
291 if (styler
.SafeGetCharAt(i
- 3) == '=') {
292 styler
.ColourTo(i
, state
);
293 state
= SCE_P_DEFAULT
;
301 if (state
== SCE_P_WORD
) {
302 ClassifyWordRb(styler
.GetStartSegment(), lengthDoc
-1, keywords
, styler
, prevWord
);
304 styler
.ColourTo(lengthDoc
-1, state
);
308 static void FoldRbDoc(unsigned int startPos
, int length
, int initStyle
,
309 WordList
*[], Accessor
&styler
) {
310 int lengthDoc
= startPos
+ length
;
312 // Backtrack to previous line in case need to fix its fold status
313 int lineCurrent
= styler
.GetLine(startPos
);
315 if (lineCurrent
> 0) {
317 startPos
= styler
.LineStart(lineCurrent
);
319 initStyle
= SCE_P_DEFAULT
;
321 initStyle
= styler
.StyleAt(startPos
-1);
324 int state
= initStyle
& 31;
326 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsRbComment
);
327 if ((state
== SCE_P_TRIPLE
) || (state
== SCE_P_TRIPLEDOUBLE
))
328 indentCurrent
|= SC_FOLDLEVELWHITEFLAG
;
329 char chNext
= styler
[startPos
];
330 for (int i
= startPos
; i
< lengthDoc
; i
++) {
332 chNext
= styler
.SafeGetCharAt(i
+ 1);
333 int style
= styler
.StyleAt(i
) & 31;
335 if ((ch
== '\r' && chNext
!= '\n') || (ch
== '\n') || (i
== lengthDoc
)) {
336 int lev
= indentCurrent
;
337 int indentNext
= styler
.IndentAmount(lineCurrent
+ 1, &spaceFlags
, IsRbComment
);
338 if ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
))
339 indentNext
|= SC_FOLDLEVELWHITEFLAG
;
340 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
)) {
341 // Only non whitespace lines can be headers
342 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext
& SC_FOLDLEVELNUMBERMASK
)) {
343 lev
|= SC_FOLDLEVELHEADERFLAG
;
344 } else if (indentNext
& SC_FOLDLEVELWHITEFLAG
) {
345 // Line after is blank so check the next - maybe should continue further?
347 int indentNext2
= styler
.IndentAmount(lineCurrent
+ 2, &spaceFlags2
, IsRbComment
);
348 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) < (indentNext2
& SC_FOLDLEVELNUMBERMASK
)) {
349 lev
|= SC_FOLDLEVELHEADERFLAG
;
353 indentCurrent
= indentNext
;
354 styler
.SetLevel(lineCurrent
, lev
);
360 static const char * const rubyWordListDesc
[] = {
365 LexerModule
lmRuby(SCLEX_RUBY
, ColouriseRbDoc
, "ruby", FoldRbDoc
, rubyWordListDesc
);