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.
10 #include <QTextStream>
14 #include <QFontDatabase>
16 #include <QContextMenuEvent>
18 #include <QMouseEvent>
19 #include <kiconloader.h>
20 #include <kxmlguiwindow.h>
21 #include <kxmlguifactory.h>
26 SourceWindow::SourceWindow(const QString
& fileName
, QWidget
* parent
) :
27 QPlainTextEdit(parent
),
33 m_lineInfoArea(new LineInfoArea(this))
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(QFontDatabase::systemFont(QFontDatabase::FixedFont
));
45 setViewportMargins(lineInfoAreaWidth(), 0, 0 ,0);
46 setWordWrapMode(QTextOption::NoWrap
);
47 connect(this, SIGNAL(updateRequest(const QRect
&, int)),
48 m_lineInfoArea
, SLOT(update()));
49 connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorChanged()));
51 // add a syntax highlighter
52 if (QRegExp("\\.(c(pp|c|\\+\\+)?|CC?|h(\\+\\+|h|pp)?|HH?)$").indexIn(m_fileName
) >= 0)
54 m_highlighter
= new HighlightCpp(this);
58 SourceWindow::~SourceWindow()
63 int SourceWindow::lineInfoAreaWidth() const
65 return 3 + m_widthItems
+ m_widthPlus
+ m_widthLineNo
;
68 bool SourceWindow::loadFile()
71 if (!f
.open(QIODevice::ReadOnly
)) {
76 setPlainText(t
.readAll());
80 m_sourceCode
.resize(n
);
81 m_rowToLine
.resize(n
);
82 for (int i
= 0; i
< n
; i
++) {
85 m_lineItems
.resize(n
, 0);
87 // set a font for line numbers
88 m_lineNoFont
= currentCharFormat().font();
89 m_lineNoFont
.setPixelSize(11);
94 void SourceWindow::reloadFile()
97 if (!f
.open(QIODevice::ReadOnly
)) {
98 // open failed; leave alone
102 m_sourceCode
.clear(); /* clear old text */
105 setPlainText(t
.readAll());
108 m_sourceCode
.resize(blockCount());
109 // expanded lines are collapsed: move existing line items up
110 for (size_t i
= 0; i
< m_lineItems
.size(); i
++) {
111 if (m_rowToLine
[i
] != int(i
)) {
112 m_lineItems
[m_rowToLine
[i
]] |= m_lineItems
[i
];
116 // allocate line items
117 m_lineItems
.resize(m_sourceCode
.size(), 0);
119 m_rowToLine
.resize(m_sourceCode
.size());
120 for (size_t i
= 0; i
< m_sourceCode
.size(); i
++)
123 // Highlighting was applied above when the text was inserted into widget,
124 // but at that time m_rowToLine was not corrected, yet, so that lines
125 // that previously were assembly were painted incorrectly.
127 m_highlighter
->rehighlight();
130 void SourceWindow::scrollTo(int lineNo
, const DbgAddr
& address
)
132 if (lineNo
< 0 || lineNo
>= int(m_sourceCode
.size()))
135 int row
= lineToRow(lineNo
, address
);
139 void SourceWindow::scrollToRow(int row
)
141 QTextCursor
cursor(document()->findBlockByNumber(row
));
142 setTextCursor(cursor
);
143 ensureCursorVisible();
146 void SourceWindow::resizeEvent(QResizeEvent
* e
)
148 QPlainTextEdit::resizeEvent(e
);
150 QRect cr
= contentsRect();
151 cr
.setRight(lineInfoAreaWidth());
152 m_lineInfoArea
->setGeometry(cr
);
155 void SourceWindow::drawLineInfoArea(QPainter
* p
, QPaintEvent
* event
)
157 QTextBlock block
= firstVisibleBlock();
159 p
->setFont(m_lineNoFont
);
161 for (; block
.isValid(); block
= block
.next())
163 if (!block
.isVisible())
166 QRect r
= blockBoundingGeometry(block
).translated(contentOffset()).toRect();
167 if (r
.bottom() < event
->rect().top())
168 continue; // skip blocks that are higher than the region being updated
169 else if (r
.top() > event
->rect().bottom())
170 break; // all the following blocks are lower then the region being updated
172 int row
= block
.blockNumber();
173 uchar item
= m_lineItems
[row
];
177 p
->translate(0, r
.top());
180 // enabled breakpoint
181 int y
= (h
- m_brkena
.height())/2;
183 p
->drawPixmap(0,y
,m_brkena
);
185 if (item
& liBPdisabled
) {
186 // disabled breakpoint
187 int y
= (h
- m_brkdis
.height())/2;
189 p
->drawPixmap(0,y
,m_brkdis
);
191 if (item
& liBPtemporary
) {
192 // temporary breakpoint marker
193 int y
= (h
- m_brktmp
.height())/2;
195 p
->drawPixmap(0,y
,m_brktmp
);
197 if (item
& liBPconditional
) {
198 // conditional breakpoint marker
199 int y
= (h
- m_brkcond
.height())/2;
201 p
->drawPixmap(0,y
,m_brkcond
);
203 if (item
& liBPorphan
) {
204 // orphaned breakpoint marker
205 int y
= (h
- m_brkcond
.height())/2;
207 p
->drawPixmap(0,y
,m_brkorph
);
210 // program counter in innermost frame
211 int y
= (h
- m_pcinner
.height())/2;
213 p
->drawPixmap(0,y
,m_pcinner
);
216 // program counter somewhere up the stack
217 int y
= (h
- m_pcup
.height())/2;
219 p
->drawPixmap(0,y
,m_pcup
);
221 p
->translate(m_widthItems
, 0);
222 if (!isRowDisassCode(row
) && m_sourceCode
[rowToLine(row
)].canDisass
) {
226 p
->drawLine(x
-2, y
, x
+2, y
);
227 if (!isRowExpanded(row
)) {
228 p
->drawLine(x
, y
-2, x
, y
+2);
231 p
->translate(m_widthPlus
, 0);
232 if (!isRowDisassCode(row
)) {
233 p
->drawText(0, 0, m_widthLineNo
, h
, Qt::AlignRight
|Qt::AlignVCenter
,
234 QString().setNum(rowToLine(row
)+1));
240 void SourceWindow::updateLineItems(const KDebugger
* dbg
)
242 // clear outdated breakpoints
243 for (int i
= m_lineItems
.size()-1; i
>= 0; i
--) {
244 if (m_lineItems
[i
] & liBPany
) {
245 // check if this breakpoint still exists
246 int line
= rowToLine(i
);
247 TRACE(QString().sprintf("checking for bp at %d", line
));
248 KDebugger::BrkptROIterator bp
= dbg
->breakpointsBegin();
249 for (; bp
!= dbg
->breakpointsEnd(); ++bp
)
251 if (bp
->lineNo
== line
&&
252 fileNameMatches(bp
->fileName
) &&
253 lineToRow(line
, bp
->address
) == i
)
255 // yes it exists; mode is changed below
259 if (bp
== dbg
->breakpointsEnd()) {
260 /* doesn't exist anymore, remove it */
261 m_lineItems
[i
] &= ~liBPany
;
266 // add new breakpoints
267 for (KDebugger::BrkptROIterator bp
= dbg
->breakpointsBegin(); bp
!= dbg
->breakpointsEnd(); ++bp
)
269 if (fileNameMatches(bp
->fileName
)) {
270 TRACE(QString("updating %2:%1").arg(bp
->lineNo
).arg(bp
->fileName
));
272 if (i
< 0 || i
>= int(m_sourceCode
.size()))
274 // compute new line item flags for breakpoint
275 uchar flags
= bp
->enabled
? liBP
: liBPdisabled
;
277 flags
|= liBPtemporary
;
278 if (!bp
->condition
.isEmpty() || bp
->ignoreCount
!= 0)
279 flags
|= liBPconditional
;
280 if (bp
->isOrphaned())
283 int row
= lineToRow(i
, bp
->address
);
284 if ((m_lineItems
[row
] & liBPany
) != flags
) {
285 m_lineItems
[row
] &= ~liBPany
;
286 m_lineItems
[row
] |= flags
;
290 m_lineInfoArea
->update();
293 void SourceWindow::setPC(bool set
, int lineNo
, const DbgAddr
& address
, int frameNo
)
295 if (lineNo
< 0 || lineNo
>= int(m_sourceCode
.size())) {
299 int row
= lineToRow(lineNo
, address
);
301 uchar flag
= frameNo
== 0 ? liPC
: liPCup
;
303 // set only if not already set
304 if ((m_lineItems
[row
] & flag
) == 0) {
305 m_lineItems
[row
] |= flag
;
306 m_lineInfoArea
->update();
309 // clear only if not set
310 if ((m_lineItems
[row
] & flag
) != 0) {
311 m_lineItems
[row
] &= ~flag
;
312 m_lineInfoArea
->update();
317 void SourceWindow::find(const QString
& text
, bool caseSensitive
, FindDirection dir
)
319 ASSERT(dir
== 1 || dir
== -1);
320 QTextDocument::FindFlags flags
= 0;
322 flags
|= QTextDocument::FindCaseSensitively
;
324 flags
|= QTextDocument::FindBackward
;
325 if (QPlainTextEdit::find(text
, flags
))
327 // not found; wrap around
328 QTextCursor
cursor(document());
330 cursor
.movePosition(QTextCursor::End
);
331 cursor
= document()->find(text
, cursor
, flags
);
332 if (!cursor
.isNull())
333 setTextCursor(cursor
);
336 void SourceWindow::infoMousePress(QMouseEvent
* ev
)
338 // we handle left and middle button
339 if (ev
->button() != Qt::LeftButton
&& ev
->button() != Qt::MidButton
)
345 int row
= cursorForPosition(QPoint(0, ev
->y())).blockNumber();
349 if (ev
->x() > m_widthItems
)
351 if (isRowExpanded(row
)) {
352 actionCollapseRow(row
);
354 actionExpandRow(row
);
360 int line
= rowToLine(row
, &sourceRow
);
362 // find address if row is disassembled code
364 if (row
> sourceRow
) {
365 // get offset from source code line
366 int off
= row
- sourceRow
;
367 address
= m_sourceCode
[line
].disassAddr
[off
-1];
370 switch (ev
->button()) {
372 TRACE(QString().sprintf("left-clicked line %d", line
));
373 emit
clickedLeft(m_fileName
, line
, address
,
374 (ev
->modifiers() & Qt::ShiftModifier
) != 0);
377 TRACE(QString().sprintf("mid-clicked row %d", line
));
378 emit
clickedMid(m_fileName
, line
, address
);
384 void SourceWindow::keyPressEvent(QKeyEvent
* ev
)
389 actionExpandRow(textCursor().blockNumber());
392 actionCollapseRow(textCursor().blockNumber());
396 moveCursor(QTextCursor::PreviousBlock
);
400 moveCursor(QTextCursor::NextBlock
);
403 moveCursor(QTextCursor::Start
);
406 moveCursor(QTextCursor::End
);
409 case Qt::Key_PageDown
:
410 top1
= firstVisibleBlock().blockNumber();
413 QPlainTextEdit::keyPressEvent(ev
);
417 case Qt::Key_PageDown
:
418 top2
= firstVisibleBlock().blockNumber();
420 QTextCursor cursor
= textCursor();
422 cursor
.movePosition(QTextCursor::NextBlock
,
423 QTextCursor::MoveAnchor
, top2
-top1
);
425 cursor
.movePosition(QTextCursor::PreviousBlock
,
426 QTextCursor::MoveAnchor
, top1
-top2
);
427 setTextCursor(cursor
);
432 QString
SourceWindow::extendExpr(const QString
&plainText
,
436 QString document
= plainText
.left(wordEnd
);
437 QString word
= plainText
.mid(wordStart
, wordEnd
- wordStart
);
438 QRegExp regex
= QRegExp("(::)?([A-Za-z_]{1}\\w*\\s*(->|\\.|::)\\s*)*" + word
+ "$");
440 #define IDENTIFIER_MAX_SIZE 256
441 // cut the document to reduce size of string to scan
442 // because of this only identifiefs of length <= IDENTIFIER_MAX_SIZE are supported
443 if (document
.length() > IDENTIFIER_MAX_SIZE
) {
444 document
.right(IDENTIFIER_MAX_SIZE
);
447 const int index
= regex
.indexIn(document
);
451 TRACE("No match, returning " + word
);
455 const int length
= regex
.matchedLength();
457 word
= plainText
.mid(index
, length
);
458 TRACE("Matched, returning " + word
);
464 bool SourceWindow::wordAtPoint(const QPoint
& p
, QString
& word
, QRect
& r
)
466 QTextCursor cursor
= cursorForPosition(viewport()->mapFrom(this, p
));
470 cursor
.select(QTextCursor::WordUnderCursor
);
471 word
= cursor
.selectedText();
476 // keep only letters and digits
477 QRegExp
w("[A-Za-z_]{1}[\\dA-Za-z_]*");
478 if (w
.indexIn(word
) < 0)
485 // if cpp highlighter is enabled - c/c++ file is being displayed
487 // check that word is not a c/c++ keyword
488 if (m_highlighter
->isCppKeyword(word
))
491 // TODO check that cursor is on top of a string literal
492 // and don't display any tooltips in this case
494 // try to extend selected word under the cursor to get a full variable name
495 word
= extendExpr(cursor
.document()->toPlainText(),
496 cursor
.selectionStart(),
497 cursor
.selectionEnd());
508 void SourceWindow::changeEvent(QEvent
* ev
)
510 switch (ev
->type()) {
511 case QEvent::ApplicationFontChange
:
512 case QEvent::FontChange
:
513 setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont
));
518 QPlainTextEdit::changeEvent(ev
);
522 * Two file names (possibly full paths) match if the last parts - the file
525 bool SourceWindow::fileNameMatches(const QString
& other
)
527 return QFileInfo(other
).fileName() == QFileInfo(m_fileName
).fileName();
530 void SourceWindow::disassembled(int lineNo
, const std::list
<DisassembledCode
>& disass
)
532 TRACE("disassembled line " + QString().setNum(lineNo
));
533 if (lineNo
< 0 || lineNo
>= int(m_sourceCode
.size()))
536 SourceLine
& sl
= m_sourceCode
[lineNo
];
538 // copy disassembled code and its addresses
539 sl
.disass
.resize(disass
.size());
540 sl
.disassAddr
.resize(disass
.size());
541 sl
.canDisass
= !disass
.empty();
543 for (std::list
<DisassembledCode
>::const_iterator c
= disass
.begin(); c
!= disass
.end(); ++c
, ++i
)
545 QString code
= c
->code
;
546 while (code
.endsWith("\n"))
547 code
.truncate(code
.length()-1);
548 sl
.disass
[i
] = c
->address
.asString() + ' ' + code
;
549 sl
.disassAddr
[i
] = c
->address
;
552 int row
= lineToRow(lineNo
);
556 // clear expansion marker
557 m_lineInfoArea
->update();
561 int SourceWindow::rowToLine(int row
, int* sourceRow
)
563 int line
= row
>= 0 ? m_rowToLine
[row
] : -1;
564 if (sourceRow
!= 0) {
565 // search back until we hit the first entry with the current line number
566 while (row
> 0 && m_rowToLine
[row
-1] == line
)
574 * Rows showing diassembled code have the same line number as the
575 * corresponding source code line number. Therefore, the line numbers in
576 * m_rowToLine are monotonically increasing with blocks of equal line
577 * numbers for a source line and its disassembled code that follows it.
579 * Hence, m_rowToLine always obeys the following condition:
581 * m_rowToLine[i] <= i
584 int SourceWindow::lineToRow(int line
)
586 // line is zero-based!
588 assert(line
< int(m_rowToLine
.size()));
590 // quick test for common case
591 if (line
< 0 || m_rowToLine
[line
] == line
)
594 assert(m_rowToLine
[line
] < line
);
597 * Binary search between row == line and end of list. In the loop below
598 * we use the fact that the line numbers m_rowToLine do not contain
602 int h
= m_rowToLine
.size();
603 while (l
< h
&& m_rowToLine
[l
] != line
)
605 assert(h
== int(m_rowToLine
.size()) || m_rowToLine
[l
] < m_rowToLine
[h
]);
608 * We want to round down the midpoint so that we find the
609 * lowest row that belongs to the line we seek.
612 if (m_rowToLine
[mid
] <= line
)
617 // Found! Result is in l:
618 assert(m_rowToLine
[l
] == line
);
621 * We might not have hit the lowest index for the line.
623 while (l
> 0 && m_rowToLine
[l
-1] == line
)
629 int SourceWindow::lineToRow(int line
, const DbgAddr
& address
)
631 int row
= lineToRow(line
);
632 if (isRowExpanded(row
)) {
633 row
+= m_sourceCode
[line
].findAddressRowOffset(address
);
638 bool SourceWindow::isRowExpanded(int row
)
641 return row
< int(m_rowToLine
.size())-1 &&
642 m_rowToLine
[row
] == m_rowToLine
[row
+1];
645 bool SourceWindow::isRowDisassCode(int row
)
647 return row
> 0 && row
< int(m_rowToLine
.size()) &&
648 m_rowToLine
[row
] == m_rowToLine
[row
-1];
651 void SourceWindow::expandRow(int row
)
653 TRACE("expanding row " + QString().setNum(row
));
654 // get disassembled code
655 int line
= rowToLine(row
);
656 const std::vector
<QString
>& disass
= m_sourceCode
[line
].disass
;
658 // remove PC (must be set again in slot of signal expanded())
659 m_lineItems
[row
] &= ~(liPC
|liPCup
);
662 setUpdatesEnabled(false);
664 m_rowToLine
.insert(m_rowToLine
.begin()+row
, disass
.size(), line
);
665 m_lineItems
.insert(m_lineItems
.begin()+row
, disass
.size(), 0);
667 QTextCursor
cursor(document()->findBlockByNumber(row
));
668 for (size_t i
= 0; i
< disass
.size(); i
++) {
669 cursor
.insertText(disass
[i
]);
670 cursor
.insertBlock();
672 setUpdatesEnabled(true);
674 emit
expanded(line
); /* must set PC */
677 void SourceWindow::collapseRow(int row
)
679 TRACE("collapsing row " + QString().setNum(row
));
680 int line
= rowToLine(row
);
682 // find end of this block
684 while (end
< int(m_rowToLine
.size()) && m_rowToLine
[end
] == m_rowToLine
[row
]) {
688 setUpdatesEnabled(false);
689 QTextCursor
cursor(document()->findBlockByNumber(end
-1));
690 while (--end
>= row
) {
691 m_rowToLine
.erase(m_rowToLine
.begin()+end
);
692 m_lineItems
.erase(m_lineItems
.begin()+end
);
693 cursor
.select(QTextCursor::BlockUnderCursor
);
694 cursor
.removeSelectedText();
696 setUpdatesEnabled(true);
698 emit
collapsed(line
);
701 void SourceWindow::activeLine(int& line
, DbgAddr
& address
)
703 int row
= textCursor().blockNumber();
706 line
= rowToLine(row
, &sourceRow
);
707 if (row
> sourceRow
) {
708 int off
= row
- sourceRow
; /* offset from source line */
709 address
= m_sourceCode
[line
].disassAddr
[off
-1];
714 * Returns the offset from the line displaying the source code to
715 * the line containing the specified address. If the address is not
716 * found, 0 is returned.
718 int SourceWindow::SourceLine::findAddressRowOffset(const DbgAddr
& address
) const
720 if (address
.isEmpty())
723 for (size_t i
= 0; i
< disassAddr
.size(); i
++) {
724 if (disassAddr
[i
] == address
) {
725 // found exact address
728 if (disassAddr
[i
] > address
) {
730 * We have already advanced too far; the address is before this
731 * index, but obviously we haven't found an exact match
732 * earlier. address is somewhere between the displayed
733 * addresses. We return the previous line.
742 void SourceWindow::actionExpandRow(int row
)
744 if (row
< 0 || isRowExpanded(row
) || isRowDisassCode(row
))
748 int line
= rowToLine(row
);
749 const SourceLine
& sl
= m_sourceCode
[line
];
752 if (sl
.disass
.size() == 0) {
753 emit
disassemble(m_fileName
, line
);
759 void SourceWindow::actionCollapseRow(int row
)
761 if (row
< 0 || !isRowExpanded(row
) || isRowDisassCode(row
))
767 void SourceWindow::setTabWidth(int numChars
)
771 QFontMetrics
fm(document()->defaultFont());
773 int w
= fm
.width(s
.fill('x', numChars
));
777 void SourceWindow::cursorChanged()
779 QList
<QTextEdit::ExtraSelection
> extraSelections
;
780 QTextEdit::ExtraSelection selection
;
782 selection
.format
.setBackground(QColor("#E7E7E7"));
783 selection
.format
.setProperty(QTextFormat::FullWidthSelection
, true);
784 selection
.cursor
= textCursor();
785 selection
.cursor
.clearSelection();
786 extraSelections
.append(selection
);
787 setExtraSelections(extraSelections
);
791 * Show our own context menu.
793 void SourceWindow::contextMenuEvent(QContextMenuEvent
* e
)
795 // get the context menu from the GUI factory
798 top
= top
->parentWidget();
799 while (!top
->isTopLevel());
800 KXmlGuiWindow
* mw
= static_cast<KXmlGuiWindow
*>(top
);
801 QMenu
* m
= static_cast<QMenu
*>(mw
->factory()->container("popup_files", mw
));
803 m
->exec(e
->globalPos());
806 void LineInfoArea::paintEvent(QPaintEvent
* e
)
809 static_cast<SourceWindow
*>(parent())->drawLineInfoArea(&p
, e
);
812 void LineInfoArea::mousePressEvent(QMouseEvent
* ev
)
814 static_cast<SourceWindow
*>(parent())->infoMousePress(ev
);
817 void LineInfoArea::contextMenuEvent(QContextMenuEvent
* e
)
819 static_cast<SourceWindow
*>(parent())->contextMenuEvent(e
);
822 HighlightCpp::HighlightCpp(SourceWindow
* srcWnd
) :
823 QSyntaxHighlighter(srcWnd
->document()),
835 static const QString ckw
[] =
923 void HighlightCpp::highlightBlock(const QString
& text
)
925 int state
= previousBlockState();
926 state
= highlight(text
, state
);
927 setCurrentBlockState(state
);
930 int HighlightCpp::highlight(const QString
& text
, int state
)
932 // highlight assembly lines
933 if (m_srcWnd
->isRowDisassCode(currentBlock().blockNumber()))
935 setFormat(0, text
.length(), Qt::blue
);
939 if (state
== -2) // initial state
942 // check for preprocessor line
943 if (state
== 0 && text
.trimmed().startsWith("#"))
945 setFormat(0, text
.length(), QColor("darkgreen"));
949 // a font for keywords
950 QTextCharFormat identFont
;
951 identFont
.setFontWeight(QFont::Bold
);
954 while (start
< text
.length())
961 setFormat(start
, end
-start
, QColor("gray"));
964 end
= text
.indexOf("*/", start
);
969 setFormat(start
, end
-start
, QColor("gray"));
972 for (end
= start
+1; end
< int(text
.length()); end
++) {
973 if (text
[end
] == '\\') {
974 if (end
< int(text
.length()))
976 } else if (text
[end
] == text
[start
]) {
982 setFormat(start
, end
-start
, QColor("darkred"));
985 for (end
= start
+1; end
< int(text
.length()); end
++) {
986 if (!text
[end
].isLetterOrNumber() && text
[end
] != '_')
990 if (isCppKeyword(text
.mid(start
, end
-start
)))
992 setFormat(start
, end
-start
, identFont
);
994 setFormat(start
, end
-start
, m_srcWnd
->palette().color(QPalette::WindowText
));
998 for (end
= start
; end
< int(text
.length()); end
++)
1000 if (text
[end
] == '/')
1002 if (end
+1 < int(text
.length())) {
1003 if (text
[end
+1] == '/') {
1004 state
= hlCommentLine
;
1006 } else if (text
[end
+1] == '*') {
1007 state
= hlCommentBlock
;
1012 else if (text
[end
] == '"' || text
[end
] == '\'')
1017 else if ((text
[end
] >= 'A' && text
[end
] <= 'Z') ||
1018 (text
[end
] >= 'a' && text
[end
] <= 'z') ||
1025 setFormat(start
, end
-start
, m_srcWnd
->palette().color(QPalette::WindowText
));
1032 bool HighlightCpp::isCppKeyword(const QString
& word
)
1035 // std::binary_search requires the search list to be sorted
1036 static bool keyword_order_verified
= false;
1037 if (!keyword_order_verified
) {
1038 for (size_t i
= 1; i
< sizeof(ckw
)/sizeof(ckw
[0]); ++i
) {
1039 if (ckw
[i
-1] > ckw
[i
]) {
1040 qDebug("\"%s\" > \"%s\"",
1041 qPrintable(ckw
[i
-1]), qPrintable(ckw
[i
]));
1045 keyword_order_verified
= true;
1049 return std::binary_search(ckw
, ckw
+ sizeof(ckw
)/sizeof(ckw
[0]), word
);
1052 #include "sourcewnd.moc"