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 | |
24 | GdbHighlighter::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 | |
49 | void 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 | |