Skip to content

Commit 9da82e4

Browse files
lievenheymilianw
authored andcommitted
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 b0e70bf commit 9da82e4

14 files changed

+122
-41
lines changed

src/flamegraph.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -546,14 +546,13 @@ 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() || expression.match(item->symbol().binary).hasMatch()
555+
|| (expression.pattern() == QLatin1String("\\?\\?") && item->symbol().symbol.isEmpty())) {
557556
result.directCost += item->cost();
558557
result.matchType = DirectMatch;
559558
}
@@ -562,7 +561,7 @@ SearchResults applySearch(FrameGraphicsItem* item, const QString& searchValue)
562561
const auto children = item->childItems();
563562
for (auto* child : children) {
564563
auto* childFrame = static_cast<FrameGraphicsItem*>(child);
565-
auto childMatch = applySearch(childFrame, searchValue);
564+
auto childMatch = applySearch(childFrame, expression);
566565
if (result.matchType != DirectMatch
567566
&& (childMatch.matchType == DirectMatch || childMatch.matchType == ChildMatch)) {
568567
result.matchType = ChildMatch;
@@ -807,13 +806,26 @@ FlameGraph::FlameGraph(QWidget* parent, Qt::WindowFlags flags)
807806
searchInput->setMinimumWidth(200);
808807
layout->addWidget(searchInput);
809808

809+
auto regexCheckBox = new QCheckBox(widget);
810+
regexCheckBox->setText(tr("Regex Search"));
811+
layout->addWidget(regexCheckBox);
812+
810813
searchInput->setPlaceholderText(i18n("Search..."));
811814
searchInput->setToolTip(i18n("<qt>Search the flame graph for a symbol.</qt>"));
812815
searchInput->setClearButtonEnabled(true);
813-
connect(searchInput, &QLineEdit::textChanged, this, &FlameGraph::setSearchValue);
814-
connect(this, &FlameGraph::uiResetRequested, this, [this, searchInput] {
816+
connect(searchInput, &QLineEdit::textChanged, this,
817+
[this](const QString& value) { this->setSearchValue(value, m_useRegex); });
818+
auto applyRegexCheckBox = [this](bool checked) { this->setSearchValue(m_search, checked); };
819+
#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
820+
connect(regexCheckBox, &QCheckBox::stateChanged, this, applyRegexCheckBox);
821+
#else
822+
connect(regexCheckBox, &QCheckBox::checkStateChanged, this, applyRegexCheckBox);
823+
#endif
824+
connect(this, &FlameGraph::uiResetRequested, this, [this, searchInput, regexCheckBox] {
815825
m_search.clear();
826+
m_useRegex = false;
816827
searchInput->clear();
828+
regexCheckBox->setChecked(false);
817829
});
818830
},
819831
this);
@@ -1142,7 +1154,7 @@ void FlameGraph::setData(FrameGraphicsItem* rootItem)
11421154
m_scene->addItem(rootItem);
11431155

11441156
if (!m_search.isEmpty()) {
1145-
setSearchValue(m_search);
1157+
setSearchValue(m_search, m_useRegex);
11461158
}
11471159
if (!m_hoveredStacks.isEmpty()) {
11481160
hoverStacks(rootItem, m_hoveredStacks);
@@ -1201,15 +1213,16 @@ void FlameGraph::selectItem(FrameGraphicsItem* item)
12011213
setTooltipItem(item);
12021214
}
12031215

1204-
void FlameGraph::setSearchValue(const QString& value)
1216+
void FlameGraph::setSearchValue(const QString& value, bool useRegex)
12051217
{
12061218
if (!m_rootItem) {
12071219
return;
12081220
}
12091221

12101222
m_search = value;
1211-
1212-
auto match = applySearch(m_rootItem, value);
1223+
m_useRegex = useRegex;
1224+
auto regex = useRegex ? value : QRegularExpression::escape(value);
1225+
auto match = applySearch(m_rootItem, QRegularExpression(regex));
12131226

12141227
if (value.isEmpty()) {
12151228
m_searchResultsLabel->hide();

src/flamegraph.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class FlameGraph : public QWidget
4545

4646
private slots:
4747
void setData(FrameGraphicsItem* rootItem);
48-
void setSearchValue(const QString& value);
48+
void setSearchValue(const QString& value, bool useRegex);
4949
void navigateBack();
5050
void navigateForward();
5151

@@ -88,6 +88,7 @@ private slots:
8888
bool m_collapseRecursion = false;
8989
bool m_buildingScene = false;
9090
QString m_search;
91+
bool m_useRegex = false;
9192
// cost threshold in percent, items below that value will not be shown
9293
static const constexpr double DEFAULT_COST_THRESHOLD = 0.1;
9394
double m_costThreshold = DEFAULT_COST_THRESHOLD;

src/recordpage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ RecordPage::RecordPage(QWidget* parent)
415415
m_recordHost->setPids(pids);
416416
});
417417

418-
ResultsUtil::connectFilter(ui->processesFilterBox, m_processProxyModel);
418+
ResultsUtil::connectFilter(ui->processesFilterBox, m_processProxyModel, ui->regexCheckBox);
419419

420420
connect(m_watcher, &QFutureWatcher<ProcDataList>::finished, this, &RecordPage::updateProcessesFinished);
421421

src/recordpage.ui

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,6 @@
144144
<property name="text">
145145
<string>Process Filter:</string>
146146
</property>
147-
<property name="buddy">
148-
<cstring>processesFilterBox</cstring>
149-
</property>
150-
</widget>
151-
</item>
152-
<item row="0" column="1">
153-
<widget class="QLineEdit" name="processesFilterBox">
154-
<property name="toolTip">
155-
<string>Filter the process list by process name or process ID</string>
156-
</property>
157147
</widget>
158148
</item>
159149
<item row="1" column="0">
@@ -185,6 +175,38 @@
185175
</property>
186176
</widget>
187177
</item>
178+
<item row="0" column="1">
179+
<widget class="QWidget" name="widget_2" native="true">
180+
<layout class="QHBoxLayout" name="horizontalLayout_4">
181+
<property name="leftMargin">
182+
<number>0</number>
183+
</property>
184+
<property name="topMargin">
185+
<number>0</number>
186+
</property>
187+
<property name="rightMargin">
188+
<number>0</number>
189+
</property>
190+
<property name="bottomMargin">
191+
<number>0</number>
192+
</property>
193+
<item>
194+
<widget class="QLineEdit" name="processesFilterBox">
195+
<property name="toolTip">
196+
<string>Filter the process list by process name or process ID</string>
197+
</property>
198+
</widget>
199+
</item>
200+
<item>
201+
<widget class="QCheckBox" name="regexCheckBox">
202+
<property name="text">
203+
<string>Regex Search</string>
204+
</property>
205+
</widget>
206+
</item>
207+
</layout>
208+
</widget>
209+
</item>
188210
</layout>
189211
</widget>
190212
</item>

src/resultsbottomuppage.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ ResultsBottomUpPage::ResultsBottomUpPage(FilterAndZoomStack* filterStack, PerfPa
6161
ui->setupUi(this);
6262

6363
auto bottomUpCostModel = new BottomUpModel(this);
64-
ResultsUtil::setupTreeView(ui->bottomUpTreeView, contextMenu, ui->bottomUpSearch, bottomUpCostModel);
64+
ResultsUtil::setupTreeView(ui->bottomUpTreeView, contextMenu, ui->bottomUpSearch, ui->regexCheckBox,
65+
bottomUpCostModel);
6566
ResultsUtil::setupCostDelegate(bottomUpCostModel, ui->bottomUpTreeView);
6667
ResultsUtil::setupContextMenu(ui->bottomUpTreeView, contextMenu, bottomUpCostModel, filterStack, this);
6768

src/resultsbottomuppage.ui

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@
7171
</property>
7272
</widget>
7373
</item>
74+
<item>
75+
<widget class="QCheckBox" name="regexCheckBox">
76+
<property name="text">
77+
<string>Regex Search</string>
78+
</property>
79+
</widget>
80+
</item>
7481
</layout>
7582
</widget>
7683
</item>

src/resultscallercalleepage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ ResultsCallerCalleePage::ResultsCallerCalleePage(FilterAndZoomStack* filterStack
8484
m_callerCalleeProxy = new CallerCalleeProxy<CallerCalleeModel>(this);
8585
m_callerCalleeProxy->setSourceModel(m_callerCalleeCostModel);
8686
m_callerCalleeProxy->setSortRole(CallerCalleeModel::SortRole);
87-
ResultsUtil::connectFilter(ui->callerCalleeFilter, m_callerCalleeProxy);
87+
ResultsUtil::connectFilter(ui->callerCalleeFilter, m_callerCalleeProxy, ui->regexCheckBox);
8888
ui->callerCalleeTableView->setSortingEnabled(true);
8989
ui->callerCalleeTableView->setModel(m_callerCalleeProxy);
9090
ResultsUtil::setupContextMenu(ui->callerCalleeTableView, contextMenu, m_callerCalleeCostModel, filterStack, this,

src/resultscallercalleepage.ui

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@
7171
</property>
7272
</widget>
7373
</item>
74+
<item>
75+
<widget class="QCheckBox" name="regexCheckBox">
76+
<property name="text">
77+
<string>Regex Search</string>
78+
</property>
79+
</widget>
80+
</item>
7481
</layout>
7582
</widget>
7683
</item>

src/resultstopdownpage.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ ResultsTopDownPage::ResultsTopDownPage(FilterAndZoomStack* filterStack, PerfPars
2222
ui->setupUi(this);
2323

2424
auto topDownCostModel = new TopDownModel(this);
25-
ResultsUtil::setupTreeView(ui->topDownTreeView, contextMenu, ui->topDownSearch, topDownCostModel);
25+
ResultsUtil::setupTreeView(ui->topDownTreeView, contextMenu, ui->topDownSearch, ui->regexCheckBox,
26+
topDownCostModel);
2627
ResultsUtil::setupCostDelegate(topDownCostModel, ui->topDownTreeView);
2728
ResultsUtil::setupContextMenu(ui->topDownTreeView, contextMenu, topDownCostModel, filterStack, this);
2829

src/resultstopdownpage.ui

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@
7171
</property>
7272
</widget>
7373
</item>
74+
<item>
75+
<widget class="QCheckBox" name="regexCheckBox">
76+
<property name="text">
77+
<string>Regex Search</string>
78+
</property>
79+
</widget>
80+
</item>
7481
</layout>
7582
</widget>
7683
</item>

0 commit comments

Comments
 (0)