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
/* Scans a sequence of digits, returning true if it found any. */
234
static bool ScanDigits(Accessor& styler, int& pos, int base) {
237
int c = styler.SafeGetCharAt(pos, '\0');
238
if (IsADigit(c, base) || c == '_')
243
return old_pos != pos;
246
/* Scans an integer and floating point literals. */
247
static void ScanNumber(Accessor& styler, int& pos) {
249
int c = styler.SafeGetCharAt(pos, '\0');
250
int n = styler.SafeGetCharAt(pos + 1, '\0');
252
/* Scan the prefix, thus determining the base.
253
* 10 is default if there's no prefix. */
254
if (c == '0' && n == 'x') {
257
} else if (c == '0' && n == 'b') {
260
} else if (c == '0' && n == 'o') {
265
/* Scan initial digits. The literal is malformed if there are none. */
266
error |= !ScanDigits(styler, pos, base);
267
/* See if there's an integer suffix. We mimic the Rust's lexer
268
* and munch it even if there was an error above. */
269
c = styler.SafeGetCharAt(pos, '\0');
270
if (c == 'u' || c == 'i') {
272
c = styler.SafeGetCharAt(pos, '\0');
273
n = styler.SafeGetCharAt(pos + 1, '\0');
276
} else if (c == '1' && n == '6') {
278
} else if (c == '3' && n == '2') {
280
} else if (c == '6' && n == '4') {
283
/* See if it's a floating point literal. These literals have to be base 10.
286
/* If there's a period, it's a floating point literal unless it's
287
* followed by an identifier (meaning this is a method call, e.g.
288
* `1.foo()`) or another period, in which case it's a range (e.g. 1..2)
290
n = styler.SafeGetCharAt(pos + 1, '\0');
291
if (c == '.' && !(IsIdentifierStart(n) || n == '.')) {
294
/* It's ok to have no digits after the period. */
295
ScanDigits(styler, pos, 10);
298
/* Look for the exponentiation. */
299
c = styler.SafeGetCharAt(pos, '\0');
300
if (c == 'e' || c == 'E') {
303
c = styler.SafeGetCharAt(pos, '\0');
304
if (c == '-' || c == '+')
306
/* It is invalid to have no digits in the exponent. */
307
error |= !ScanDigits(styler, pos, 10);
310
/* Scan the floating point suffix. */
311
c = styler.SafeGetCharAt(pos, '\0');
315
c = styler.SafeGetCharAt(pos, '\0');
316
n = styler.SafeGetCharAt(pos + 1, '\0');
317
if (c == '3' && n == '2') {
319
} else if (c == '6' && n == '4') {
328
styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
330
styler.ColourTo(pos - 1, SCE_RUST_NUMBER);
333
static bool IsOneCharOperator(int c) {
334
return c == ';' || c == ',' || c == '(' || c == ')'
335
|| c == '{' || c == '}' || c == '[' || c == ']'
336
|| c == '@' || c == '#' || c == '~' || c == '+'
337
|| c == '*' || c == '/' || c == '^' || c == '%'
338
|| c == '.' || c == ':' || c == '!' || c == '<'
339
|| c == '>' || c == '=' || c == '-' || c == '&'
340
|| c == '|' || c == '$';
343
static bool IsTwoCharOperator(int c, int n) {
344
return (c == '.' && n == '.') || (c == ':' && n == ':')
345
|| (c == '!' && n == '=') || (c == '<' && n == '<')
346
|| (c == '<' && n == '=') || (c == '>' && n == '>')
347
|| (c == '>' && n == '=') || (c == '=' && n == '=')
348
|| (c == '=' && n == '>') || (c == '-' && n == '>')
349
|| (c == '&' && n == '&') || (c == '|' && n == '|')
350
|| (c == '-' && n == '=') || (c == '&' && n == '=')
351
|| (c == '|' && n == '=') || (c == '+' && n == '=')
352
|| (c == '*' && n == '=') || (c == '/' && n == '=')
353
|| (c == '^' && n == '=') || (c == '%' && n == '=');
356
static bool IsThreeCharOperator(int c, int n, int n2) {
357
return (c == '<' && n == '<' && n2 == '=')
358
|| (c == '>' && n == '>' && n2 == '=');
361
static bool IsValidCharacterEscape(int c) {
362
return c == 'n' || c == 'r' || c == 't' || c == '\\'
363
|| c == '\'' || c == '"' || c == '0';
366
static bool IsValidStringEscape(int c) {
367
return IsValidCharacterEscape(c) || c == '\n' || c == '\r';
370
static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool stop_asap) {
372
int c = styler.SafeGetCharAt(pos, '\0');
373
if (!IsADigit(c, 16))
377
if (num_digits == 0 && stop_asap)
380
if (num_digits == 0) {
387
/* This is overly permissive for character literals in order to accept UTF-8 encoded
388
* character literals. */
389
static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos, bool ascii_only) {
391
int c = styler.SafeGetCharAt(pos, '\0');
392
int n = styler.SafeGetCharAt(pos + 1, '\0');
394
bool valid_lifetime = !ascii_only && IsIdentifierStart(c);
395
bool valid_char = true;
401
if (IsValidCharacterEscape(n)) {
403
} else if (n == 'x') {
405
valid_char = ScanNumericEscape(styler, pos, 2, false);
406
} else if (n == 'u' && !ascii_only) {
408
valid_char = ScanNumericEscape(styler, pos, 4, false);
409
} else if (n == 'U' && !ascii_only) {
411
valid_char = ScanNumericEscape(styler, pos, 8, false);
428
if (ascii_only && !IsASCII((char)c)) {
431
} else if (!IsIdentifierContinue(c) && !first) {
438
c = styler.SafeGetCharAt(pos, '\0');
439
n = styler.SafeGetCharAt(pos + 1, '\0');
443
if (styler.SafeGetCharAt(pos, '\0') == '\'') {
444
valid_lifetime = false;
448
if (valid_lifetime) {
449
styler.ColourTo(pos - 1, SCE_RUST_LIFETIME);
450
} else if (valid_char) {
452
styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTECHARACTER : SCE_RUST_CHARACTER);
454
styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
465
* 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.
466
* Otherwise it's a regular comment.
468
static void ResumeBlockComment(Accessor &styler, int& pos, int max, CommentState state, int level) {
469
int c = styler.SafeGetCharAt(pos, '\0');
470
bool maybe_doc_comment = false;
472
int n = styler.SafeGetCharAt(pos + 1, '\0');
473
if (n != '*' && n != '/') {
474
maybe_doc_comment = true;
476
} else if (c == '!') {
477
maybe_doc_comment = true;
481
int n = styler.SafeGetCharAt(pos + 1, '\0');
482
if (pos == styler.LineEnd(styler.GetLine(pos)))
483
styler.SetLineState(styler.GetLine(pos), level);
490
styler.SetLineState(styler.GetLine(pos), 0);
491
if (state == DocComment || (state == UnknownComment && maybe_doc_comment))
492
styler.ColourTo(pos - 1, SCE_RUST_COMMENTBLOCKDOC);
494
styler.ColourTo(pos - 1, SCE_RUST_COMMENTBLOCK);
498
} else if (c == '/') {
509
if (state == DocComment || (state == UnknownComment && maybe_doc_comment))
510
styler.ColourTo(pos - 1, SCE_RUST_COMMENTBLOCKDOC);
512
styler.ColourTo(pos - 1, SCE_RUST_COMMENTBLOCK);
515
c = styler.SafeGetCharAt(pos, '\0');
520
* The rule for line-doc comments is as follows... ///N and //! (where N is a non slash) start doc comments.
521
* Otherwise it's a normal line comment.
523
static void ResumeLineComment(Accessor &styler, int& pos, int max, CommentState state) {
524
bool maybe_doc_comment = false;
525
int c = styler.SafeGetCharAt(pos, '\0');
529
c = styler.SafeGetCharAt(pos, '\0');
531
maybe_doc_comment = true;
534
} else if (c == '!') {
535
maybe_doc_comment = true;
538
while (pos < max && c != '\n') {
539
if (pos == styler.LineEnd(styler.GetLine(pos)))
540
styler.SetLineState(styler.GetLine(pos), 0);
542
c = styler.SafeGetCharAt(pos, '\0');
545
if (state == DocComment || (state == UnknownComment && maybe_doc_comment))
546
styler.ColourTo(pos - 1, SCE_RUST_COMMENTLINEDOC);
548
styler.ColourTo(pos - 1, SCE_RUST_COMMENTLINE);
551
static void ScanComments(Accessor &styler, int& pos, int max) {
553
int c = styler.SafeGetCharAt(pos, '\0');
556
ResumeLineComment(styler, pos, max, UnknownComment);
558
ResumeBlockComment(styler, pos, max, UnknownComment, 1);
561
static void ResumeString(Accessor &styler, int& pos, int max, bool ascii_only) {
562
int c = styler.SafeGetCharAt(pos, '\0');
564
while (c != '"' && !error) {
569
if (pos == styler.LineEnd(styler.GetLine(pos)))
570
styler.SetLineState(styler.GetLine(pos), 0);
572
int n = styler.SafeGetCharAt(pos + 1, '\0');
573
if (IsValidStringEscape(n)) {
575
} else if (n == 'x') {
577
error = !ScanNumericEscape(styler, pos, 2, true);
578
} else if (n == 'u' && !ascii_only) {
580
error = !ScanNumericEscape(styler, pos, 4, true);
581
} else if (n == 'U' && !ascii_only) {
583
error = !ScanNumericEscape(styler, pos, 8, true);
589
if (ascii_only && !IsASCII((char)c))
594
c = styler.SafeGetCharAt(pos, '\0');
598
styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRING : SCE_RUST_STRING);
601
static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes, bool ascii_only) {
603
if (pos == styler.LineEnd(styler.GetLine(pos)))
604
styler.SetLineState(styler.GetLine(pos), num_hashes);
606
int c = styler.SafeGetCharAt(pos, '\0');
609
int trailing_num_hashes = 0;
610
while (styler.SafeGetCharAt(pos, '\0') == '#' && trailing_num_hashes < num_hashes) {
611
trailing_num_hashes++;
614
if (trailing_num_hashes == num_hashes) {
615
styler.SetLineState(styler.GetLine(pos), 0);
618
} else if (pos >= max) {
621
if (ascii_only && !IsASCII((char)c))
626
styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRINGR : SCE_RUST_STRINGR);
629
static void ScanRawString(Accessor &styler, int& pos, int max, bool ascii_only) {
632
while (styler.SafeGetCharAt(pos, '\0') == '#') {
636
if (styler.SafeGetCharAt(pos, '\0') != '"') {
637
styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
640
ResumeRawString(styler, pos, max, num_hashes, ascii_only);
644
void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
646
Accessor styler(pAccess, &props);
648
int max = pos + length;
651
styler.StartSegment(pos);
653
if (initStyle == SCE_RUST_COMMENTBLOCK || initStyle == SCE_RUST_COMMENTBLOCKDOC) {
654
ResumeBlockComment(styler, pos, max, initStyle == SCE_RUST_COMMENTBLOCKDOC ? DocComment : NotDocComment, styler.GetLineState(styler.GetLine(pos) - 1));
655
} else if (initStyle == SCE_RUST_COMMENTLINE || initStyle == SCE_RUST_COMMENTLINEDOC) {
656
ResumeLineComment(styler, pos, max, initStyle == SCE_RUST_COMMENTLINEDOC ? DocComment : NotDocComment);
657
} else if (initStyle == SCE_RUST_STRING) {
658
ResumeString(styler, pos, max, false);
659
} else if (initStyle == SCE_RUST_BYTESTRING) {
660
ResumeString(styler, pos, max, true);
661
} else if (initStyle == SCE_RUST_STRINGR) {
662
ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), false);
663
} else if (initStyle == SCE_RUST_BYTESTRINGR) {
664
ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), true);
668
int c = styler.SafeGetCharAt(pos, '\0');
669
int n = styler.SafeGetCharAt(pos + 1, '\0');
670
int n2 = styler.SafeGetCharAt(pos + 2, '\0');
672
if (pos == 0 && c == '#' && n == '!' && n2 != '[') {
674
ResumeLineComment(styler, pos, max, NotDocComment);
675
} else if (IsWhitespace(c)) {
676
ScanWhitespace(styler, pos, max);
677
} else if (c == '/' && (n == '/' || n == '*')) {
678
ScanComments(styler, pos, max);
679
} else if (c == 'r' && (n == '#' || n == '"')) {
680
ScanRawString(styler, pos, max, false);
681
} else if (c == 'b' && n == 'r' && (n2 == '#' || n2 == '"')) {
683
ScanRawString(styler, pos, max, true);
684
} else if (c == 'b' && n == '"') {
686
ResumeString(styler, pos, max, true);
687
} else if (c == 'b' && n == '\'') {
689
ScanCharacterLiteralOrLifetime(styler, pos, true);
690
} else if (IsIdentifierStart(c)) {
691
ScanIdentifier(styler, pos, keywords);
692
} else if (IsADigit(c)) {
693
ScanNumber(styler, pos);
694
} else if (IsThreeCharOperator(c, n, n2)) {
696
styler.ColourTo(pos - 1, SCE_RUST_OPERATOR);
697
} else if (IsTwoCharOperator(c, n)) {
699
styler.ColourTo(pos - 1, SCE_RUST_OPERATOR);
700
} else if (IsOneCharOperator(c)) {
702
styler.ColourTo(pos - 1, SCE_RUST_OPERATOR);
703
} else if (c == '\'') {
704
ScanCharacterLiteralOrLifetime(styler, pos, false);
705
} else if (c == '"') {
707
ResumeString(styler, pos, max, false);
710
styler.ColourTo(pos - 1, SCE_RUST_LEXERROR);
713
styler.ColourTo(pos - 1, SCE_RUST_DEFAULT);
717
void SCI_METHOD LexerRust::Fold(unsigned int startPos, int length, int initStyle, IDocument *pAccess) {
722
LexAccessor styler(pAccess);
724
unsigned int endPos = startPos + length;
725
int visibleChars = 0;
726
bool inLineComment = false;
727
int lineCurrent = styler.GetLine(startPos);
728
int levelCurrent = SC_FOLDLEVELBASE;
730
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
731
unsigned int lineStartNext = styler.LineStart(lineCurrent+1);
732
int levelMinCurrent = levelCurrent;
733
int levelNext = levelCurrent;
734
char chNext = styler[startPos];
735
int styleNext = styler.StyleAt(startPos);
736
int style = initStyle;
737
const bool userDefinedFoldMarkers = !options.foldExplicitStart.empty() && !options.foldExplicitEnd.empty();
738
for (unsigned int i = startPos; i < endPos; i++) {
740
chNext = styler.SafeGetCharAt(i + 1);
741
int stylePrev = style;
743
styleNext = styler.StyleAt(i + 1);
744
bool atEOL = i == (lineStartNext-1);
745
if ((style == SCE_RUST_COMMENTLINE) || (style == SCE_RUST_COMMENTLINEDOC))
746
inLineComment = true;
747
if (options.foldComment && options.foldCommentMultiline && IsStreamCommentStyle(style) && !inLineComment) {
748
if (!IsStreamCommentStyle(stylePrev)) {
750
} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
751
// Comments don't end at end of line and the next character may be unstyled.
755
if (options.foldComment && options.foldCommentExplicit && ((style == SCE_RUST_COMMENTLINE) || options.foldExplicitAnywhere)) {
756
if (userDefinedFoldMarkers) {
757
if (styler.Match(i, options.foldExplicitStart.c_str())) {
759
} else if (styler.Match(i, options.foldExplicitEnd.c_str())) {
763
if ((ch == '/') && (chNext == '/')) {
764
char chNext2 = styler.SafeGetCharAt(i + 2);
765
if (chNext2 == '{') {
767
} else if (chNext2 == '}') {
773
if (options.foldSyntaxBased && (style == SCE_RUST_OPERATOR)) {
775
// Measure the minimum before a '{' to allow
776
// folding on "} else {"
777
if (levelMinCurrent > levelNext) {
778
levelMinCurrent = levelNext;
781
} else if (ch == '}') {
787
if (atEOL || (i == endPos-1)) {
788
int levelUse = levelCurrent;
789
if (options.foldSyntaxBased && options.foldAtElse) {
790
levelUse = levelMinCurrent;
792
int lev = levelUse | levelNext << 16;
793
if (visibleChars == 0 && options.foldCompact)
794
lev |= SC_FOLDLEVELWHITEFLAG;
795
if (levelUse < levelNext)
796
lev |= SC_FOLDLEVELHEADERFLAG;
797
if (lev != styler.LevelAt(lineCurrent)) {
798
styler.SetLevel(lineCurrent, lev);
801
lineStartNext = styler.LineStart(lineCurrent+1);
802
levelCurrent = levelNext;
803
levelMinCurrent = levelCurrent;
804
if (atEOL && (i == static_cast<unsigned int>(styler.Length()-1))) {
805
// There is an empty line at end of file so give it same level and empty
806
styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
809
inLineComment = false;
814
LexerModule lmRust(SCLEX_RUST, LexerRust::LexerFactoryRust, "rust", rustWordLists);