Skip to content

Commit 765c49e

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 765c49e

File tree

7 files changed

+22
-12
lines changed

7 files changed

+22
-12
lines changed

src/flamegraph.cpp

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

549-
SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue)
549+
SearchResults applySearch(FrameGraphicsItem* item, const QRegularExpression& expression)
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+
|| (expression.pattern() == QLatin1String("??") && item->symbol().symbol.isEmpty())
556+
|| item->symbol().binary.contains(expression.pattern(), Qt::CaseInsensitive)) {
557557
result.directCost += item->cost();
558558
result.matchType = DirectMatch;
559559
}
@@ -562,7 +562,7 @@ SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue)
562562
const auto children = item->childItems();
563563
for (auto* child : children) {
564564
auto* childFrame = static_cast<FrameGraphicsItem*>(child);
565-
auto childMatch = applySearch(childFrame, searchValue);
565+
auto childMatch = applySearch(childFrame, expression);
566566
if (result.matchType != DirectMatch
567567
&& (childMatch.matchType == DirectMatch || childMatch.matchType == ChildMatch)) {
568568
result.matchType = ChildMatch;
@@ -806,7 +806,8 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags)
806806
layout->addWidget(searchInput);
807807

808808
searchInput->setPlaceholderText(i18n("Search..."));
809-
searchInput->setToolTip(i18n("<qt>Search the flame graph for a symbol.</qt>"));
809+
searchInput->setToolTip(tr("<html><head/><body><p>Filter the call graph tree.<br/>Prefix with '%' to turn "
810+
"it into an regex.</p></body></html>"));
810811
searchInput->setClearButtonEnabled(true);
811812
connect(searchInput, &QLineEdit::textChanged, this, &FlameGraph::setSearchValue);
812813
connect(this, &FlameGraph::uiResetRequested, this, [this, searchInput] {
@@ -1212,7 +1213,8 @@ void FlameGraph::setSearchValue(const QString& value)
12121213

12131214
m_search = value;
12141215

1215-
auto match = applySearch(m_rootItem, value);
1216+
QRegularExpression regex(Util::escapeSearchPatternIfNessessary(value));
1217+
auto match = applySearch(m_rootItem, regex);
12161218

12171219
if (value.isEmpty()) {
12181220
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)