Remove Help button from the program arguments dialog.
[kdbg.git] / kdbg / sourcewnd.cpp
blob85fdd2a2c847034a6c00cbbf26abc2edcf9ef805
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include "debugger.h"
8 #include "sourcewnd.h"
9 #include <qtextstream.h>
10 #include <qpainter.h>
11 #include <qbrush.h>
12 #include <qfile.h>
13 #include <qfileinfo.h>
14 #include <qkeycode.h>
15 #include <qpopupmenu.h>
16 #include <kapplication.h>
17 #include <kiconloader.h>
18 #include <kglobalsettings.h>
19 #include <kmainwindow.h>
20 #include <algorithm>
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "mydebug.h"
27 SourceWindow::SourceWindow(const QString& fileName, QWidget* parent, const char* name) :
28 QTextEdit(parent, name),
29 m_fileName(fileName),
30 m_curRow(-1),
31 m_widthItems(16),
32 m_widthPlus(12),
33 m_widthLineNo(30)
35 // load pixmaps
36 m_pcinner = UserIcon("pcinner");
37 m_pcup = UserIcon("pcup");
38 m_brkena = UserIcon("brkena");
39 m_brkdis = UserIcon("brkdis");
40 m_brktmp = UserIcon("brktmp");
41 m_brkcond = UserIcon("brkcond");
42 m_brkorph = UserIcon("brkorph");
43 setFont(KGlobalSettings::fixedFont());
44 setReadOnly(true);
45 setMargins(m_widthItems+m_widthPlus+m_widthLineNo, 0, 0 ,0);
46 setAutoFormatting(AutoNone);
47 setTextFormat(Qt::PlainText);
48 setWordWrap(NoWrap);
49 connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
50 this, SLOT(update()));
51 connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(cursorChanged(int)));
52 viewport()->installEventFilter(this);
54 // add a syntax highlighter
55 if (QRegExp("\\.(c(pp|c|\\+\\+)?|CC?|h(\\+\\+|h)?|HH?)$").search(m_fileName))
57 new HighlightCpp(this);
61 SourceWindow::~SourceWindow()
63 delete syntaxHighlighter();
66 bool SourceWindow::loadFile()
68 // first we load the code into QTextEdit
69 QFile f(m_fileName);
70 if (!f.open(IO_ReadOnly)) {
71 return false;
74 QTextStream t(&f);
75 setText(t.read());
76 f.close();
78 // then we copy it into our own m_sourceCode
79 int n = paragraphs();
80 m_sourceCode.resize(n);
81 m_rowToLine.resize(n);
82 for (int i = 0; i < n; i++) {
83 m_sourceCode[i].code = text(i);
84 m_rowToLine[i] = i;
86 m_lineItems.resize(n, 0);
88 // set a font for line numbers
89 m_lineNoFont = currentFont();
90 m_lineNoFont.setPixelSize(11);
92 return true;
95 void SourceWindow::reloadFile()
97 QFile f(m_fileName);
98 if (!f.open(IO_ReadOnly)) {
99 // open failed; leave alone
100 return;
103 // read text into m_sourceCode
104 m_sourceCode.clear(); /* clear old text */
106 QTextStream t(&f);
107 setText(t.read());
108 f.close();
110 m_sourceCode.resize(paragraphs());
111 for (size_t i = 0; i < m_sourceCode.size(); i++) {
112 m_sourceCode[i].code = text(i);
114 // allocate line items
115 m_lineItems.resize(m_sourceCode.size(), 0);
117 m_rowToLine.resize(m_sourceCode.size());
118 for (size_t i = 0; i < m_sourceCode.size(); i++)
119 m_rowToLine[i] = i;
122 void SourceWindow::scrollTo(int lineNo, const DbgAddr& address)
124 if (lineNo < 0 || lineNo >= int(m_sourceCode.size()))
125 return;
127 int row = lineToRow(lineNo, address);
128 scrollToRow(row);
131 void SourceWindow::scrollToRow(int row)
133 setCursorPosition(row, 0);
134 ensureCursorVisible();
137 void SourceWindow::drawFrame(QPainter* p)
139 QTextEdit::drawFrame(p);
141 // and paragraph at the top is...
142 int top = paragraphAt(QPoint(0,contentsY()));
143 int bot = paragraphAt(QPoint(0,contentsY()+visibleHeight()-1));
144 if (bot < 0)
145 bot = paragraphs()-1;
147 p->save();
149 // set a clip rectangle
150 int fw = frameWidth();
151 QRect inside = rect();
152 inside.addCoords(fw,fw,-fw,-fw);
153 QRegion clip = p->clipRegion();
154 clip &= QRegion(inside);
155 p->setClipRegion(clip);
157 p->setFont(m_lineNoFont);
158 p->setPen(colorGroup().text());
159 p->eraseRect(inside);
161 for (int row = top; row <= bot; row++)
163 uchar item = m_lineItems[row];
164 p->save();
166 QRect r = paragraphRect(row);
167 QPoint pt = contentsToViewport(r.topLeft());
168 int h = r.height();
169 p->translate(fw, pt.y()+viewport()->y());
171 if (item & liBP) {
172 // enabled breakpoint
173 int y = (h - m_brkena.height())/2;
174 if (y < 0) y = 0;
175 p->drawPixmap(0,y,m_brkena);
177 if (item & liBPdisabled) {
178 // disabled breakpoint
179 int y = (h - m_brkdis.height())/2;
180 if (y < 0) y = 0;
181 p->drawPixmap(0,y,m_brkdis);
183 if (item & liBPtemporary) {
184 // temporary breakpoint marker
185 int y = (h - m_brktmp.height())/2;
186 if (y < 0) y = 0;
187 p->drawPixmap(0,y,m_brktmp);
189 if (item & liBPconditional) {
190 // conditional breakpoint marker
191 int y = (h - m_brkcond.height())/2;
192 if (y < 0) y = 0;
193 p->drawPixmap(0,y,m_brkcond);
195 if (item & liBPorphan) {
196 // orphaned breakpoint marker
197 int y = (h - m_brkcond.height())/2;
198 if (y < 0) y = 0;
199 p->drawPixmap(0,y,m_brkorph);
201 if (item & liPC) {
202 // program counter in innermost frame
203 int y = (h - m_pcinner.height())/2;
204 if (y < 0) y = 0;
205 p->drawPixmap(0,y,m_pcinner);
207 if (item & liPCup) {
208 // program counter somewhere up the stack
209 int y = (h - m_pcup.height())/2;
210 if (y < 0) y = 0;
211 p->drawPixmap(0,y,m_pcup);
213 p->translate(m_widthItems, 0);
214 if (!isRowDisassCode(row) && m_sourceCode[rowToLine(row)].canDisass) {
215 int w = m_widthPlus;
216 int x = w/2;
217 int y = h/2;
218 p->drawLine(x-2, y, x+2, y);
219 if (!isRowExpanded(row)) {
220 p->drawLine(x, y-2, x, y+2);
223 p->translate(m_widthPlus, 0);
224 if (!isRowDisassCode(row)) {
225 p->drawText(0, 0, m_widthLineNo, h, Qt::AlignRight|Qt::AlignVCenter,
226 QString().setNum(rowToLine(row)+1));
228 p->restore();
230 p->restore();
233 void SourceWindow::updateLineItems(const KDebugger* dbg)
235 // clear outdated breakpoints
236 for (int i = m_lineItems.size()-1; i >= 0; i--) {
237 if (m_lineItems[i] & liBPany) {
238 // check if this breakpoint still exists
239 int line = rowToLine(i);
240 TRACE(QString().sprintf("checking for bp at %d", line));
241 KDebugger::BrkptROIterator bp = dbg->breakpointsBegin();
242 for (; bp != dbg->breakpointsEnd(); ++bp)
244 if (bp->lineNo == line &&
245 fileNameMatches(bp->fileName) &&
246 lineToRow(line, bp->address) == i)
248 // yes it exists; mode is changed below
249 break;
252 if (bp == dbg->breakpointsEnd()) {
253 /* doesn't exist anymore, remove it */
254 m_lineItems[i] &= ~liBPany;
255 update();
260 // add new breakpoints
261 for (KDebugger::BrkptROIterator bp = dbg->breakpointsBegin(); bp != dbg->breakpointsEnd(); ++bp)
263 if (fileNameMatches(bp->fileName)) {
264 TRACE(QString().sprintf("updating %s:%d", bp->fileName.data(), bp->lineNo));
265 int i = bp->lineNo;
266 if (i < 0 || i >= int(m_sourceCode.size()))
267 continue;
268 // compute new line item flags for breakpoint
269 uchar flags = bp->enabled ? liBP : liBPdisabled;
270 if (bp->temporary)
271 flags |= liBPtemporary;
272 if (!bp->condition.isEmpty() || bp->ignoreCount != 0)
273 flags |= liBPconditional;
274 if (bp->isOrphaned())
275 flags |= liBPorphan;
276 // update if changed
277 int row = lineToRow(i, bp->address);
278 if ((m_lineItems[row] & liBPany) != flags) {
279 m_lineItems[row] &= ~liBPany;
280 m_lineItems[row] |= flags;
281 update();
287 void SourceWindow::setPC(bool set, int lineNo, const DbgAddr& address, int frameNo)
289 if (lineNo < 0 || lineNo >= int(m_sourceCode.size())) {
290 return;
293 int row = lineToRow(lineNo, address);
295 uchar flag = frameNo == 0 ? liPC : liPCup;
296 if (set) {
297 // set only if not already set
298 if ((m_lineItems[row] & flag) == 0) {
299 m_lineItems[row] |= flag;
300 update();
302 } else {
303 // clear only if not set
304 if ((m_lineItems[row] & flag) != 0) {
305 m_lineItems[row] &= ~flag;
306 update();
311 void SourceWindow::find(const QString& text, bool caseSensitive, FindDirection dir)
313 ASSERT(dir == 1 || dir == -1);
314 if (QTextEdit::find(text, caseSensitive, false, dir > 0))
315 return;
316 // not found; wrap around
317 int para = dir > 0 ? 0 : paragraphs(), index = 0;
318 QTextEdit::find(text, caseSensitive, false, dir > 0, &para, &index);
321 void SourceWindow::mousePressEvent(QMouseEvent* ev)
323 // we handle left and middle button
324 if (ev->button() != Qt::LeftButton && ev->button() != Qt::MidButton)
326 QTextEdit::mousePressEvent(ev);
327 return;
330 // get row
331 QPoint p = viewportToContents(QPoint(0, ev->y() - viewport()->y()));
332 int row = paragraphAt(p);
333 if (row < 0)
334 return;
336 if (ev->x() > m_widthItems+frameWidth())
338 if (isRowExpanded(row)) {
339 actionCollapseRow(row);
340 } else {
341 actionExpandRow(row);
343 return;
346 int sourceRow;
347 int line = rowToLine(row, &sourceRow);
349 // find address if row is disassembled code
350 DbgAddr address;
351 if (row > sourceRow) {
352 // get offset from source code line
353 int off = row - sourceRow;
354 address = m_sourceCode[line].disassAddr[off-1];
357 switch (ev->button()) {
358 case Qt::LeftButton:
359 TRACE(QString().sprintf("left-clicked line %d", line));
360 emit clickedLeft(m_fileName, line, address,
361 (ev->state() & Qt::ShiftButton) != 0);
362 break;
363 case Qt::MidButton:
364 TRACE(QString().sprintf("mid-clicked row %d", line));
365 emit clickedMid(m_fileName, line, address);
366 break;
367 default:;
371 void SourceWindow::keyPressEvent(QKeyEvent* ev)
373 int top1, top2;
374 QPoint top;
375 switch (ev->key()) {
376 case Qt::Key_Plus:
377 actionExpandRow(m_curRow);
378 return;
379 case Qt::Key_Minus:
380 actionCollapseRow(m_curRow);
381 return;
382 case Qt::Key_Up:
383 if (m_curRow > 0) {
384 setCursorPosition(m_curRow-1, 0);
386 return;
387 case Qt::Key_Down:
388 if (m_curRow < paragraphs()-1) {
389 setCursorPosition(m_curRow+1, 0);
391 return;
392 case Qt::Key_Home:
393 setCursorPosition(0, 0);
394 return;
395 case Qt::Key_End:
396 setCursorPosition(paragraphs()-1, 0);
397 return;
398 case Qt::Key_Next:
399 case Qt::Key_Prior:
400 top = viewportToContents(QPoint(0,0));
401 top1 = paragraphAt(top);
404 QTextEdit::keyPressEvent(ev);
406 switch (ev->key()) {
407 case Qt::Key_Next:
408 case Qt::Key_Prior:
409 top = viewportToContents(QPoint(0,0));
410 top2 = paragraphAt(top);
411 setCursorPosition(m_curRow+(top2-top1), 0);
415 static inline bool isident(QChar c)
417 return c.isLetterOrNumber() || c.latin1() == '_';
420 bool SourceWindow::wordAtPoint(const QPoint& p, QString& word, QRect& r)
422 QPoint pv = viewportToContents(p - viewport()->pos());
423 int row, col = charAt(pv, &row);
424 if (row < 0 || col < 0)
425 return false;
427 // isolate the word at row, col
428 QString line = text(row);
429 if (!isident(line[col]))
430 return false;
432 int begin = col;
433 while (begin > 0 && isident(line[begin-1]))
434 --begin;
436 ++col;
437 while (col < int(line.length()) && isident(line[col]));
439 r = QRect(p, p);
440 r.addCoords(-5,-5,5,5);
441 word = line.mid(begin, col-begin);
442 return true;
445 void SourceWindow::paletteChange(const QPalette& oldPal)
447 setFont(KGlobalSettings::fixedFont());
448 QTextEdit::paletteChange(oldPal);
452 * Two file names (possibly full paths) match if the last parts - the file
453 * names - match.
455 bool SourceWindow::fileNameMatches(const QString& other)
457 return QFileInfo(other).fileName() == QFileInfo(m_fileName).fileName();
460 void SourceWindow::disassembled(int lineNo, const std::list<DisassembledCode>& disass)
462 TRACE("disassembled line " + QString().setNum(lineNo));
463 if (lineNo < 0 || lineNo >= int(m_sourceCode.size()))
464 return;
466 SourceLine& sl = m_sourceCode[lineNo];
468 // copy disassembled code and its addresses
469 sl.disass.resize(disass.size());
470 sl.disassAddr.resize(disass.size());
471 sl.canDisass = !disass.empty();
472 int i = 0;
473 for (std::list<DisassembledCode>::const_iterator c = disass.begin(); c != disass.end(); ++c, ++i)
475 QString code = c->code;
476 while (code.endsWith("\n"))
477 code.truncate(code.length()-1);
478 sl.disass[i] = c->address.asString() + ' ' + code;
479 sl.disassAddr[i] = c->address;
482 int row = lineToRow(lineNo);
483 if (sl.canDisass) {
484 expandRow(row);
485 } else {
486 // clear expansion marker
487 update();
491 int SourceWindow::rowToLine(int row, int* sourceRow)
493 int line = row >= 0 ? m_rowToLine[row] : -1;
494 if (sourceRow != 0) {
495 // search back until we hit the first entry with the current line number
496 while (row > 0 && m_rowToLine[row-1] == line)
497 row--;
498 *sourceRow = row;
500 return line;
504 * Rows showing diassembled code have the same line number as the
505 * corresponding source code line number. Therefore, the line numbers in
506 * m_rowToLine are monotonically increasing with blocks of equal line
507 * numbers for a source line and its disassembled code that follows it.
509 * Hence, m_rowToLine always obeys the following condition:
511 * m_rowToLine[i] <= i
514 int SourceWindow::lineToRow(int line)
516 // line is zero-based!
518 assert(line < int(m_rowToLine.size()));
520 // quick test for common case
521 if (line < 0 || m_rowToLine[line] == line)
522 return line;
524 assert(m_rowToLine[line] < line);
527 * Binary search between row == line and end of list. In the loop below
528 * we use the fact that the line numbers m_rowToLine do not contain
529 * holes.
531 int l = line;
532 int h = m_rowToLine.size();
533 while (l < h && m_rowToLine[l] != line)
535 assert(h == int(m_rowToLine.size()) || m_rowToLine[l] < m_rowToLine[h]);
538 * We want to round down the midpoint so that we find the
539 * lowest row that belongs to the line we seek.
541 int mid = (l+h)/2;
542 if (m_rowToLine[mid] <= line)
543 l = mid;
544 else
545 h = mid;
547 // Found! Result is in l:
548 assert(m_rowToLine[l] == line);
551 * We might not have hit the lowest index for the line.
553 while (l > 0 && m_rowToLine[l-1] == line)
554 --l;
556 return l;
559 int SourceWindow::lineToRow(int line, const DbgAddr& address)
561 int row = lineToRow(line);
562 if (isRowExpanded(row)) {
563 row += m_sourceCode[line].findAddressRowOffset(address);
565 return row;
568 bool SourceWindow::isRowExpanded(int row)
570 assert(row >= 0);
571 return row < int(m_rowToLine.size())-1 &&
572 m_rowToLine[row] == m_rowToLine[row+1];
575 bool SourceWindow::isRowDisassCode(int row)
577 return row > 0 && row < int(m_rowToLine.size()) &&
578 m_rowToLine[row] == m_rowToLine[row-1];
581 void SourceWindow::expandRow(int row)
583 TRACE("expanding row " + QString().setNum(row));
584 // get disassembled code
585 int line = rowToLine(row);
586 const std::vector<QString>& disass = m_sourceCode[line].disass;
588 // remove PC (must be set again in slot of signal expanded())
589 m_lineItems[row] &= ~(liPC|liPCup);
591 // adjust current row
592 if (m_curRow > row) {
593 m_curRow += disass.size();
594 // highlight is moved automatically
597 // insert new lines
598 setUpdatesEnabled(false);
599 ++row;
600 for (size_t i = 0; i < disass.size(); i++) {
601 m_rowToLine.insert(m_rowToLine.begin()+row, line);
602 m_lineItems.insert(m_lineItems.begin()+row, 0);
603 insertParagraph(disass[i], row++);
605 setUpdatesEnabled(true);
606 viewport()->update();
607 update(); // line items
609 emit expanded(line); /* must set PC */
612 void SourceWindow::collapseRow(int row)
614 TRACE("collapsing row " + QString().setNum(row));
615 int line = rowToLine(row);
617 // find end of this block
618 int end = row+1;
619 while (end < int(m_rowToLine.size()) && m_rowToLine[end] == m_rowToLine[row]) {
620 end++;
622 ++row;
623 // adjust current row
624 if (m_curRow >= row) {
625 m_curRow -= end-row;
626 if (m_curRow < row) // was m_curRow in disassembled code?
627 m_curRow = -1;
629 setUpdatesEnabled(false);
630 while (--end >= row) {
631 m_rowToLine.erase(m_rowToLine.begin()+end);
632 m_lineItems.erase(m_lineItems.begin()+end);
633 removeParagraph(end);
635 setUpdatesEnabled(true);
636 viewport()->update();
637 update(); // line items
639 emit collapsed(line);
642 void SourceWindow::activeLine(int& line, DbgAddr& address)
644 int row = m_curRow;
646 int sourceRow;
647 line = rowToLine(row, &sourceRow);
648 if (row > sourceRow) {
649 int off = row - sourceRow; /* offset from source line */
650 address = m_sourceCode[line].disassAddr[off-1];
655 * Returns the offset from the line displaying the source code to
656 * the line containing the specified address. If the address is not
657 * found, 0 is returned.
659 int SourceWindow::SourceLine::findAddressRowOffset(const DbgAddr& address) const
661 if (address.isEmpty())
662 return 0;
664 for (size_t i = 0; i < disassAddr.size(); i++) {
665 if (disassAddr[i] == address) {
666 // found exact address
667 return i+1;
669 if (disassAddr[i] > address) {
671 * We have already advanced too far; the address is before this
672 * index, but obviously we haven't found an exact match
673 * earlier. address is somewhere between the displayed
674 * addresses. We return the previous line.
676 return i;
679 // not found
680 return 0;
683 void SourceWindow::actionExpandRow(int row)
685 if (row < 0 || isRowExpanded(row) || isRowDisassCode(row))
686 return;
688 // disassemble
689 int line = rowToLine(row);
690 const SourceLine& sl = m_sourceCode[line];
691 if (!sl.canDisass)
692 return;
693 if (sl.disass.size() == 0) {
694 emit disassemble(m_fileName, line);
695 } else {
696 expandRow(row);
700 void SourceWindow::actionCollapseRow(int row)
702 if (row < 0 || !isRowExpanded(row) || isRowDisassCode(row))
703 return;
705 collapseRow(row);
708 void SourceWindow::setTabWidth(int numChars)
710 if (numChars <= 0)
711 numChars = 8;
712 QFontMetrics fm(currentFont());
713 QString s;
714 int w = fm.width(s.fill('x', numChars));
715 setTabStopWidth(w);
718 void SourceWindow::cursorChanged(int row)
720 if (row == m_curRow)
721 return;
723 if (m_curRow >= 0 && m_curRow < paragraphs())
724 clearParagraphBackground(m_curRow);
725 m_curRow = row;
726 setParagraphBackgroundColor(row, colorGroup().background());
730 * We must override the context menu handling because QTextEdit's handling
731 * requires that it receives ownership of the popup menu; but the popup menu
732 * returned from the GUI factory is owned by the factory.
735 void SourceWindow::contextMenuEvent(QContextMenuEvent* e)
737 // get the context menu from the GUI factory
738 QWidget* top = this;
740 top = top->parentWidget();
741 while (!top->isTopLevel());
742 KMainWindow* mw = static_cast<KMainWindow*>(top);
743 QPopupMenu* m =
744 static_cast<QPopupMenu*>(mw->factory()->container("popup_files", mw));
745 m->exec(e->globalPos());
748 bool SourceWindow::eventFilter(QObject* watched, QEvent* e)
750 if (e->type() == QEvent::ContextMenu && watched == viewport())
752 contextMenuEvent(static_cast<QContextMenuEvent*>(e));
753 return true;
755 return QTextEdit::eventFilter(watched, e);
758 HighlightCpp::HighlightCpp(SourceWindow* srcWnd) :
759 QSyntaxHighlighter(srcWnd),
760 m_srcWnd(srcWnd)
764 enum HLState {
765 hlCommentLine = 1,
766 hlCommentBlock,
767 hlIdent,
768 hlString
771 static const QString ckw[] =
773 "and",
774 "and_eq",
775 "asm",
776 "auto",
777 "bitand",
778 "bitor",
779 "bool",
780 "break",
781 "case",
782 "catch",
783 "char",
784 "class",
785 "compl",
786 "const",
787 "const_cast",
788 "continue",
789 "default",
790 "delete",
791 "do",
792 "double",
793 "dynamic_cast",
794 "else",
795 "enum",
796 "explicit",
797 "export",
798 "extern",
799 "false",
800 "float",
801 "for",
802 "friend",
803 "goto",
804 "if",
805 "inline",
806 "int",
807 "long",
808 "mutable",
809 "namespace",
810 "new",
811 "not",
812 "not_eq",
813 "operator",
814 "or",
815 "or_eq",
816 "private",
817 "protected",
818 "public",
819 "reinterpret_cast",
820 "register",
821 "return",
822 "short",
823 "signed",
824 "sizeof",
825 "static",
826 "static_cast",
827 "struct",
828 "switch",
829 "template",
830 "this",
831 "throw",
832 "true",
833 "try",
834 "typedef",
835 "typeid",
836 "typename",
837 "using",
838 "union",
839 "unsigned",
840 "virtual",
841 "void",
842 "volatile",
843 "wchar_t",
844 "while",
845 "xor",
846 "xor_eq"
849 int HighlightCpp::highlightParagraph(const QString& text, int state)
851 int row = currentParagraph();
852 // highlight assembly lines
853 if (m_srcWnd->isRowDisassCode(row))
855 setFormat(0, text.length(), Qt::blue);
856 return state;
859 if (state == -2) // initial state
860 state = 0;
862 // check for preprocessor line
863 if (state == 0 && text.stripWhiteSpace().startsWith("#"))
865 setFormat(0, text.length(), QColor("dark green"));
866 return 0;
869 // a font for keywords
870 QFont identFont = textEdit()->currentFont();
871 identFont.setBold(!identFont.bold());
873 unsigned start = 0;
874 while (start < text.length())
876 int end;
877 switch (state) {
878 case hlCommentLine:
879 end = text.length();
880 state = 0;
881 setFormat(start, end-start, QColor("gray50"));
882 break;
883 case hlCommentBlock:
884 end = text.find("*/", start);
885 if (end >= 0)
886 end += 2, state = 0;
887 else
888 end = text.length();
889 setFormat(start, end-start, QColor("gray50"));
890 break;
891 case hlString:
892 for (end = start+1; end < int(text.length()); end++) {
893 if (text[end] == '\\') {
894 if (end < int(text.length()))
895 ++end;
896 } else if (text[end] == text[start]) {
897 ++end;
898 break;
901 state = 0;
902 setFormat(start, end-start, QColor("dark red"));
903 break;
904 case hlIdent:
905 for (end = start+1; end < int(text.length()); end++) {
906 if (!text[end].isLetterOrNumber() && text[end] != '_')
907 break;
909 state = 0;
910 if (std::binary_search(ckw, ckw + sizeof(ckw)/sizeof(ckw[0]),
911 text.mid(start, end-start)))
913 setFormat(start, end-start, identFont);
914 } else {
915 setFormat(start, end-start, m_srcWnd->colorGroup().text());
917 break;
918 default:
919 for (end = start; end < int(text.length()); end++)
921 if (text[end] == '/')
923 if (end+1 < int(text.length())) {
924 if (text[end+1] == '/') {
925 state = hlCommentLine;
926 break;
927 } else if (text[end+1] == '*') {
928 state = hlCommentBlock;
929 break;
933 else if (text[end] == '"' || text[end] == '\'')
935 state = hlString;
936 break;
938 else if (text[end] >= 'A' && text[end] <= 'Z' ||
939 text[end] >= 'a' && text[end] <= 'z' ||
940 text[end] == '_')
942 state = hlIdent;
943 break;
946 setFormat(start, end-start, m_srcWnd->colorGroup().text());
948 start = end;
950 return state;
953 #include "sourcewnd.moc"