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