Skip to content

Commit a1fe6f0

Browse files
committed
feat: support regex search
Since we use QSortFilterProxyModel we get this for free. This patch adds support for regex search by not escaping the search term if it is prefix with %. For the flamegraph there is a custom implementation, which changes the current QString::contains to a QRegularExpression::match call. Closes: #666
1 parent 36bedef commit a1fe6f0

File tree

7 files changed

+24
-13
lines changed

7 files changed

+24
-13
lines changed

src/flamegraph.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -546,14 +546,15 @@ struct SearchResults
546546
qint64 directCost = 0;
547547
};
548548

549-
SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue)
549+
SearchResults applySearch(FrameGraphicsItem* item, const QRegularExpression& expression, const QString& pattern)
550550
{
551551
SearchResults result;
552-
if (searchValue.isEmpty()) {
552+
if (expression.pattern().isEmpty()) {
553553
result.matchType = NoSearch;
554-
} else if (item->symbol().symbol.contains(searchValue, Qt::CaseInsensitive)
555-
|| (searchValue == QLatin1String("??") && item->symbol().symbol.isEmpty())
556-
|| item->symbol().binary.contains(searchValue, Qt::CaseInsensitive)) {
554+
} else if (expression.match(item->symbol().symbol).hasMatch()
555+
|| item->symbol().symbol.contains(pattern, Qt::CaseInsensitive)
556+
|| (pattern == QLatin1String("??") && item->symbol().symbol.isEmpty())
557+
|| item->symbol().binary.contains(pattern, Qt::CaseInsensitive)) {
557558
result.directCost += item->cost();
558559
result.matchType = DirectMatch;
559560
}
@@ -562,7 +563,7 @@ SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue)
562563
const auto children = item->childItems();
563564
for (auto* child : children) {
564565
auto* childFrame = static_cast<FrameGraphicsItem*>(child);
565-
auto childMatch = applySearch(childFrame, searchValue);
566+
auto childMatch = applySearch(childFrame, expression, pattern);
566567
if (result.matchType != DirectMatch
567568
&& (childMatch.matchType == DirectMatch || childMatch.matchType == ChildMatch)) {
568569
result.matchType = ChildMatch;
@@ -806,7 +807,8 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags)
806807
layout->addWidget(searchInput);
807808

808809
searchInput->setPlaceholderText(i18n("Search..."));
809-
searchInput->setToolTip(i18n("<qt>Search the flame graph for a symbol.</qt>"));
810+
searchInput->setToolTip(tr("<html><head/><body><p>Filter the call graph tree.<br/>Prefix with '%' to turn "
811+
"it into an regex.</p></body></html>"));
810812
searchInput->setClearButtonEnabled(true);
811813
connect(searchInput, &QLineEdit::textChanged, this, &FlameGraph::setSearchValue);
812814
connect(this, &FlameGraph::uiResetRequested, this, [this, searchInput] {
@@ -1210,9 +1212,10 @@ void FlameGraph::setSearchValue(const QString& value)
12101212
return;
12111213
}
12121214

1213-
m_search = value;
1215+
m_search = value.startsWith(QLatin1Char('%')) ? value.mid(1) : value;
12141216

1215-
auto match = applySearch(m_rootItem, value);
1217+
const QRegularExpression regex(Util::escapeSearchPatternIfNessessary(value));
1218+
auto match = applySearch(m_rootItem, regex, value);
12161219

12171220
if (value.isEmpty()) {
12181221
m_searchResultsLabel->hide();

src/resultsbottomuppage.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<item>
6868
<widget class="QLineEdit" name="bottomUpSearch">
6969
<property name="toolTip">
70-
<string>Filter the call graph tree.</string>
70+
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Filter the call graph tree.&lt;br/&gt;Prefix with '%' to turn it into an regex.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
7171
</property>
7272
</widget>
7373
</item>

src/resultscallercalleepage.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<item>
6868
<widget class="QLineEdit" name="callerCalleeFilter">
6969
<property name="toolTip">
70-
<string>Filter the call graph tree.</string>
70+
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Filter the call graph tree.&lt;br/&gt;Prefix with '%' to turn it into an regex.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
7171
</property>
7272
</widget>
7373
</item>

src/resultstopdownpage.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<item>
6868
<widget class="QLineEdit" name="topDownSearch">
6969
<property name="toolTip">
70-
<string>Filter the call graph tree.</string>
70+
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Filter the call graph tree.&lt;br/&gt;Prefix with '%' to turn it into an regex.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
7171
</property>
7272
</widget>
7373
</item>

src/resultsutil.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void connectFilter(QLineEdit* filter, QSortFilterProxyModel* proxy)
4545
proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
4646

4747
QObject::connect(timer, &QTimer::timeout, proxy, [filter, proxy]() {
48-
proxy->setFilterRegularExpression(QRegularExpression::escape(filter->text()));
48+
proxy->setFilterRegularExpression(Util::escapeSearchPatternIfNessessary(filter->text()));
4949
});
5050
QObject::connect(filter, &QLineEdit::textChanged, timer, [timer]() { timer->start(300); });
5151
}

src/util.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,8 @@ KParts::ReadOnlyPart* Util::createPart(const QString& pluginName)
455455
return service->createInstance<KParts::ReadOnlyPart>();
456456
#endif
457457
}
458+
459+
QString Util::escapeSearchPatternIfNessessary(const QString& pattern)
460+
{
461+
return pattern.startsWith(QLatin1Char('%')) ? pattern.mid(1) : QRegularExpression::escape(pattern);
462+
}

src/util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,7 @@ QString collapseTemplate(const QString& str, int level);
7474
QProcessEnvironment appImageEnvironment();
7575

7676
KParts::ReadOnlyPart* createPart(const QString& pluginName);
77+
78+
// if a pattern is prefixed with % then return the pattern, otherwise do a regex escape
79+
QString escapeSearchPatternIfNessessary(const QString& pattern);
7780
}

0 commit comments

Comments
 (0)