1 /*
2 Copyright (C) 2008, 2009 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23 #include "highlighter.h"
24
25 #include <QDebug>
26
TextBlockData()27 TextBlockData::TextBlockData()
28 {
29 // Nothing to do
30 }
31
parentheses()32 QVector<ParenthesisInfo *> TextBlockData::parentheses()
33 {
34 return m_parentheses;
35 }
36
37
insert(ParenthesisInfo * info)38 void TextBlockData::insert(ParenthesisInfo *info)
39 {
40 int i = 0;
41 while (i < m_parentheses.size() &&
42 info->position > m_parentheses.at(i)->position)
43 ++i;
44
45 m_parentheses.insert(i, info);
46 }
47
saturateColor(QColor color,int percent)48 QColor saturateColor(QColor color, int percent) {
49 int sat = color.saturation();
50 sat = sat * percent / 100;
51 if(sat > 255)
52 sat = 255;
53 return QColor::fromHsl(color.hue(), sat, color.lightness());
54 }
55
setTheme(const QString & theme)56 void Highlighter::setTheme(const QString &theme) {
57 if(theme == "none") {
58 defaultFormat.setForeground(QColor("black"));
59 defaultFormat.setBackground(QColor(250, 250, 250));
60 /*
61 csdtagFormat = defaultFormat;
62 instFormat = defaultFormat;
63 keywordFormat = defaultFormat;
64 headerFormat = defaultFormat;
65 opcodeFormat = defaultFormat;
66 singleLineCommentFormat = defaultFormat;
67 */
68
69
70 }
71 else if(theme == "classic") {
72 defaultFormat.setForeground(QColor("black"));
73 defaultFormat.setBackground(QColor(250, 250, 250));
74
75 csdtagFormat.setForeground(QColor("brown"));
76 csdtagFormat.setFontWeight(QFont::Bold);
77
78 instFormat.setForeground(QColor("purple"));
79 instFormat.setFontWeight(QFont::Bold);
80
81 keywordFormat.setForeground(QColor("#E65100"));
82 keywordFormat.setFontWeight(QFont::Bold);
83
84 headerFormat.setForeground(QColor("brown"));
85 headerFormat.setFontWeight(QFont::Bold);
86
87 opcodeFormat.setForeground(QColor("blue"));
88 opcodeFormat.setFontWeight(QFont::Bold);
89 deprecatedFormat = opcodeFormat;
90
91 singleLineCommentFormat.setForeground(QColor("green"));
92 singleLineCommentFormat.setFontItalic(true);
93
94 macroDefineFormat.setForeground(QColor("green"));
95 macroDefineFormat.setFontWeight(QFont::Bold);
96
97 pfieldFormat.setFontWeight(QFont::Bold);
98
99 irateFormat.setForeground(QColor("darkCyan"));
100 krateFormat.setForeground(QColor("darkCyan"));
101
102 arateFormat.setForeground(QColor("darkCyan"));
103 arateFormat.setFontWeight(QFont::Bold);
104
105 stringVarFormat.setForeground(QColor(Qt::darkYellow));
106 stringVarFormat.setFontWeight(QFont::Bold);
107
108 fsigFormat.setForeground(QColor(Qt::gray));
109 fsigFormat.setFontWeight(QFont::Bold);
110
111 labelFormat.setForeground(QColor(205,92,92));
112 labelFormat.setFontWeight(QFont::Bold);
113
114 nameFormat.setForeground(QColor("#880E4F"));
115 nameFormat.setFontWeight(QFont::Bold);
116 // nameFormat.setFontUnderline(true);
117
118 quotationFormat.setForeground(Qt::red);
119 multiLineCommentFormat.setForeground(QColor("green"));
120
121 ioFormat = opcodeFormat;
122 udoFormat = opcodeFormat;
123 operatorFormat = defaultFormat;
124 importantCommentFormat = singleLineCommentFormat;
125 }
126 else if(theme == "light") {
127 defaultFormat.setForeground(QColor("#030303"));
128 defaultFormat.setBackground(QColor("#F9F9F9"));
129
130 // csdtagFormat.setFontWeight(QFont::Bold);
131
132 instFormat.setForeground(QColor("#82387B"));
133 instFormat.setFontWeight(QFont::Bold);
134
135 keywordFormat.setForeground(QColor("#D64100"));
136 keywordFormat.setFontWeight(QFont::Bold);
137
138 // headerFormat.setForeground(QColor("#C62828"));
139 // headerFormat.setFontWeight(QFont::Bold);
140 headerFormat = keywordFormat;
141
142 opcodeFormat.setForeground(QColor("#303F9F"));
143 opcodeFormat.setFontWeight(QFont::Bold);
144
145 deprecatedFormat.setForeground(QColor("#880000"));
146 deprecatedFormat.setFontUnderline(true);
147
148 singleLineCommentFormat.setForeground(QColor("#8F8F7F"));
149 singleLineCommentFormat.setFontItalic(true);
150
151
152 importantCommentFormat.setBackground(QColor("#FFFFA0"));
153 importantCommentFormat.setForeground(
154 singleLineCommentFormat.foreground().color().darker(150));
155 // importantCommentFormat.setFontItalic(true);
156
157 macroDefineFormat.setForeground(QColor("#00695C"));
158 macroDefineFormat.setFontWeight(QFont::Bold);
159
160 pfieldFormat.setFontWeight(QFont::Bold);
161
162
163 krateFormat.setForeground(QColor("#10796C"));
164 irateFormat.setForeground(QColor("#303F9F"));
165
166 // arateFormat.setForeground(QColor("#C62828"));
167 arateFormat.setForeground(QColor("#B71C1C"));
168 arateFormat.setFontWeight(QFont::Bold);
169
170 stringVarFormat.setForeground(QColor(Qt::darkYellow));
171 stringVarFormat.setFontWeight(QFont::Normal);
172
173 fsigFormat.setForeground(QColor("#Ad1457"));
174 fsigFormat.setFontWeight(QFont::Bold);
175
176 labelFormat.setForeground(QColor(205,92,92));
177 labelFormat.setFontWeight(QFont::Bold);
178 labelFormat.setFontUnderline(true);
179
180 nameFormat.setForeground(QColor("#F50057"));
181 nameFormat.setFontWeight(QFont::Bold);
182 // nameFormat.setFontUnderline(true);
183
184 // quotationFormat.setForeground(QColor("#4CAf50"));
185 quotationFormat.setForeground(QColor("#827717"));
186 multiLineCommentFormat.setForeground(quotationFormat.foreground());
187
188 ioFormat.setForeground(QColor("#8844BB"));
189 ioFormat.setFontWeight(QFont::Bold);
190 // ioFormat.setFontItalic(true);
191
192 udoFormat = opcodeFormat;
193 udoFormat.setForeground(opcodeFormat.foreground().color().darker(150));
194
195 csdtagFormat.setForeground(instFormat.foreground());
196
197 operatorFormat.setForeground(instFormat.foreground().color());
198
199 }
200 else if(theme == "dark") {
201 defaultFormat.setForeground(QColor("#FBFBFB"));
202 defaultFormat.setBackground(QColor("#161616"));
203
204
205 // csdtagFormat.setFontWeight(QFont::Bold);
206
207 instFormat.setForeground(QColor("#B268AB"));
208 instFormat.setFontWeight(QFont::Bold);
209
210 keywordFormat.setForeground(QColor("#FF9800"));
211 keywordFormat.setFontWeight(QFont::Bold);
212
213 // headerFormat.setForeground(QColor("#FFD54F"));
214 // headerFormat.setFontWeight(QFont::Bold);
215 headerFormat = keywordFormat;
216
217 opcodeFormat.setForeground(QColor("#4FC3F7"));
218 opcodeFormat.setFontWeight(QFont::Bold);
219
220 deprecatedFormat.setForeground(saturateColor(opcodeFormat.foreground().color(), 50));
221 deprecatedFormat.setUnderlineColor("#880000");
222 deprecatedFormat.setFontUnderline(true);
223
224
225 // singleLineCommentFormat.setForeground(QColor("#9F9F8F"));
226 singleLineCommentFormat.setForeground(QColor("#755CB0"));
227 singleLineCommentFormat.setFontItalic(true);
228
229 importantCommentFormat.setBackground(defaultFormat.background().color().lighter(140));
230 importantCommentFormat.setForeground(
231 singleLineCommentFormat.foreground().color().lighter(175));
232
233 macroDefineFormat.setForeground(QColor("#F06292"));
234 macroDefineFormat.setFontWeight(QFont::Bold);
235
236 pfieldFormat.setFontWeight(QFont::Bold);
237
238 // krateFormat.setForeground(QColor("#EF9A9A"));
239 krateFormat.setForeground(QColor("#66EEBB"));
240 irateFormat.setForeground(QColor("#FFFFFF"));
241
242 // arateFormat.setForeground(QColor("#C62828"));
243 arateFormat.setForeground(QColor("#F75C5C"));
244 arateFormat.setFontWeight(QFont::Bold);
245
246
247 fsigFormat.setForeground(QColor("#Ad1457"));
248 fsigFormat.setFontWeight(QFont::Bold);
249
250 labelFormat.setForeground(instFormat.foreground());
251 labelFormat.setFontWeight(QFont::Bold);
252 labelFormat.setFontUnderline(true);
253
254 nameFormat.setForeground(QColor("#D298FB"));
255 nameFormat.setFontWeight(QFont::Bold);
256 // nameFormat.setFontUnderline(true);
257
258 // quotationFormat.setForeground(QColor("#66FFAA"));
259 quotationFormat.setForeground(QColor("#91FF55"));
260 stringVarFormat.setForeground(quotationFormat.foreground());
261 stringVarFormat.setFontWeight(QFont::Normal);
262
263 multiLineCommentFormat.setForeground(quotationFormat.foreground());
264
265 ioFormat.setForeground(QColor("#FFD54F"));
266 ioFormat.setFontWeight(QFont::Bold);
267
268 // udoFormat.setForeground(QColor("#60BBB4"));
269 // udoFormat.setFontWeight(opcodeFormat.fontWeight());
270 udoFormat.setForeground(opcodeFormat.foreground());
271 udoFormat.setFontWeight(QFont::Normal);
272
273 // ioFormat.setFontItalic(true);
274 csdtagFormat.setForeground(instFormat.foreground());
275 operatorFormat.setForeground(nameFormat.foreground().color());
276
277 }
278 else {
279 qDebug() << "Theme" << theme << "not defined, using default";
280 this->setTheme("classic");
281 return;
282 }
283 // --------------------------------------
284 girateFormat.setForeground(irateFormat.foreground());
285 // girateFormat.setFontWeight(QFont::Bold);
286 girateFormat.setFontItalic(true);
287
288 gkrateFormat.setForeground(krateFormat.foreground());
289 // gkrateFormat.setFontWeight(QFont::Bold);
290 gkrateFormat.setFontItalic(true);
291
292 garateFormat.setForeground(arateFormat.foreground());
293 garateFormat.setFontWeight(arateFormat.fontWeight());
294 garateFormat.setFontItalic(true);
295
296 gfsigFormat.setForeground(fsigFormat.foreground());
297 gfsigFormat.setFontWeight(fsigFormat.fontWeight());
298 gfsigFormat.setFontItalic(true);
299
300 gstringVarFormat.setForeground(stringVarFormat.foreground());
301 gstringVarFormat.setFontWeight(QFont::Bold);
302 gstringVarFormat.setFontItalic(true);
303
304 // ioFormat.setFontItalic(true);
305
306 QColor color = saturateColor(headerFormat.foreground().color().lighter(150), 150);
307 csoundOptionFormat.setForeground(color);
308 jsKeywordFormat = keywordFormat;
309
310 m_theme = theme;
311 emit this->rehighlight();
312 }
313
getFormat(QString tag)314 QTextCharFormat Highlighter::getFormat(QString tag) {
315 if(tag == "" || tag == "default") {
316 return defaultFormat;
317 }
318 if(tag == "csdtag")
319 return csdtagFormat;
320 if(tag == "inst")
321 return instFormat;
322 if(tag == "keyword")
323 return keywordFormat;
324 if(tag == "opcode")
325 return opcodeFormat;
326 if(tag == "singleLineComment")
327 return singleLineCommentFormat;
328 if(tag == "macroDefine")
329 return macroDefineFormat;
330 if(tag == "pfield")
331 return pfieldFormat;
332 QTextCharFormat fallback;
333 fallback.setForeground(QColor("black"));
334 fallback.setBackground(QColor(250, 250, 250));
335 return fallback;
336 }
337
Highlighter(QTextDocument * parent)338 Highlighter::Highlighter(QTextDocument *parent)
339 : QSyntaxHighlighter(parent)
340 {
341 commentStartExpression = QRegExp("/\\*");
342 commentEndExpression = QRegExp("\\*/");
343
344 // b64encStartExpression = QRegExp("<CsFileB .*>");
345 // b64encEndExpression = QRegExp("<CsFileB>");
346 colorVariables = true;
347 m_mode = 0; // default to Csound mode
348
349 tagPatterns << "<CsoundSynthesizer>" << "</CsoundSynthesizer>"
350 << "<CsInstruments>" << "</CsInstruments>"
351 << "<CsOptions>" << "</CsOptions>"
352 << "<CsScore>" << "</CsScore>"
353 << "<CsVersion>" << "</CsVersion>"
354 << "<MacOptions>" << "</MacOptions>"
355 << "<MacGUI>" << "</MacGUI>"
356 << "<csLADSPA>" << "</csLADSPA>"
357 << "<Cabbage>" << "</Cabbage>"
358 << "<CsHtml5>" << "</CsHtml5>"
359 << "<CsFileB>" << "</CsFileB>";
360
361 instPatterns << "instr" << "endin" << "opcode" << "endop";
362 headerPatterns << "sr" << "kr" << "ksmps" << "nchnls" << "nchnls_i" << "0dbfs" << "A4"
363 << "zakinit" << "massign";
364
365 keywordLiterals << "init" << "if" << "then" << "else" << "endif" << "elseif"
366 << "while" << "goto" << "igoto" << "kgoto"
367 << "do" << "od"
368 << "int" << "turnoff" << "xin" << "xout"
369 << "passign";
370
371 ioPatterns << "in" << "ins" << "inch" << "out" << "outs" << "outch"
372 << "outvalue" << "invalue" << "chnget" << "chnset" << "chn_k" << "chn_a"
373 << "zaw" << "zar" << "zkw" << "zkr" << "zawm"
374 << "OSCsend" << "OSClisten" << "OSCraw" << "OSCinit";
375
376 deprecatedOpcodes << "array" << "compress" << "dcblock" << "diskin" << "flooper"
377 << "in32" << "inh" << "ino" << "inq" << "inrq" << "inx"
378 << "loop_ge" << "loop_gt" << "loop_le" << "loop_lt"
379 << "nlfilt" << "outc" << "outo" << "outq" << "outx" << "vco"
380 << "vincr" << "vbap16" << "vbap4" << "vbap8"
381 << "vbap4move" << "vbap8move" << "balance"
382 << "chani" << "chano" << "cigoto" << "ckgoto"
383 << "cngoto" << "control" << "setctrl" << "flashtxt"
384 << "vaset" << "vaget"
385 << "button" << "checkbox";
386
387 operatorPatterns << "&&" << "||";
388
389 csoundOptions << "-+rtaudio=" << "-+rtmidi=" << "--nodisplays" << "--nosound"
390 << "--syntax-check-only" << "--control-rate=" << "--messagelevel="
391 << "--env:" << "--dither" << "--sched" << "--omacro:"
392 << "--smacro:" << "--verbose" << "--sample-accurate" << "--realtime"
393 << "--nchnls=" << "--nchnls_i=" << "--sinesize" << "--daemon"
394 << "--port=" << "--use-system-sr" << "--ksmps=" << "-+jack_client="
395 ;
396
397 csoundOptionsRx = QRegExp("--(env|nodisplays|nosound|control-rate|messagelevel=|"
398 "dither|sched|omacro:|smacro:|verbose|sample-accurate|"
399 "realtime|nchnls|nchnls_i|sinesize=|daemon|port=|"
400 "use-system-sr|ksmps|midi-key-cps=|midi-velocity=)");
401
402 csoundOptionsRx2 = QRegExp("-+(rtaudio=|rtmidi=|jack_client=)");
403
404 functionRegex = QRegExp("\\b\\w+(\\:a|\\:k|\\:i)?(?=\\()");
405
406 // For Python
407 pythonKeywords << "and" << "or" << "not" << "is"
408 << "global" << "with" << "from" << "import" << "as"
409 << "if" << "else" << "elif"
410 << "print" << "class" << "del" << "exec"
411 << "for" << "in" << "while" << "continue" << "pass" << "break"
412 << "def" << "return" << "lambda"
413 << "yield" << "assert" << "try" << "except" << "finally" << "raise"
414 << "True" << "False" << "None";
415
416 // for html
417 htmlKeywords << "<\\ba\\b" << "<\\babbr\\b" << "<\\bacronym\\b" << "<\\baddress\\b"
418 << "<\\bapplet\\b" << "<\\barea\\b" << "<\\barticle\\b" << "<\\baside\\b"
419 << "<\\baudio\\b" << "<\\bb\\b" << "<\\bbase\\b" << "<\\bbasefont\\b"
420 << "<\\bbdi\\b" << "<\\bbdo\\b" << "<\\bbgsound\\b" << "<\\bblockquote\\b"
421 << "<\\bbig\\b" << "<\\bbody\\b" << "<\\bblink\\b" << "<\\bbr\\b"
422 << "<\\bbutton\\b" << "<\\bcanvas\\b" << "<\\bcaption\\b" << "<\\bcenter\\b"
423 << "<\\bcite\\b" << "<\\bcode\\b" << "<\\bcol\\b" << "<\\bcolgroup\\b"
424 << "<\\bcomment\\b" << "<\\bdata\\b" << "<\\bdatalist\\b" << "<\\bdd\\b"
425 << "<\\bdel\\b" << "<\\bdetails\\b" << "<\\bdfn\\b" << "<\\bdialog\\b"
426 << "<\\bdir\\b" << "<\\bdiv\\b" << "<\\bdl\\b" << "<\\bdt\\b"
427 << "<\\bem\\b" << "<\\bembed\\b"
428 << "<\\bfieldset\\b" << "<\\bfigcaption\\b" << "<\\bfigure\\b"
429 << "<\\bfont\\b" << "<\\bfooter\\b" << "<\\bform\\b" << "<\\bframe\\b"
430 << "<\\bframeset\\b" << "<\\bh1\\b" << "<\\bh2\\b" << "<\\bh3\\b" << "<\\bh4\\b"
431 << "<\\bh5\\b" << "<\\bh6\\b" << "<\\bhead\\b" << "<\\bheader\\b" << "<\\bhgroup\\b"
432 << "<\\bhr\\b" << "<\\bhtml\\b" << "<\\bi\\b" << "<\\biframe\\b" << "<\\bimg\\b"
433 << "<\\binput\\b" << "<\\bins\\b" << "<\\bisindex\\b" << "<\\bkbd\\b"
434 << "<\\bkeygen\\b" << "<\\blabel\\b" << "<\\blegend\\b" << "<\\bli\\b"
435 << "<\\blink\\b" << "<\\blisting\\b" << "<\\bmain\\b" << "<\\bmap\\b"
436 << "<\\bmarquee\\b" << "<\\bmark\\b" << "<\\bmenu\\b"
437 << "<\\bamenuitem\\b" << "<\\bmeta\\b" << "<\\bmeter\\b" << "<\\bmulticol\\b"
438 << "<\\bnav\\b" << "<\\bnobr\\b" << "<\\bnoembed\\b" << "<\\bnoindex\\b"
439 << "<\\bnoframes\\b" << "<\\bnoscript\\b" << "<\\bobject\\b" << "<\\bol\\b"
440 << "<\\boptgroup\\b" << "<\\boption\\b" << "<\\boutput\\b"
441 << "<\\bp\\b" << "<\\bparam\\b" << "<\\bpicture\\b" << "<\\bplaintext\\b"
442 << "<\\bpre\\b" << "<\\bprogress\\b" << "<\\bq\\b" << "<\\brp\\b"
443 << "<\\brt\\b" << "<\\brtc\\b" << "<\\bruby\\b" << "<\\bs\\b"
444 << "<\\bsamp\\b" << "<\\bscript\\b" << "<\\bsection\\b" << "<\\bselect\\b"
445 << "<\\bsmall\\b" << "<\\bsource\\b" << "<\\bspacer\\b" << "<\\bspan\\b"
446 << "<\\bstrike\\b" << "<\\bstrong\\b" << "<\\bstyle\\b" << "<\\bsub\\b"
447 << "<\\bsummary\\b" << "<\\bsup\\b" << "<\\btable\\b" << "<\\btbody\\b"
448 << "<\\btd\\b" << "<\\btemplate\\b" << "<\\btextarea\\b"
449 << "<\\btfoot\\b" << "<\\bth\\b" << "<\\bthead\\b" << "<\\btime\\b"
450 << "<\\btitle\\b" << "<\\btr\\b" << "<\\btrack\\b" << "<\\btt\\b"
451 << "<\\bu\\b" << "<\\bul\\b" << "<\\bvar\\b" << "<\\bwbr\\b" << "<\\bxmp\\b"
452 << "<!\\bDOCTYPE\\b";
453
454 javascriptKeywords << "function" << "var" << "if" << "===" << "console.log" << "console.warn";
455
456 // this->setTheme("classic");
457 }
458
459
~Highlighter()460 Highlighter::~Highlighter()
461 {
462 }
463
setOpcodeNameList(QStringList list)464 void Highlighter::setOpcodeNameList(QStringList list)
465 {
466 m_opcodeList = list;
467 // setFirstRules();
468 setLastRules();
469 }
470
setMode(int mode)471 void Highlighter::setMode(int mode)
472 {
473 m_mode = mode;
474 }
475
476
setColorVariables(bool color)477 void Highlighter::setColorVariables(bool color)
478 {
479 colorVariables = color;
480
481 highlightingRules.clear();
482 setLastRules();
483 }
484
highlightBlock(const QString & text)485 void Highlighter::highlightBlock(const QString &text)
486 {
487 switch (m_mode) {
488 case 0: // Csound mode
489 highlightCsoundBlock(text);
490 break;
491 case 1: // Python mode
492 highlightPythonBlock(text);
493 break;
494 case 2: // Xml mode
495 highlightXmlBlock(text);
496 break;
497 case 3: // Orc
498 highlightCsoundBlock(text);
499 break;
500 case 4: // Sco
501 highlightCsoundBlock(text);
502 break;
503 case 5: // Inc
504 highlightCsoundBlock(text); // maybe anything not python or xml should be higlighter as csound?
505 break;
506 case 6: // Html
507 highlightHtmlBlock(text);
508 break;
509 }
510 // for parenthesis
511 TextBlockData *data = new TextBlockData;
512
513 int leftPos = text.indexOf('(');
514 while (leftPos != -1) {
515 ParenthesisInfo *info = new ParenthesisInfo;
516 info->character = '(';
517 info->position = leftPos;
518
519 data->insert(info);
520 leftPos = text.indexOf('(', leftPos + 1);
521 }
522
523 int rightPos = text.indexOf(')');
524 while (rightPos != -1) {
525 ParenthesisInfo *info = new ParenthesisInfo;
526 info->character = ')';
527 info->position = rightPos;
528
529 data->insert(info);
530
531 rightPos = text.indexOf(')', rightPos +1);
532 }
533
534 setCurrentBlockUserData(data);
535 }
536
537
highlightCsoundBlock(const QString & text)538 void Highlighter::highlightCsoundBlock(const QString &text)
539 {
540 // TODO: rewrite this using QRegularExpression
541
542 // text is processed one line at a time
543 if(m_theme == "none")
544 return;
545
546 int commentIndex = text.indexOf(';'); // try both comment markings
547 if (commentIndex < 0) {
548 commentIndex = text.indexOf("//");
549 }
550
551 if (commentIndex >= 0) {
552 // if(QRegExp("^\\s*;;").indexIn(text) != -1) {
553 if (text.length() > commentIndex+1) {
554 if(text[commentIndex+1] == ';' && text.trimmed()[0] == ';') {
555 // ;; pattern, which is picked up by inspector
556 setFormat(commentIndex, text.size() - commentIndex, importantCommentFormat);
557 } else {
558 setFormat(commentIndex, text.size() - commentIndex, singleLineCommentFormat);
559 }
560 }
561 }
562 else {
563 commentIndex = text.size() + 1;
564 }
565
566 QRegExp regexp;
567 int index = 0;
568 int length;
569
570 // string
571 regexp = QRegExp("\"[^\"]*\"");
572
573 index = text.indexOf(regexp);
574 while (index >= 0 && index < commentIndex) {
575 length = regexp.matchedLength();
576 setFormat(index, length, quotationFormat);
577 index = text.indexOf(regexp, index + length);
578 }
579
580 // define
581 regexp = QRegExp("^\\s*#define\\s+[_\\w\\ \\t]*#.*#");
582 index = text.indexOf(regexp);
583 if(index >= 0 && index < commentIndex) {
584 int length = regexp.matchedLength();
585 setFormat(index, length, macroDefineFormat);
586 index = text.indexOf(regexp,index+length);
587 }
588
589 regexp = QRegExp("\\b(instr|opcode)\\s+(\\w+)\\b");
590 index = 0;
591 while ((index = regexp.indexIn(text, index)) != -1) {
592 auto group = regexp.cap(2);
593 length = regexp.matchedLength();
594 setFormat(regexp.pos(2), group.length(), nameFormat);
595 index += length;
596 }
597
598 index = 0;
599 while ((index = csoundOptionsRx.indexIn(text, index)) != -1 && index < commentIndex) {
600 length = csoundOptionsRx.matchedLength();
601 setFormat(index, length, csoundOptionFormat);
602 index += length;
603 }
604
605 index = 0;
606 while ((index = csoundOptionsRx2.indexIn(text, index)) != -1 && index < commentIndex) {
607 length = csoundOptionsRx2.matchedLength();
608 setFormat(index, length, csoundOptionFormat);
609 index += length;
610 }
611
612
613 regexp = QRegExp(R"(&&|==|\|\||<|>|<=|>=|!=|\\)");
614 index = 0;
615 while ((index = regexp.indexIn(text, index)) != -1 && index < commentIndex) {
616 length = regexp.matchedLength();
617 setFormat(index, length, operatorFormat);
618 index += length;
619 }
620
621
622 /*
623 index = 0;
624 while ((index = functionRegex.indexIn(text, index)) != -1 && index < commentIndex) {
625 length = functionRegex.matchedLength();
626 setFormat(index, length, opcodeFormat);
627 index += length;
628 }
629 */
630
631 QRegExp expression("\\b[\\w:]+\\b");
632 index = text.indexOf(expression, 0);
633 length = expression.matchedLength();
634
635 while (index >= 0 && index < commentIndex) {
636 int wordStart = index;
637 int wordEnd = wordStart + length;
638
639 if (index>0) {
640 auto prev = text.at(index - 1);
641 if (prev == '$' || prev == '#') {
642 // check if macro name - replacement for regexp solution which I could not find
643 wordStart--;
644 length++;
645 setFormat(wordStart, wordEnd - wordStart, macroDefineFormat);
646 index = text.indexOf(expression, wordEnd);
647 length = expression.matchedLength();
648 continue;
649 }
650 }
651 wordEnd = (wordEnd > 0 ? wordEnd : text.size());
652 QString word = text.mid(wordStart, length);
653 if (word.indexOf(QRegExp("p[\\d]+\\b")) != -1) {
654 setFormat(wordStart, wordEnd - wordStart, pfieldFormat);
655 }
656 if (instPatterns.contains(word)) {
657 setFormat(wordStart, wordEnd - wordStart, instFormat);
658 break; // was: return. FOr any case, to go through lines after while loop
659 }
660 else if (tagPatterns.contains("<" + word + ">") && wordStart > 0) {
661 setFormat(wordStart - (text[wordStart - 1] == '/'? 2: 1),
662 wordEnd - wordStart + (text[wordStart - 1] == '/'? 3: 2),
663 csdtagFormat);
664 }
665 else if (headerPatterns.contains(word)) {
666 setFormat(wordStart, wordEnd - wordStart, headerFormat);
667 }
668 else if (keywordLiterals.contains(word)) {
669 setFormat(wordStart, wordEnd - wordStart, keywordFormat);
670 }
671 else if (ioPatterns.contains(word)) {
672 setFormat(wordStart, wordEnd - wordStart, ioFormat);
673 }
674
675 else if (word.contains(":")) {
676 QStringList parts = word.split(":");
677 if (parts.size() == 2) {
678 if (findOpcode(parts[0]) >= 0) {
679 setFormat(wordStart, wordEnd - wordStart, opcodeFormat);
680 }
681 }
682 }
683 else if (m_parsedUDOs.contains(word)) {
684 setFormat(wordStart, wordEnd - wordStart, udoFormat);
685 }
686 else if (deprecatedOpcodes.contains(word)) {
687 setFormat(wordStart, wordEnd - wordStart, deprecatedFormat);
688 }
689 else if (findOpcode(word) >= 0) {
690 setFormat(wordStart, wordEnd - wordStart, opcodeFormat);
691 }
692 else if (word.startsWith('a') && colorVariables) {
693 setFormat(wordStart, wordEnd - wordStart, arateFormat);
694 }
695 else if (word.startsWith('k') && colorVariables) {
696 setFormat(wordStart, wordEnd - wordStart, krateFormat);
697 }
698 else if (word.startsWith('i') && colorVariables) {
699 setFormat(wordStart, wordEnd - wordStart, irateFormat);
700 }
701 else if (word.startsWith("ga") && colorVariables) {
702 setFormat(wordStart, wordEnd - wordStart, garateFormat);
703 }
704 else if (word.startsWith("gk") && colorVariables) {
705 setFormat(wordStart, wordEnd - wordStart, gkrateFormat);
706 }
707 else if (word.startsWith("gi") && colorVariables) {
708 setFormat(wordStart, wordEnd - wordStart, girateFormat);
709 }
710 else if (word.startsWith("S") && colorVariables) {
711 setFormat(wordStart, wordEnd - wordStart, stringVarFormat);
712 }
713 else if (word.startsWith("gS") && colorVariables) {
714 setFormat(wordStart, wordEnd - wordStart, gstringVarFormat);
715 }
716 else if (word.startsWith("f") && colorVariables) {
717 setFormat(wordStart, wordEnd - wordStart, fsigFormat);
718 }
719 else if (word.startsWith("gf") && colorVariables) {
720 setFormat(wordStart, wordEnd - wordStart, gfsigFormat);
721 }
722 index = text.indexOf(expression, wordEnd);
723 length = expression.matchedLength();
724 }
725 //last rules
726 for (int i = 0; i < lastHighlightingRules.size(); i++) {
727 QRegExp expression(lastHighlightingRules[i].pattern);
728 int index = 0, length;
729 while((index = expression.indexIn(text, index)) != -1 && index < commentIndex) {
730 int group = lastHighlightingRules[i].group;
731 if(group == 0) {
732 length = expression.matchedLength();
733 setFormat(index, length, lastHighlightingRules[i].format);
734 } else {
735 auto capture = expression.cap(group);
736 length = expression.matchedLength();
737 setFormat(expression.pos(group), capture.length(), lastHighlightingRules[i].format);
738 }
739 index += length;
740 }
741 }
742
743 setCurrentBlockState(0);
744
745 int startIndex = 0;
746 if (previousBlockState() != 1) {
747 startIndex = text.indexOf(commentStartExpression);
748 }
749
750 // while (startIndex >= 0 && startIndex < commentIndex) {
751 while (startIndex >= 0) {
752 int endIndex = text.indexOf(commentEndExpression, startIndex);
753 if (format(startIndex) == quotationFormat) {
754 startIndex = text.indexOf(commentStartExpression,
755 startIndex + 1);
756 continue;
757 }
758 int commentLength;
759 if (endIndex == -1) {
760 setCurrentBlockState(1);
761 commentLength = text.length() - startIndex;
762 } else {
763 commentLength = endIndex - startIndex
764 + commentEndExpression.matchedLength();
765 }
766 setFormat(startIndex, commentLength, multiLineCommentFormat);
767 startIndex = text.indexOf(commentStartExpression,
768 startIndex + commentLength);
769 }
770 }
771
772
highlightPythonBlock(const QString & text)773 void Highlighter::highlightPythonBlock(const QString &text)
774 {
775 QRegExp expression("\\b+\\w\\b+");
776 int index = text.indexOf(expression, 0);
777 for (int i = 0; i < pythonKeywords.size(); i++) {
778 QRegExp expression("\\b+" + pythonKeywords[i] + "\\b+");
779 int index = text.indexOf(expression);
780 while (index >= 0) {
781 int length = expression.matchedLength();
782 setFormat(index, length, keywordFormat);
783 index = text.indexOf(expression, index + length);
784 }
785 }
786 QRegExp strings( QRegExp("\"[^\"]*\""));
787 index = text.indexOf(strings);
788 while (index >= 0) {
789 int length = strings.matchedLength();
790 setFormat(index, length, quotationFormat);
791 index = text.indexOf(strings, index + length);
792 }
793 strings = QRegExp("'[^'']*'");
794 index = text.indexOf(strings);
795 while (index >= 0) {
796 int length = strings.matchedLength();
797 setFormat(index, length, quotationFormat);
798 index = text.indexOf(strings, index + length);
799 }
800 QRegExp expComment("#.*");
801 index = text.indexOf(expComment);
802 while (index >= 0) {
803 int length = expComment.matchedLength();
804 setFormat(index, length, singleLineCommentFormat);
805 index = text.indexOf(expComment, index + length);
806 }
807 }
808
highlightXmlBlock(const QString &)809 void Highlighter::highlightXmlBlock(const QString &/*text*/)
810 {
811 }
812
813 // for html
814
highlightHtmlBlock(const QString & text)815 void Highlighter::highlightHtmlBlock(const QString &text)
816 {
817 QRegExp expression("\\b+\\w\\b+");
818 int index = text.indexOf(expression, 0);
819 for (int i = 0; i < htmlKeywords.size(); i++) {
820 QRegExp expression(htmlKeywords[i]);//expression("\\b+" + htmlKeywords[i] + "\\b+");
821 int index = text.indexOf(expression);
822 while (index >= 0) {
823 int length = expression.matchedLength();
824 setFormat(index, length, keywordFormat);
825 index = text.indexOf(expression, index + length);
826 }
827 }
828
829 for (int i=0; i<javascriptKeywords.size(); i++) {
830 QRegExp expression("\\b+" + javascriptKeywords[i] + "\\b+");
831 int index = text.indexOf(expression);
832 while (index >= 0) {
833 int length = expression.matchedLength();
834 setFormat(index, length, jsKeywordFormat); // TODO javascriptformat
835 index = text.indexOf(expression, index + length);
836 }
837 }
838
839 QRegExp endTag( QRegExp(">$"));
840 index = text.indexOf(endTag);
841 while (index >= 0) {
842 int length = endTag.matchedLength();
843 setFormat(index, length, keywordFormat);
844 index = text.indexOf(endTag, index + length);
845 }
846
847 QRegExp strings( QRegExp("\"[^\"]*\""));
848 index = text.indexOf(strings);
849 while (index >= 0) {
850 int length = strings.matchedLength();
851 setFormat(index, length, quotationFormat);
852 index = text.indexOf(strings, index + length);
853 }
854 strings = QRegExp("'[^'']*'");
855 index = text.indexOf(strings);
856 while (index >= 0) {
857 int length = strings.matchedLength();
858 setFormat(index, length, quotationFormat);
859 index = text.indexOf(strings, index + length);
860 }
861 int commentIndex = -1;
862 QRegExp expComment("//.*"); // TODO: avaoid https://
863 index = text.indexOf(expComment);
864 if (index>0 ) {
865 if (text.at(index-1)!=':') { // clumsy way to avoid addresses like https://
866 while (index >= 0) { // did not manage to do it with regular expression
867 int length = expComment.matchedLength();
868 setFormat(index, length, singleLineCommentFormat);
869 index = text.indexOf(expComment, index + length);
870 }
871 commentIndex = index; // better do other way
872 }
873 }
874
875 // if (commentIndex >= 0) {
876 // setFormat(commentIndex, text.size() - commentIndex, singleLineCommentFormat);
877 //// return;
878 // }
879 if (commentIndex < 0) {
880 commentIndex = text.size() + 1;
881 }
882
883 // multiline
884 setCurrentBlockState(0);
885 QRegExp htmlCommentStartExpression = QRegExp("<!--");
886 QRegExp htmlCommentEndExpression = QRegExp("-->");
887
888
889 int startIndex = 0;
890 if (previousBlockState() != 1) {
891 startIndex = text.indexOf(htmlCommentStartExpression);
892 }
893
894 while (startIndex >= 0 && startIndex < commentIndex) {
895 int endIndex = text.indexOf(htmlCommentEndExpression, startIndex);
896 if (format(startIndex) == quotationFormat) {
897 startIndex = text.indexOf(htmlCommentStartExpression,
898 startIndex + 1);
899 continue;
900 }
901 int commentLength;
902 if (endIndex == -1) {
903 setCurrentBlockState(1);
904 commentLength = text.length() - startIndex;
905 } else {
906 commentLength = endIndex - startIndex
907 + htmlCommentEndExpression.matchedLength();
908 }
909 setFormat(startIndex, commentLength, multiLineCommentFormat);
910 startIndex = text.indexOf(htmlCommentStartExpression,
911 startIndex + commentLength);
912 }
913 }
914
915 // void Highlighter::setFirstRules()
916 // {
917 // highlightingRules.clear();
918 // }
919
setLastRules()920 void Highlighter::setLastRules()
921 {
922 HighlightingRule rule;
923
924 rule = {QRegExp("^\\s*([a-zA-Z]\\w*):\\s*"), labelFormat, 1};
925 lastHighlightingRules.append(rule);
926
927 // strings
928 rule = {QRegExp("\"[^\"]*\""), quotationFormat, 0};
929 lastHighlightingRules.append(rule);
930
931 // multi line strings
932 rule = {QRegExp("\\{\\{.*"), quotationFormat, 0};
933 lastHighlightingRules.append(rule);
934
935 // end multi line strings
936 rule = {QRegExp(".*\\}\\}"), quotationFormat, 0};
937 lastHighlightingRules.append(rule);
938 }
939
findOpcode(QString opcodeName,int start,int end)940 int Highlighter::findOpcode(QString opcodeName, int start, int end)
941 {
942 // fprintf(stderr, "%i - %i\n", start, end);
943 Q_ASSERT(m_opcodeList.size() > 0);
944 if (end == -1) {
945 end = m_opcodeList.size() -1;
946 }
947 int pos = ((end - start)/2) + start;
948 if (opcodeName == m_opcodeList[pos])
949 return pos;
950 else if (start == end)
951 return -1;
952 else if (opcodeName < m_opcodeList[pos])
953 return findOpcode(opcodeName, start, pos);
954 else if (opcodeName > m_opcodeList[pos])
955 return findOpcode(opcodeName, pos + 1, end);
956 return -1;
957 }
958
setUDOs(QStringList udos)959 void Highlighter::setUDOs(QStringList udos)
960 {
961 m_parsedUDOs = udos;
962 }
963