1 #include "CodeEditor.h"
2
3 namespace Upp {
4
5 #define LTIMING(x) // RTIMING(x)
6
cmps(const wchar * q,const char * s,int & n)7 bool cmps(const wchar *q, const char *s, int& n) {
8 const wchar *t = q;
9 while(*q)
10 if(*q++ != *s++)
11 return false;
12 n += int(q - t);
13 return *q == *s;
14 }
15
IsUpperString(const char * q)16 bool IsUpperString(const char *q)
17 {
18 while(*q)
19 {
20 if(*q != '_' && (*q < '0' || *q > '9') && !IsUpper(*q))
21 return false;
22 q++;
23 }
24 return true;
25 }
26
BlockColor(int level)27 Color CSyntax::BlockColor(int level)
28 {
29 if(hilite_scope == 1)
30 return GetHlStyle(level & 1 ? PAPER_BLOCK1 : PAPER_NORMAL).color;
31 if(hilite_scope == 2) {
32 int q = level % 5;
33 return GetHlStyle(q ? PAPER_BLOCK1 + q - 1 : PAPER_NORMAL).color;
34 }
35 return GetHlStyle(PAPER_NORMAL).color;
36 }
37
Bracket(int64 pos,HighlightOutput & hls,CodeEditor * editor)38 void CSyntax::Bracket(int64 pos, HighlightOutput& hls, CodeEditor *editor) // TODO:SYNTAX: Cleanup passing bracket info
39 {
40 if(!editor)
41 return;
42 if(editor->IsCursorBracket(pos)) {
43 HlStyle& h = hl_style[PAPER_BRACKET0];
44 hls.SetPaper(hls.pos, 1, h.color);
45 hls.SetFont(hls.pos, 1, h);
46 }
47 if(editor->IsMatchingBracket(pos)) {
48 HlStyle& h = hl_style[PAPER_BRACKET];
49 hls.SetPaper(hls.pos, 1, h.color);
50 hls.SetFont(hls.pos, 1, h);
51 }
52 }
53
HighlightNumber(HighlightOutput & hls,const wchar * p,bool ts,bool octal,bool css)54 const wchar *HighlightNumber(HighlightOutput& hls, const wchar *p, bool ts, bool octal, bool css)
55 {
56 int c = octal ? HighlightSetup::INK_CONST_OCT : HighlightSetup::INK_CONST_INT;
57 const wchar *t = p;
58 while(IsDigit(*p)) p++;
59 int fixdigits = int(p - t);
60 bool u = false;
61 if(*p == '.') {
62 c = HighlightSetup::INK_CONST_FLOAT;
63 p++;
64 }
65 while(IsDigit(*p)) p++;
66 if(*p == 'e' || *p == 'E') {
67 c = HighlightSetup::INK_CONST_FLOAT;
68 p++;
69 p += *p == '-' || *p == '+';
70 while(IsDigit(*p)) p++;
71 if(*p == 'f' || *p == 'F')
72 p++;
73 }
74 else
75 if(*p == 'u' && c != HighlightSetup::INK_CONST_FLOAT) {
76 u = true;
77 p++;
78 }
79 if(c == HighlightSetup::INK_CONST_OCT && p - t == (u ? 2 : 1))
80 c = HighlightSetup::INK_CONST_INT;
81 int n = int(p - t);
82 for(int i = 0; i < n; i++) {
83 if(t[i] == 'e')
84 ts = false;
85 hls.Put(HighlightSetup::hl_style[c],
86 c == HighlightSetup::INK_CONST_OCT || (fixdigits < 5 && n - fixdigits < 5)
87 || i == fixdigits || !ts ? 0 :
88 i < fixdigits ? decode((fixdigits - i) % 3, 1, LineEdit::SHIFT_L, 0, LineEdit::SHIFT_R, 0) :
89 decode((i - fixdigits) % 3, 1, LineEdit::SHIFT_R, 0, LineEdit::SHIFT_L, 0));
90 }
91 return p;
92 }
93
HighlightHexBin(HighlightOutput & hls,const wchar * p,int plen,bool thousands_separator)94 const wchar *HighlightHexBin(HighlightOutput& hls, const wchar *p, int plen, bool thousands_separator)
95 {
96 hls.Put(plen, HighlightSetup::hl_style[HighlightSetup::INK_CONST_HEX]);
97 p += plen;
98 const wchar *t = p;
99 while(IsXDigit(*p))
100 p++;
101 int n = int(p - t);
102 for(int i = 0; i < n; i++) {
103 hls.Put(HighlightSetup::hl_style[HighlightSetup::INK_CONST_HEX],
104 thousands_separator && ((n - i) & 1) ? LineEdit::SHIFT_L : 0);
105 }
106 return p;
107 }
108
DoComment(HighlightOutput & hls,const wchar * p,const wchar * e)109 const wchar *CSyntax::DoComment(HighlightOutput& hls, const wchar *p, const wchar *e)
110 {
111 WString w;
112 for(const wchar *s = p; s < e && IsLetter(*s); s++)
113 w.Cat(ToUpper(*s));
114 int n = w.GetCount();
115 word flags = 0;
116 if(n) {
117 if(comments_lang && !SpellWord(w, comments_lang))
118 flags = LineEdit::SPELLERROR;
119 }
120 else
121 for(const wchar *s = p; s < e && !IsLetter(*s); s++)
122 n++;
123 hls.SetFlags(n, flags);
124 static WString todo = "TODO";
125 static WString fixme = "FIXME";
126 if(w.GetCount() >= 4 && w.GetCount() <= 5 && findarg(w, todo, fixme) >= 0)
127 hls.Put(n, hl_style[INK_COMMENT_WORD], hl_style[PAPER_COMMENT_WORD]);
128 else
129 hls.Put(n, hl_style[INK_COMMENT]);
130 return p + n;
131 }
132
RawString(const wchar * p,int & n)133 bool CSyntax::RawString(const wchar *p, int& n) {
134 if(highlight != HIGHLIGHT_CPP)
135 return false;
136 const wchar *s = p;
137 if(*s++ != 'R')
138 return false;
139 while(*s == ' ' || *s == '\t')
140 s++;
141 if(*s++ != '\"')
142 return false;
143 WString rs;
144 while(*s != '(') {
145 if(*s == '\0')
146 return false;
147 rs.Cat(*s++);
148 }
149 raw_string = ")";
150 raw_string.Cat(rs);
151 raw_string.Cat('\"');
152 n = int(s + 1 - p);
153 return true;
154 };
155
Highlight(const wchar * ltext,const wchar * e,HighlightOutput & hls,CodeEditor * editor,int line,int64 pos)156 void CSyntax::Highlight(const wchar *ltext, const wchar *e, HighlightOutput& hls, CodeEditor *editor, int line, int64 pos)
157 {
158 ONCELOCK {
159 InitKeywords();
160 }
161
162 bool include = false;
163
164 int tabsize = editor ? editor->GetTabSize() : 4;
165
166 LTIMING("HighlightLine");
167 if(highlight < 0 || highlight >= keyword.GetCount())
168 return;
169 CSyntax next;
170 next.Set(Get());
171 next.ScanSyntax(ltext, e, line + 1, tabsize);
172 bool macro = next.macro != MACRO_OFF;
173
174 int linelen = int(e - ltext);
175 const wchar *p = ltext;
176
177 for(const wchar *ms = p; ms < e; ms++)
178 if(*ms != ' ' && *ms != '\t') {
179 macro = macro || *ms == '#';
180 break;
181 }
182
183 Grounding(p, e);
184 if(highlight == HIGHLIGHT_CALC) {
185 if(editor && line == editor->GetLineCount() - 1 || *p == '$')
186 hls.SetPaper(0, linelen + 1, hl_style[PAPER_BLOCK1].color);
187 }
188 else
189 hls.SetPaper(0, linelen + 1,
190 macro ? hl_style[PAPER_MACRO].color : hl_style[PAPER_NORMAL].color);
191 int block_level = bid.GetCount() - 1;
192 String cppid;
193 if(!comment && highlight != HIGHLIGHT_CALC) {
194 if(!macro) {
195 int i = 0, bid = 0, pos = 0;
196 while(bid < this->bid.GetCount() - 1
197 && (i >= linelen || p[i] == ' ' || p[i] == '\t')) {
198 hls.SetPaper(i, 1, BlockColor(bid));
199 if(i < linelen && p[i] == '\t' || ++pos >= tabsize) {
200 pos = 0;
201 bid++;
202 }
203 i++;
204 }
205 hls.SetPaper(i, 1 + max(0, linelen - i), BlockColor(this->bid.GetCount() - 1));
206 }
207 while(*p == ' ' || *p == '\t') {
208 p++;
209 hls.Put(hl_style[INK_NORMAL]);
210 }
211 if(*p == '#' && findarg(highlight, HIGHLIGHT_CPP, HIGHLIGHT_CS) >= 0) {
212 static Index<String> macro;
213 ONCELOCK {
214 static const char *pd[] = {
215 "include", "define", "error", "if", "elif", "else", "endif",
216 "ifdef", "ifndef", "line", "undef", "pragma",
217 // CLR
218 "using"
219 };
220 for(int i = 0; i < __countof(pd); i++)
221 macro.Add(pd[i]);
222 }
223 const wchar *q = p + 1;
224 while(*q == ' ' || *q == '\t')
225 q++;
226 StringBuffer id;
227 while(IsAlpha(*q))
228 id.Cat(*q++);
229 cppid = id;
230 int mq = macro.Find(cppid);
231 hls.Put(mq < 0 ? 1 : int(q - p), hl_style[INK_MACRO]);
232 if(mq == 0)
233 include = true;
234 p = q;
235 }
236 }
237 int lindent = int(p - ltext);
238 int lbrace = -1;
239 int lbclose = -1;
240 Color lbcolor = Null;
241 bool is_comment = false;
242 while(p < e) {
243 int raw_n = 0;
244 dword pair = MAKELONG(p[0], p[1]);
245 if(pair == MAKELONG('/', '*') && highlight != HIGHLIGHT_JSON || comment) {
246 if(!comment) {
247 hls.Put(2, hl_style[INK_COMMENT]);
248 p += 2;
249 }
250 for(const wchar *ce = p; ce < e - 1; ce++)
251 if(ce[0] == '*' && ce[1] == '/') {
252 while(p < ce)
253 p = DoComment(hls, p, ce);
254 hls.Put(2, hl_style[INK_COMMENT]);
255 p += 2;
256 comment = false;
257 goto comment_ended;
258 }
259 while(p < e)
260 p = DoComment(hls, p, e);
261 comment = is_comment = true;
262 break;
263 comment_ended:;
264 }
265 else
266 if(raw_string.GetCount() || RawString(p, raw_n)) {
267 hls.Put(raw_n, hl_style[INK_CONST_STRING]);
268 p += raw_n;
269 const wchar *b = p;
270 while(p < e) {
271 const wchar *s = p;
272 const wchar *r = raw_string;
273 while(*s && *r) {
274 if(*s != *r)
275 break;
276 s++;
277 r++;
278 }
279 if(*r == '\0') {
280 hls.Put(int(p - b), hl_style[INK_RAW_STRING]);
281 hls.Put(int(s - p), hl_style[INK_CONST_STRING]);
282 b = p = s;
283 raw_string.Clear();
284 break;
285 }
286 p++;
287 }
288 if(p != b)
289 hls.Put(int(p - b), hl_style[INK_RAW_STRING]);
290 }
291 else
292 if(linecomment && linecont || pair == MAKELONG('/', '/') &&
293 highlight != HIGHLIGHT_CSS && highlight != HIGHLIGHT_JSON ||
294 highlight == HIGHLIGHT_PHP && *p == '#') {
295 while(p < e)
296 p = DoComment(hls, p, e);
297 is_comment = true;
298 break;
299 }
300 else
301 if((*p == '\"' || *p == '\'') || linecont && string)
302 p = hls.CString(p);
303 else
304 if(*p == '(') {
305 brk.Add(')');
306 Bracket(int(p - ltext) + pos, hls, editor);
307 hls.Put(hl_style[INK_PAR0 + max(pl++, 0) % 4]);
308 p++;
309 }
310 else
311 if(*p == '{') {
312 brk.Add(was_namespace ? 0 : '}');
313 Bracket(int(p - ltext) + pos, hls, editor);
314 hls.Put(hl_style[INK_PAR0 + max(cl, 0) % 4]);
315 if(was_namespace)
316 was_namespace = false;
317 else {
318 ++block_level;
319 ++cl;
320 }
321 if(hls.pos < linelen)
322 hls.SetPaper(hls.pos, linelen - hls.pos + 1, BlockColor(block_level));
323 p++;
324 }
325 else
326 if(*p == '[') {
327 brk.Add(']');
328 Bracket(int(p - ltext) + pos, hls, editor);
329 hls.Put(hl_style[INK_PAR0 + max(bl++, 0) % 4]);
330 p++;
331 }
332 else
333 if(*p == ')' || *p == '}' || *p == ']') {
334 int bc = brk.GetCount() ? brk.Pop() : 0;
335 if(*p == '}' && hilite_scope && block_level > 0 && bc)
336 hls.SetPaper(hls.pos, linelen + 1 - hls.pos, BlockColor(--block_level));
337 Bracket(int(p - ltext) + pos, hls, editor);
338 int& l = *p == ')' ? pl : *p == '}' ? cl : bl;
339 if(bc && (bc != *p || l <= 0) || bc == 0 && *p != '}') {
340 hls.Put(p == ltext || ignore_errors ? hl_style[INK_PAR0] : hl_style[INK_ERROR]);
341 brk.Clear();
342 cl = bl = pl = 0;
343 }
344 else {
345 if(bc) --l;
346 hls.Put(1, hl_style[INK_PAR0 + l % 4]);
347 }
348 p++;
349 }
350 else
351 if(highlight == HIGHLIGHT_CSS ? *p == '#' : findarg(pair, MAKELONG('0', 'x'), MAKELONG('0', 'X'), MAKELONG('0', 'b'), MAKELONG('0', 'B')) >= 0)
352 p = HighlightHexBin(hls, p, 1 + (highlight != HIGHLIGHT_CSS), thousands_separator);
353 else
354 if(IsDigit(*p))
355 p = HighlightNumber(hls, p, thousands_separator, *p == '0', highlight == HIGHLIGHT_CSS);
356 else
357 if(pair == MAKELONG('t', '_') && p[2] == '(' && p[3] == '\"') {
358 int pos0 = hls.pos;
359 hls.Put(3, hl_style[INK_UPP]);
360 p = hls.CString(p + 3);
361 if(*p == ')') {
362 hls.Put(hl_style[INK_UPP]);
363 p++;
364 }
365 hls.SetPaper(pos0, hls.pos - pos0, hl_style[PAPER_LNG].color);
366 }
367 else
368 if(pair == MAKELONG('t', 't') && p[3] == '(' && p[4] == '\"') {
369 int pos0 = hls.pos;
370 hls.Put(4, hl_style[INK_UPP]);
371 p = hls.CString(p + 4);
372 if(*p == ')') {
373 hls.Put(hl_style[INK_UPP]);
374 p++;
375 }
376 hls.SetPaper(pos0, hls.pos - pos0, hl_style[PAPER_LNG].color);
377 }
378 else
379 if(iscib(*p)) {
380 const wchar *q = p;
381 StringBuffer id;
382 while((iscidl(*q) || highlight == HIGHLIGHT_CSS && *q == '-') && q < e)
383 id.Cat(*q++);
384 String iid = id;
385 if(highlight == HIGHLIGHT_SQL)
386 iid = ToUpper(iid);
387 int uq = kw_upp.Find(iid);
388 int nq = -1;
389 hls.Put(int(q - p), !include && (nq = keyword[highlight].Find(iid)) >= 0 ? hl_style[INK_KEYWORD] :
390 name[highlight].Find(iid) >= 0 ? hl_style[INK_UPP] :
391 uq >= 0 ? uq < kw_macros ? hl_style[INK_UPPMACROS] :
392 uq < kw_logs ? hl_style[INK_UPPLOGS] :
393 uq < kw_sql_base ? hl_style[INK_SQLBASE] :
394 uq < kw_sql_func ? hl_style[INK_SQLFUNC] :
395 hl_style[INK_SQLBOOL] :
396 IsUpperString(iid) && !macro ? hl_style[INK_UPPER] :
397 hl_style[INK_NORMAL]);
398 p = q;
399 if(nq == 0)
400 was_namespace = true;
401 }
402 else {
403 if(*p == ';')
404 was_namespace = false;
405 hls.Put(strchr("!+-*^/%~&|=[]:?<>.", *p) ? hl_style[INK_OPERATOR] : hl_style[INK_NORMAL]);
406 p++;
407 }
408 }
409 if(hilite_ifdef && !IsNull(cppid) && !is_comment) {
410 if((cppid == "else" || cppid == "elif" || cppid == "endif") && !ifstack.IsEmpty()) {
411 WStringBuffer ifln;
412 ifln.Cat(" // ");
413 ifln.Cat(ifstack.Top().iftext);
414 if(ifstack.Top().ifline && hilite_ifdef == 2) {
415 ifln.Cat(", line ");
416 ifln.Cat(FormatInt(ifstack.Top().ifline));
417 }
418 ifln.Cat('\t');
419 int start = linelen;
420 WString ifs(ifln);
421 hls.Set(start, ifs.GetLength(), hl_style[INK_IFDEF]);
422 for(int i = 0; i < ifs.GetCount(); i++)
423 hls.SetChar(start + i, ifs[i]);
424 }
425 }
426 if(hilite_scope) {
427 if(lbrace >= 0 && lbclose < 0 && lbrace > lindent)
428 hls.SetPaper(lindent, lbrace - lindent, lbcolor);
429 if(lbrace < 0 && lbclose >= 0)
430 hls.SetPaper(lbclose, linelen + 1 - lbclose, lbcolor);
431 }
432 if(findarg(cppid, "else", "elif", "endif", "if", "ifdef", "ifndef") >= 0)
433 hls.SetPaper(0, hls.v.GetCount(), hl_style[PAPER_IFDEF].color);
434 }
435
436 }
437