4 ** Copyright (c) 2013 by SiegeLord <slabode@aim.com>
5 ** Converted to lexer object and added further folding features/properties by "Udo Lechner" <dlchnr(at)gmx(dot)net>
7 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
21 #include "Scintilla.h"
24 #include "PropSetSimple.h"
26 #include "LexAccessor.h"
28 #include "StyleContext.h"
29 #include "CharacterSet.h"
30 #include "LexerModule.h"
31 #include "OptionSet.h"
34 using namespace Scintilla
;
37 static const int NUM_RUST_KEYWORD_LISTS
= 7;
38 static const int MAX_RUST_IDENT_CHARS
= 1023;
40 static bool IsStreamCommentStyle(int style
) {
41 return style
== SCE_RUST_COMMENTBLOCK
||
42 style
== SCE_RUST_COMMENTBLOCKDOC
;
45 // Options used for LexerRust
50 bool foldCommentMultiline
;
51 bool foldCommentExplicit
;
52 std::string foldExplicitStart
;
53 std::string foldExplicitEnd
;
54 bool foldExplicitAnywhere
;
60 foldSyntaxBased
= true;
62 foldCommentMultiline
= true;
63 foldCommentExplicit
= true;
64 foldExplicitStart
= "";
66 foldExplicitAnywhere
= false;
73 static const char * const rustWordLists
[NUM_RUST_KEYWORD_LISTS
+ 1] = {
74 "Primary keywords and identifiers",
84 struct OptionSetRust
: public OptionSet
<OptionsRust
> {
86 DefineProperty("fold", &OptionsRust::fold
);
88 DefineProperty("fold.comment", &OptionsRust::foldComment
);
90 DefineProperty("fold.compact", &OptionsRust::foldCompact
);
92 DefineProperty("fold.at.else", &OptionsRust::foldAtElse
);
94 DefineProperty("fold.rust.syntax.based", &OptionsRust::foldSyntaxBased
,
95 "Set this property to 0 to disable syntax based folding.");
97 DefineProperty("fold.rust.comment.multiline", &OptionsRust::foldCommentMultiline
,
98 "Set this property to 0 to disable folding multi-line comments when fold.comment=1.");
100 DefineProperty("fold.rust.comment.explicit", &OptionsRust::foldCommentExplicit
,
101 "Set this property to 0 to disable folding explicit fold points when fold.comment=1.");
103 DefineProperty("fold.rust.explicit.start", &OptionsRust::foldExplicitStart
,
104 "The string to use for explicit fold start points, replacing the standard //{.");
106 DefineProperty("fold.rust.explicit.end", &OptionsRust::foldExplicitEnd
,
107 "The string to use for explicit fold end points, replacing the standard //}.");
109 DefineProperty("fold.rust.explicit.anywhere", &OptionsRust::foldExplicitAnywhere
,
110 "Set this property to 1 to enable explicit fold points anywhere, not just in line comments.");
112 DefineProperty("lexer.rust.fold.at.else", &OptionsRust::foldAtElseInt
,
113 "This option enables Rust folding on a \"} else {\" line of an if statement.");
115 DefineWordListSets(rustWordLists
);
119 class LexerRust
: public ILexer
{
120 WordList keywords
[NUM_RUST_KEYWORD_LISTS
];
122 OptionSetRust osRust
;
124 virtual ~LexerRust() {
126 void SCI_METHOD
Release() {
129 int SCI_METHOD
Version() const {
132 const char * SCI_METHOD
PropertyNames() {
133 return osRust
.PropertyNames();
135 int SCI_METHOD
PropertyType(const char *name
) {
136 return osRust
.PropertyType(name
);
138 const char * SCI_METHOD
DescribeProperty(const char *name
) {
139 return osRust
.DescribeProperty(name
);
141 int SCI_METHOD
PropertySet(const char *key
, const char *val
);
142 const char * SCI_METHOD
DescribeWordListSets() {
143 return osRust
.DescribeWordListSets();
145 int SCI_METHOD
WordListSet(int n
, const char *wl
);
146 void SCI_METHOD
Lex(unsigned int startPos
, int length
, int initStyle
, IDocument
*pAccess
);
147 void SCI_METHOD
Fold(unsigned int startPos
, int length
, int initStyle
, IDocument
*pAccess
);
148 void * SCI_METHOD
PrivateCall(int, void *) {
151 static ILexer
*LexerFactoryRust() {
152 return new LexerRust();
156 int SCI_METHOD
LexerRust::PropertySet(const char *key
, const char *val
) {
157 if (osRust
.PropertySet(&options
, key
, val
)) {
163 int SCI_METHOD
LexerRust::WordListSet(int n
, const char *wl
) {
164 int firstModification
= -1;
165 if (n
< NUM_RUST_KEYWORD_LISTS
) {
166 WordList
*wordListN
= &keywords
[n
];
169 if (*wordListN
!= wlNew
) {
171 firstModification
= 0;
174 return firstModification
;
177 static bool IsWhitespace(int c
) {
178 return c
== ' ' || c
== '\t' || c
== '\r' || c
== '\n';
181 /* This isn't quite right for Unicode identifiers */
182 static bool IsIdentifierStart(int ch
) {
183 return (IsASCII(ch
) && (isalpha(ch
) || ch
== '_')) || !IsASCII(ch
);
186 /* This isn't quite right for Unicode identifiers */
187 static bool IsIdentifierContinue(int ch
) {
188 return (IsASCII(ch
) && (isalnum(ch
) || ch
== '_')) || !IsASCII(ch
);
191 static void ScanWhitespace(Accessor
& styler
, int& pos
, int max
) {
192 while (IsWhitespace(styler
.SafeGetCharAt(pos
, '\0')) && pos
< max
) {
193 if (pos
== styler
.LineEnd(styler
.GetLine(pos
)))
194 styler
.SetLineState(styler
.GetLine(pos
), 0);
197 styler
.ColourTo(pos
-1, SCE_RUST_DEFAULT
);
200 static void GrabString(char* s
, Accessor
& styler
, int start
, int len
) {
201 for (int ii
= 0; ii
< len
; ii
++)
202 s
[ii
] = styler
[ii
+ start
];
206 static void ScanIdentifier(Accessor
& styler
, int& pos
, WordList
*keywords
) {
208 while (IsIdentifierContinue(styler
.SafeGetCharAt(pos
, '\0')))
211 if (styler
.SafeGetCharAt(pos
, '\0') == '!') {
213 styler
.ColourTo(pos
- 1, SCE_RUST_MACRO
);
215 char s
[MAX_RUST_IDENT_CHARS
+ 1];
216 int len
= pos
- start
;
217 len
= len
> MAX_RUST_IDENT_CHARS
? MAX_RUST_IDENT_CHARS
: len
;
218 GrabString(s
, styler
, start
, len
);
219 bool keyword
= false;
220 for (int ii
= 0; ii
< NUM_RUST_KEYWORD_LISTS
; ii
++) {
221 if (keywords
[ii
].InList(s
)) {
222 styler
.ColourTo(pos
- 1, SCE_RUST_WORD
+ ii
);
228 styler
.ColourTo(pos
- 1, SCE_RUST_IDENTIFIER
);
233 static void ScanDigits(Accessor
& styler
, int& pos
, int base
) {
235 int c
= styler
.SafeGetCharAt(pos
, '\0');
236 if (IsADigit(c
, base
) || c
== '_')
243 static void ScanNumber(Accessor
& styler
, int& pos
) {
245 int c
= styler
.SafeGetCharAt(pos
, '\0');
246 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
248 if (c
== '0' && n
== 'x') {
251 } else if (c
== '0' && n
== 'b') {
254 } else if (c
== '0' && n
== 'o') {
259 ScanDigits(styler
, pos
, base
);
260 c
= styler
.SafeGetCharAt(pos
, '\0');
261 if (c
== 'u' || c
== 'i') {
263 c
= styler
.SafeGetCharAt(pos
, '\0');
264 n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
267 } else if (c
== '1' && n
== '6') {
269 } else if (c
== '3' && n
== '2') {
271 } else if (c
== '6' && n
== '4') {
275 n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
276 if (c
== '.' && !(IsIdentifierStart(n
) || n
== '.')) {
279 ScanDigits(styler
, pos
, 10);
282 c
= styler
.SafeGetCharAt(pos
, '\0');
283 if (c
== 'e' || c
== 'E') {
286 c
= styler
.SafeGetCharAt(pos
, '\0');
287 if (c
== '-' || c
== '+')
290 ScanDigits(styler
, pos
, 10);
291 if (old_pos
== pos
) {
296 c
= styler
.SafeGetCharAt(pos
, '\0');
300 c
= styler
.SafeGetCharAt(pos
, '\0');
301 n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
302 if (c
== '3' && n
== '2') {
304 } else if (c
== '6' && n
== '4') {
311 if (old_pos
== pos
) {
315 styler
.ColourTo(pos
- 1, SCE_RUST_LEXERROR
);
317 styler
.ColourTo(pos
- 1, SCE_RUST_NUMBER
);
320 static bool IsOneCharOperator(int c
) {
321 return c
== ';' || c
== ',' || c
== '(' || c
== ')'
322 || c
== '{' || c
== '}' || c
== '[' || c
== ']'
323 || c
== '@' || c
== '#' || c
== '~' || c
== '+'
324 || c
== '*' || c
== '/' || c
== '^' || c
== '%'
325 || c
== '.' || c
== ':' || c
== '!' || c
== '<'
326 || c
== '>' || c
== '=' || c
== '-' || c
== '&'
327 || c
== '|' || c
== '$';
330 static bool IsTwoCharOperator(int c
, int n
) {
331 return (c
== '.' && n
== '.') || (c
== ':' && n
== ':')
332 || (c
== '!' && n
== '=') || (c
== '<' && n
== '<')
333 || (c
== '<' && n
== '=') || (c
== '>' && n
== '>')
334 || (c
== '>' && n
== '=') || (c
== '=' && n
== '=')
335 || (c
== '=' && n
== '>') || (c
== '-' && n
== '>')
336 || (c
== '&' && n
== '&') || (c
== '|' && n
== '|')
337 || (c
== '-' && n
== '=') || (c
== '&' && n
== '=')
338 || (c
== '|' && n
== '=') || (c
== '+' && n
== '=')
339 || (c
== '*' && n
== '=') || (c
== '/' && n
== '=')
340 || (c
== '^' && n
== '=') || (c
== '%' && n
== '=');
343 static bool IsThreeCharOperator(int c
, int n
, int n2
) {
344 return (c
== '<' && n
== '<' && n2
== '=')
345 || (c
== '>' && n
== '>' && n2
== '=');
348 static bool IsValidCharacterEscape(int c
) {
349 return c
== 'n' || c
== 'r' || c
== 't' || c
== '\\'
350 || c
== '\'' || c
== '"' || c
== '0';
353 static bool IsValidStringEscape(int c
) {
354 return IsValidCharacterEscape(c
) || c
== '\n';
357 static bool ScanNumericEscape(Accessor
&styler
, int& pos
, int num_digits
, bool stop_asap
) {
359 int c
= styler
.SafeGetCharAt(pos
, '\0');
360 if (!IsADigit(c
, 16))
364 if (num_digits
== 0 && stop_asap
)
367 if (num_digits
== 0) {
374 /* This is overly permissive for character literals in order to accept UTF-8 encoded
375 * character literals. */
376 static void ScanCharacterLiteralOrLifetime(Accessor
&styler
, int& pos
) {
378 int c
= styler
.SafeGetCharAt(pos
, '\0');
379 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
381 bool valid_lifetime
= IsIdentifierStart(c
);
382 bool valid_char
= true;
388 if (IsValidCharacterEscape(n
)) {
390 } else if (n
== 'x') {
392 valid_char
= ScanNumericEscape(styler
, pos
, 2, false);
393 } else if (n
== 'u') {
395 valid_char
= ScanNumericEscape(styler
, pos
, 4, false);
396 } else if (n
== 'U') {
398 valid_char
= ScanNumericEscape(styler
, pos
, 8, false);
415 if (!IsIdentifierContinue(c
) && !first
) {
422 c
= styler
.SafeGetCharAt(pos
, '\0');
423 n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
427 if (styler
.SafeGetCharAt(pos
, '\0') == '\'') {
428 valid_lifetime
= false;
432 if (valid_lifetime
) {
433 styler
.ColourTo(pos
- 1, SCE_RUST_LIFETIME
);
434 } else if (valid_char
) {
436 styler
.ColourTo(pos
- 1, SCE_RUST_CHARACTER
);
438 styler
.ColourTo(pos
- 1, SCE_RUST_LEXERROR
);
449 * The rule for block-doc comments is as follows: /xxN and /x! (where x is an asterisk, N is a non-asterisk) start doc comments.
450 * Otherwise it's a regular comment.
452 static void ResumeBlockComment(Accessor
&styler
, int& pos
, int max
, CommentState state
, int level
) {
453 int c
= styler
.SafeGetCharAt(pos
, '\0');
454 bool maybe_doc_comment
= false;
456 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
457 if (n
!= '*' && n
!= '/') {
458 maybe_doc_comment
= true;
460 } else if (c
== '!') {
461 maybe_doc_comment
= true;
465 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
466 if (pos
== styler
.LineEnd(styler
.GetLine(pos
)))
467 styler
.SetLineState(styler
.GetLine(pos
), level
);
474 styler
.SetLineState(styler
.GetLine(pos
), 0);
475 if (state
== DocComment
|| (state
== UnknownComment
&& maybe_doc_comment
))
476 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTBLOCKDOC
);
478 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTBLOCK
);
482 } else if (c
== '/') {
493 if (state
== DocComment
|| (state
== UnknownComment
&& maybe_doc_comment
))
494 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTBLOCKDOC
);
496 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTBLOCK
);
499 c
= styler
.SafeGetCharAt(pos
, '\0');
504 * The rule for line-doc comments is as follows... ///N and //! (where N is a non slash) start doc comments.
505 * Otherwise it's a normal line comment.
507 static void ResumeLineComment(Accessor
&styler
, int& pos
, int max
, CommentState state
) {
508 bool maybe_doc_comment
= false;
509 int c
= styler
.SafeGetCharAt(pos
, '\0');
513 c
= styler
.SafeGetCharAt(pos
, '\0');
515 maybe_doc_comment
= true;
518 } else if (c
== '!') {
519 maybe_doc_comment
= true;
522 while (pos
< max
&& c
!= '\n') {
523 if (pos
== styler
.LineEnd(styler
.GetLine(pos
)))
524 styler
.SetLineState(styler
.GetLine(pos
), 0);
526 c
= styler
.SafeGetCharAt(pos
, '\0');
529 if (state
== DocComment
|| (state
== UnknownComment
&& maybe_doc_comment
))
530 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTLINEDOC
);
532 styler
.ColourTo(pos
- 1, SCE_RUST_COMMENTLINE
);
535 static void ScanComments(Accessor
&styler
, int& pos
, int max
) {
537 int c
= styler
.SafeGetCharAt(pos
, '\0');
540 ResumeLineComment(styler
, pos
, max
, UnknownComment
);
542 ResumeBlockComment(styler
, pos
, max
, UnknownComment
, 1);
545 static void ResumeString(Accessor
&styler
, int& pos
, int max
) {
546 int c
= styler
.SafeGetCharAt(pos
, '\0');
548 while (c
!= '"' && !error
) {
553 if (pos
== styler
.LineEnd(styler
.GetLine(pos
)))
554 styler
.SetLineState(styler
.GetLine(pos
), 0);
556 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
557 if (IsValidStringEscape(n
)) {
559 } else if (n
== 'x') {
561 error
= !ScanNumericEscape(styler
, pos
, 2, true);
562 } else if (n
== 'u') {
564 error
= !ScanNumericEscape(styler
, pos
, 4, true);
565 } else if (n
== 'U') {
567 error
= !ScanNumericEscape(styler
, pos
, 8, true);
575 c
= styler
.SafeGetCharAt(pos
, '\0');
579 styler
.ColourTo(pos
- 1, SCE_RUST_STRING
);
582 static void ResumeRawString(Accessor
&styler
, int& pos
, int max
, int num_hashes
) {
584 if (pos
== styler
.LineEnd(styler
.GetLine(pos
)))
585 styler
.SetLineState(styler
.GetLine(pos
), num_hashes
);
587 int c
= styler
.SafeGetCharAt(pos
, '\0');
590 int trailing_num_hashes
= 0;
591 while (styler
.SafeGetCharAt(pos
, '\0') == '#' && trailing_num_hashes
< num_hashes
) {
592 trailing_num_hashes
++;
595 if (trailing_num_hashes
== num_hashes
) {
596 styler
.SetLineState(styler
.GetLine(pos
), 0);
597 styler
.ColourTo(pos
- 1, SCE_RUST_STRINGR
);
600 } else if (pos
>= max
) {
601 styler
.ColourTo(pos
- 1, SCE_RUST_STRINGR
);
609 static void ScanRawString(Accessor
&styler
, int& pos
, int max
) {
612 while (styler
.SafeGetCharAt(pos
, '\0') == '#') {
616 if (styler
.SafeGetCharAt(pos
, '\0') != '"') {
617 styler
.ColourTo(pos
- 1, SCE_RUST_LEXERROR
);
620 ResumeRawString(styler
, pos
, max
, num_hashes
);
624 void SCI_METHOD
LexerRust::Lex(unsigned int startPos
, int length
, int initStyle
, IDocument
*pAccess
) {
626 Accessor
styler(pAccess
, &props
);
628 int max
= pos
+ length
;
631 styler
.StartSegment(pos
);
633 if (initStyle
== SCE_RUST_COMMENTBLOCK
|| initStyle
== SCE_RUST_COMMENTBLOCKDOC
) {
634 ResumeBlockComment(styler
, pos
, max
, initStyle
== SCE_RUST_COMMENTBLOCKDOC
? DocComment
: NotDocComment
, styler
.GetLineState(styler
.GetLine(pos
) - 1));
635 } else if (initStyle
== SCE_RUST_COMMENTLINE
|| initStyle
== SCE_RUST_COMMENTLINEDOC
) {
636 ResumeLineComment(styler
, pos
, max
, initStyle
== SCE_RUST_COMMENTLINEDOC
? DocComment
: NotDocComment
);
637 } else if (initStyle
== SCE_RUST_STRING
) {
638 ResumeString(styler
, pos
, max
);
639 } else if (initStyle
== SCE_RUST_STRINGR
) {
640 ResumeRawString(styler
, pos
, max
, styler
.GetLineState(styler
.GetLine(pos
) - 1));
644 int c
= styler
.SafeGetCharAt(pos
, '\0');
645 int n
= styler
.SafeGetCharAt(pos
+ 1, '\0');
646 int n2
= styler
.SafeGetCharAt(pos
+ 2, '\0');
648 if (pos
== 0 && c
== '#' && n
== '!') {
650 ResumeLineComment(styler
, pos
, max
, NotDocComment
);
651 } else if (IsWhitespace(c
)) {
652 ScanWhitespace(styler
, pos
, max
);
653 } else if (c
== '/' && (n
== '/' || n
== '*')) {
654 ScanComments(styler
, pos
, max
);
655 } else if (c
== 'r' && (n
== '#' || n
== '"')) {
656 ScanRawString(styler
, pos
, max
);
657 } else if (IsIdentifierStart(c
)) {
658 ScanIdentifier(styler
, pos
, keywords
);
659 } else if (IsADigit(c
)) {
660 ScanNumber(styler
, pos
);
661 } else if (IsThreeCharOperator(c
, n
, n2
)) {
663 styler
.ColourTo(pos
- 1, SCE_RUST_OPERATOR
);
664 } else if (IsTwoCharOperator(c
, n
)) {
666 styler
.ColourTo(pos
- 1, SCE_RUST_OPERATOR
);
667 } else if (IsOneCharOperator(c
)) {
669 styler
.ColourTo(pos
- 1, SCE_RUST_OPERATOR
);
670 } else if (c
== '\'') {
671 ScanCharacterLiteralOrLifetime(styler
, pos
);
672 } else if (c
== '"') {
674 ResumeString(styler
, pos
, max
);
677 styler
.ColourTo(pos
- 1, SCE_RUST_LEXERROR
);
680 styler
.ColourTo(pos
- 1, SCE_RUST_DEFAULT
);
684 void SCI_METHOD
LexerRust::Fold(unsigned int startPos
, int length
, int initStyle
, IDocument
*pAccess
) {
689 LexAccessor
styler(pAccess
);
691 unsigned int endPos
= startPos
+ length
;
692 int visibleChars
= 0;
693 bool inLineComment
= false;
694 int lineCurrent
= styler
.GetLine(startPos
);
695 int levelCurrent
= SC_FOLDLEVELBASE
;
697 levelCurrent
= styler
.LevelAt(lineCurrent
-1) >> 16;
698 unsigned int lineStartNext
= styler
.LineStart(lineCurrent
+1);
699 int levelMinCurrent
= levelCurrent
;
700 int levelNext
= levelCurrent
;
701 char chNext
= styler
[startPos
];
702 int styleNext
= styler
.StyleAt(startPos
);
703 int style
= initStyle
;
704 const bool userDefinedFoldMarkers
= !options
.foldExplicitStart
.empty() && !options
.foldExplicitEnd
.empty();
705 for (unsigned int i
= startPos
; i
< endPos
; i
++) {
707 chNext
= styler
.SafeGetCharAt(i
+ 1);
708 int stylePrev
= style
;
710 styleNext
= styler
.StyleAt(i
+ 1);
711 bool atEOL
= i
== (lineStartNext
-1);
712 if ((style
== SCE_RUST_COMMENTLINE
) || (style
== SCE_RUST_COMMENTLINEDOC
))
713 inLineComment
= true;
714 if (options
.foldComment
&& options
.foldCommentMultiline
&& IsStreamCommentStyle(style
) && !inLineComment
) {
715 if (!IsStreamCommentStyle(stylePrev
)) {
717 } else if (!IsStreamCommentStyle(styleNext
) && !atEOL
) {
718 // Comments don't end at end of line and the next character may be unstyled.
722 if (options
.foldComment
&& options
.foldCommentExplicit
&& ((style
== SCE_RUST_COMMENTLINE
) || options
.foldExplicitAnywhere
)) {
723 if (userDefinedFoldMarkers
) {
724 if (styler
.Match(i
, options
.foldExplicitStart
.c_str())) {
726 } else if (styler
.Match(i
, options
.foldExplicitEnd
.c_str())) {
730 if ((ch
== '/') && (chNext
== '/')) {
731 char chNext2
= styler
.SafeGetCharAt(i
+ 2);
732 if (chNext2
== '{') {
734 } else if (chNext2
== '}') {
740 if (options
.foldSyntaxBased
&& (style
== SCE_RUST_OPERATOR
)) {
742 // Measure the minimum before a '{' to allow
743 // folding on "} else {"
744 if (levelMinCurrent
> levelNext
) {
745 levelMinCurrent
= levelNext
;
748 } else if (ch
== '}') {
754 if (atEOL
|| (i
== endPos
-1)) {
755 int levelUse
= levelCurrent
;
756 if (options
.foldSyntaxBased
&& options
.foldAtElse
) {
757 levelUse
= levelMinCurrent
;
759 int lev
= levelUse
| levelNext
<< 16;
760 if (visibleChars
== 0 && options
.foldCompact
)
761 lev
|= SC_FOLDLEVELWHITEFLAG
;
762 if (levelUse
< levelNext
)
763 lev
|= SC_FOLDLEVELHEADERFLAG
;
764 if (lev
!= styler
.LevelAt(lineCurrent
)) {
765 styler
.SetLevel(lineCurrent
, lev
);
768 lineStartNext
= styler
.LineStart(lineCurrent
+1);
769 levelCurrent
= levelNext
;
770 levelMinCurrent
= levelCurrent
;
771 if (atEOL
&& (i
== static_cast<unsigned int>(styler
.Length()-1))) {
772 // There is an empty line at end of file so give it same level and empty
773 styler
.SetLevel(lineCurrent
, (levelCurrent
| levelCurrent
<< 16) | SC_FOLDLEVELWHITEFLAG
);
776 inLineComment
= false;
781 LexerModule
lmRust(SCLEX_RUST
, LexerRust::LexerFactoryRust
, "rust", rustWordLists
);