1/*
2 Copyright (C) 2010 Milian Wolff <mail@milianw.de>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17*/
18#include "gdbhighlighter.h"
19
20#include <QTextDocument>
21
22#include <KColorScheme>
23
24GdbHighlighter::GdbHighlighter(QTextDocument* parent, const QList<BacktraceLine> & gdbLines)
25 : QSyntaxHighlighter(parent)
26{
27 // setup line lookup
28 int l = 0;
29 foreach(const BacktraceLine& line, gdbLines) {
30 lines.insert(l, line);
31 l += line.toString().count('\n');
32 }
33
34 // setup formates
35 KColorScheme scheme(QPalette::Active);
36
37 crashFormat.setForeground(scheme.foreground(KColorScheme::NegativeText));
38 nullptrFormat.setForeground(scheme.foreground(KColorScheme::NegativeText));
39 nullptrFormat.setFontWeight(QFont::Bold);
40 assertFormat = nullptrFormat;
41 threadFormat.setForeground(scheme.foreground(KColorScheme::NeutralText));
42 urlFormat.setForeground(scheme.foreground(KColorScheme::LinkText));
43 funcFormat.setForeground(scheme.foreground(KColorScheme::VisitedText));
44 funcFormat.setFontWeight(QFont::Bold);
45 otheridFormat.setForeground(scheme.foreground(KColorScheme::PositiveText));
46 crapFormat.setForeground(scheme.foreground(KColorScheme::InactiveText));
47}
48
49void GdbHighlighter::highlightBlock(const QString& text)
50{
51 int cur = 0;
52 int next;
53 int diff;
54 const QRegExp hexptrPattern("0x[0-9a-f]+", Qt::CaseSensitive, QRegExp::RegExp2);
55 int lineNr = currentBlock().firstLineNumber();
56 while ( cur < text.length() ) {
57 next = text.indexOf('\n', cur);
58 if (next == -1) {
59 next = text.length();
60 }
61 if (lineNr == 0) {
62 // line that contains 'Application: ...'
63 ++lineNr;
64 cur = next;
65 continue;
66 }
67
68 diff = next - cur;
69
70 QString lineStr = text.mid(cur, diff).append('\n');
71 // -1 since we skip the first line
72 QMap< int, BacktraceLine >::iterator it = lines.lowerBound(lineNr - 1);
73 Q_ASSERT(it != lines.end());
74 // lowerbound would return the next higher item, even though we want the former one
75 if (it.key() > lineNr - 1) {
76 --it;
77 }
78 const BacktraceLine& line = it.value();
79
80 if (line.type() == BacktraceLine::KCrash) {
81 setFormat(cur, diff, crashFormat);
82 } else if (line.type() == BacktraceLine::ThreadStart || line.type() == BacktraceLine::ThreadIndicator) {
83 setFormat(cur, diff, threadFormat);
84 } else if (line.type() == BacktraceLine::Crap) {
85 setFormat(cur, diff, crapFormat);
86 } else if (line.type() == BacktraceLine::StackFrame) {
87 if (!line.fileName().isEmpty()) {
88 int colonPos = line.fileName().lastIndexOf(':');
89 setFormat(lineStr.indexOf(line.fileName()), colonPos == -1 ? line.fileName().length() : colonPos, urlFormat);
90 }
91 if (!line.libraryName().isEmpty()) {
92 setFormat(lineStr.indexOf(line.libraryName()), line.libraryName().length(), urlFormat);
93 }
94 if (!line.functionName().isEmpty()) {
95 int idx = lineStr.indexOf(line.functionName());
96 if (idx != -1) {
97 // highlight Id::Id::Id::Func
98 // Id should have otheridFormat, :: no format and Func funcFormat
99 int i = idx;
100 int from = idx;
101 while (i < idx + line.functionName().length()) {
102 if (lineStr.at(i) == ':') {
103 setFormat(from, i - from, otheridFormat);
104 // skip ::
105 i += 2;
106 from = i;
107 continue;
108 } else if (lineStr.at(i) == '<' || lineStr.at(i) == '>') {
109 setFormat(from, i - from, otheridFormat);
110 ++i;
111 from = i;
112 continue;
113 }
114 ++i;
115 }
116 if (line.functionName() == "qFatal" || line.functionName() == "abort" || line.functionName() == "__assert_fail"
117 || line.functionName() == "*__GI___assert_fail" || line.functionName() == "*__GI_abort") {
118 setFormat(from, i - from, assertFormat);
119 } else {
120 setFormat(from, i - from, funcFormat);
121 }
122 }
123 }
124 // highlight hexadecimal ptrs
125 int idx = 0;
126 while ((idx = hexptrPattern.indexIn(lineStr, idx)) != -1) {
127 if (hexptrPattern.cap() == "0x0") {
128 setFormat(idx, hexptrPattern.matchedLength(), nullptrFormat);
129 }
130 idx += hexptrPattern.matchedLength();
131 }
132 }
133
134 cur = next;
135 ++lineNr;
136 }
137}
138