51
51
static inline bool isSafeWordcharOrHigh(char ch) {
52
return isHighBitChar(ch) || iswordchar(ch);
52
// Error: scintilla's KeyWords.h includes '.' as a word-char
53
// we want to separate things that can take methods from the
55
return isHighBitChar(ch) || isalnum(ch) || ch == '_';
55
58
static bool inline iswhitespace(char ch) {
97
100
static int ClassifyWordRb(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler, char *prevWord) {
101
char s[MAX_KEYWORD_LENGTH];
99
102
unsigned int i, j;
100
103
unsigned int lim = end - start + 1; // num chars to copy
101
104
if (lim >= MAX_KEYWORD_LENGTH) {
244
// This class is used by the enter and exit methods, so it needs
245
// to be hoisted out of the function.
265
QuoteCls(const QuoteCls& q) {
266
// copy constructor -- use this for copying in
271
QuoteCls& operator=(const QuoteCls& q) { // assignment constructor
283
static void enterInnerExpression(int *p_inner_string_types,
284
int *p_inner_expn_brace_counts,
285
QuoteCls *p_inner_quotes,
286
int& inner_string_count,
291
p_inner_string_types[inner_string_count] = state;
292
state = SCE_RB_DEFAULT;
293
p_inner_expn_brace_counts[inner_string_count] = brace_counts;
295
p_inner_quotes[inner_string_count] = curr_quote;
296
++inner_string_count;
299
static void exitInnerExpression(int *p_inner_string_types,
300
int *p_inner_expn_brace_counts,
301
QuoteCls *p_inner_quotes,
302
int& inner_string_count,
307
--inner_string_count;
308
state = p_inner_string_types[inner_string_count];
309
brace_counts = p_inner_expn_brace_counts[inner_string_count];
310
curr_quote = p_inner_quotes[inner_string_count];
242
313
static bool isEmptyLine(int pos,
243
314
Accessor &styler) {
644
696
char chPrev = styler.SafeGetCharAt(startPos - 1);
645
697
char chNext = styler.SafeGetCharAt(startPos);
698
bool is_real_number = true; // Differentiate between constants and ?-sequences.
646
699
// Ruby uses a different mask because bad indentation is marked by oring with 32
647
700
styler.StartAt(startPos, 127);
648
701
styler.StartSegment(startPos);
654
707
SCE_RB_STRING_QW,
655
708
SCE_RB_STRING_QX};
656
709
static const char* q_chars = "qQrwWx";
658
for (int i = startPos; i < lengthDoc; i++) {
711
// In most cases a value of 2 should be ample for the code in the
712
// Ruby library, and the code the user is likely to enter.
714
// fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}"
715
// if options[:verbose]
716
// from fileutils.rb nests to a level of 2
717
// If the user actually hits a 6th occurrence of '#{' in a double-quoted
718
// string (including regex'es, %Q, %<sym>, %w, and other strings
719
// that interpolate), it will stay as a string. The problem with this
720
// is that quotes might flip, a 7th '#{' will look like a comment,
721
// and code-folding might be wrong.
723
// If anyone runs into this problem, I recommend raising this
724
// value slightly higher to replacing the fixed array with a linked
725
// list. Keep in mind this code will be called everytime the lexer
728
#define INNER_STRINGS_MAX_COUNT 5
729
// These vars track our instances of "...#{,,,%Q<..#{,,,}...>,,,}..."
730
int inner_string_types[INNER_STRINGS_MAX_COUNT];
731
// Track # braces when we push a new #{ thing
732
int inner_expn_brace_counts[INNER_STRINGS_MAX_COUNT];
733
QuoteCls inner_quotes[INNER_STRINGS_MAX_COUNT];
734
int inner_string_count = 0;
735
int brace_counts = 0; // Number of #{ ... } things within an expression
738
for (i = 0; i < INNER_STRINGS_MAX_COUNT; i++) {
739
inner_string_types[i] = 0;
740
inner_expn_brace_counts[i] = 0;
742
for (i = startPos; i < lengthDoc; i++) {
659
743
char ch = chNext;
660
744
chNext = styler.SafeGetCharAt(i + 1);
661
745
char chNext2 = styler.SafeGetCharAt(i + 2);
699
784
state = SCE_RB_COMMENTLINE;
700
785
} else if (ch == '=') {
701
786
// =begin indicates the start of a comment (doc) block
702
if (i == 0 || isEOLChar(chPrev)
787
if (i == 0 || (isEOLChar(chPrev)
704
789
&& styler.SafeGetCharAt(i + 2) == 'e'
705
790
&& styler.SafeGetCharAt(i + 3) == 'g'
706
791
&& styler.SafeGetCharAt(i + 4) == 'i'
707
792
&& styler.SafeGetCharAt(i + 5) == 'n'
708
&& !isSafeWordcharOrHigh(styler.SafeGetCharAt(i + 6))) {
793
&& !isSafeWordcharOrHigh(styler.SafeGetCharAt(i + 6)))) {
709
794
styler.ColourTo(i - 1, state);
710
795
state = SCE_RB_POD;
885
970
chNext = styler.SafeGetCharAt(i + 1);
886
971
have_string = true;
888
} else if (!isSafeWordcharOrHigh(chNext)) {
973
} else if (preferRE && !isSafeWordcharOrHigh(chNext)) {
889
974
// Ruby doesn't allow high bit chars here,
890
975
// but the editor host might
891
976
state = SCE_RB_STRING_QQ;
898
983
// stay in default
986
} else if (ch == '?') {
987
styler.ColourTo(i - 1, state);
988
if (iswhitespace(chNext) || chNext == '\n' || chNext == '\r') {
989
styler.ColourTo(i, SCE_RB_OPERATOR);
991
// It's the start of a character code escape sequence
992
// Color it as a number.
993
state = SCE_RB_NUMBER;
994
is_real_number = false;
901
996
} else if (isoperator(ch) || ch == '.') {
902
997
styler.ColourTo(i - 1, state);
903
998
styler.ColourTo(i, SCE_RB_OPERATOR);
909
1004
// we aren't ending an object exp'n, and ops
910
1005
// like : << / are unary operators.
912
preferRE = (strchr(")}].", ch) == NULL);
1010
} else if (ch == '}' && --brace_counts < 0
1011
&& inner_string_count > 0) {
1012
styler.ColourTo(i, SCE_RB_OPERATOR);
1013
exitInnerExpression(inner_string_types,
1014
inner_expn_brace_counts,
1017
state, brace_counts, Quote);
1019
preferRE = (strchr(")}].", ch) == NULL);
913
1021
// Stay in default state
914
1022
} else if (isEOLChar(ch)) {
915
1023
// Make sure it's a true line-end, with no backslash
986
1094
} else if (state == SCE_RB_NUMBER) {
987
if (isSafeAlnumOrHigh(ch) || ch == '_') {
1095
if (!is_real_number) {
1097
styler.ColourTo(i, state);
1098
state = SCE_RB_DEFAULT;
1100
} else if (strchr("\\ntrfvaebs", chNext)) {
1101
// Terminal escape sequence -- handle it next time
1102
// Nothing more to do this time through the loop
1103
} else if (chNext == 'C' || chNext == 'M') {
1104
if (chNext2 != '-') {
1105
// \C or \M ends the sequence -- handle it next time
1107
// Move from abc?\C-x
1113
chNext = styler.SafeGetCharAt(i + 1);
1115
} else if (chNext == 'c') {
1116
// Stay here, \c is a combining sequence
1117
advance_char(i, ch, chNext, chNext2); // pass by ref
1119
// ?\x, including ?\\ is final.
1120
styler.ColourTo(i + 1, state);
1121
state = SCE_RB_DEFAULT;
1123
advance_char(i, ch, chNext, chNext2);
1125
} else if (isSafeAlnumOrHigh(ch) || ch == '_') {
989
1127
} else if (ch == '.' && ++numDots == 1) {
1157
1295
} else if (ch == '#' ) {
1158
//todo: distinguish comments from pound chars
1159
// for now, handle as comment
1160
styler.ColourTo(i - 1, state);
1161
bool inEscape = false;
1162
while (++i < lengthDoc) {
1163
ch = styler.SafeGetCharAt(i);
1166
} else if (isEOLChar(ch)) {
1167
// Comment inside a regex
1168
styler.ColourTo(i - 1, SCE_RB_COMMENTLINE);
1170
} else if (inEscape) {
1171
inEscape = false; // don't look at char
1172
} else if (ch == Quote.Down) {
1173
// Have the regular handler deal with this
1174
// to get trailing modifiers.
1297
&& inner_string_count < INNER_STRINGS_MAX_COUNT) {
1299
styler.ColourTo(i - 1, state);
1300
styler.ColourTo(i + 1, SCE_RB_OPERATOR);
1301
enterInnerExpression(inner_string_types,
1302
inner_expn_brace_counts,
1310
advance_char(i, ch, chNext, chNext2);
1312
//todo: distinguish comments from pound chars
1313
// for now, handle as comment
1314
styler.ColourTo(i - 1, state);
1315
bool inEscape = false;
1316
while (++i < lengthDoc) {
1317
ch = styler.SafeGetCharAt(i);
1320
} else if (isEOLChar(ch)) {
1321
// Comment inside a regex
1322
styler.ColourTo(i - 1, SCE_RB_COMMENTLINE);
1324
} else if (inEscape) {
1325
inEscape = false; // don't look at char
1326
} else if (ch == Quote.Down) {
1327
// Have the regular handler deal with this
1328
// to get trailing modifiers.
1334
chNext = styler.SafeGetCharAt(i + 1);
1335
chNext2 = styler.SafeGetCharAt(i + 2);
1180
chNext = styler.SafeGetCharAt(i + 1);
1181
chNext2 = styler.SafeGetCharAt(i + 2);
1183
1338
// Quotes of all kinds...
1184
1339
} else if (state == SCE_RB_STRING_Q || state == SCE_RB_STRING_QQ ||
1200
1355
} else if (ch == Quote.Up) {
1357
} else if (ch == '#' && chNext == '{'
1358
&& inner_string_count < INNER_STRINGS_MAX_COUNT
1359
&& state != SCE_RB_CHARACTER
1360
&& state != SCE_RB_STRING_Q) {
1362
styler.ColourTo(i - 1, state);
1363
styler.ColourTo(i + 1, SCE_RB_OPERATOR);
1364
enterInnerExpression(inner_string_types,
1365
inner_expn_brace_counts,
1373
advance_char(i, ch, chNext, chNext2);