Skip to content

Commit 577045e

Browse files
feat(acp): rank command popup results by prefix match
Substring matches were previously hidden entirely; now they appear below exact-prefix matches instead of being discarded. - Introduce appendCommandItem() to eliminate duplicated label/data build logic across showCommandPopup and filterCommandPopup - Rebuild the list on each filter pass (two-pass: starts-with tier then contains tier) so ordering reflects match quality rather than relying on setHidden which couldn't express rank - Empty prefix skips the second pass, preserving original order for the unfiltered state
1 parent c602d34 commit 577045e

2 files changed

Lines changed: 27 additions & 15 deletions

File tree

src/widgets/AcpSessionView.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,11 +2062,7 @@ void AcpSessionView::showCommandPopup()
20622062

20632063
m_commandPopup->clear();
20642064
for (const auto &cmd : cmds) {
2065-
QString label = QStringLiteral("/") + cmd.name;
2066-
if (!cmd.description.isEmpty())
2067-
label += QStringLiteral(" ") + cmd.description;
2068-
auto *item = new QListWidgetItem(label, m_commandPopup);
2069-
item->setData(Qt::UserRole, cmd.name);
2065+
appendCommandItem(cmd);
20702066
}
20712067
m_commandPopup->setCurrentRow(0);
20722068
m_commandPopup->show();
@@ -2114,24 +2110,39 @@ void AcpSessionView::filterCommandPopup()
21142110
showCommandPopup();
21152111
}
21162112

2117-
int firstVisible = -1;
2118-
for (int i = 0; i < m_commandPopup->count(); ++i) {
2119-
auto *item = m_commandPopup->item(i);
2120-
const QString name = item->data(Qt::UserRole).toString();
2121-
const bool match = prefix.isEmpty() || name.toLower().startsWith(prefix);
2122-
item->setHidden(!match);
2123-
if (match && firstVisible < 0) firstVisible = i;
2113+
// Rank: names that START WITH the typed prefix come first, names that only
2114+
// CONTAIN it as a substring come after. Original order is preserved within
2115+
// each tier. Empty prefix puts everything in the starts-with tier (no-op
2116+
// reorder), matching the unfiltered popup.
2117+
m_commandPopup->clear();
2118+
for (const auto &cmd : cmds) {
2119+
if (prefix.isEmpty() || cmd.name.toLower().startsWith(prefix))
2120+
appendCommandItem(cmd);
2121+
}
2122+
for (const auto &cmd : cmds) {
2123+
const QString lower = cmd.name.toLower();
2124+
if (!prefix.isEmpty() && !lower.startsWith(prefix) && lower.contains(prefix))
2125+
appendCommandItem(cmd);
21242126
}
21252127

2126-
if (firstVisible < 0) {
2128+
if (m_commandPopup->count() == 0) {
21272129
hideCommandPopup();
21282130
} else {
2129-
if (m_commandPopup->currentItem() && m_commandPopup->currentItem()->isHidden())
2130-
m_commandPopup->setCurrentRow(firstVisible);
2131+
m_commandPopup->setCurrentRow(0);
21312132
resizeCommandPopup();
21322133
}
21332134
}
21342135

2136+
void AcpSessionView::appendCommandItem(const AcpProtocol::AcpCommandInfo &cmd)
2137+
{
2138+
if (!m_commandPopup) return;
2139+
QString label = QStringLiteral("/") + cmd.name;
2140+
if (!cmd.description.isEmpty())
2141+
label += QStringLiteral(" ") + cmd.description;
2142+
auto *item = new QListWidgetItem(label, m_commandPopup);
2143+
item->setData(Qt::UserRole, cmd.name);
2144+
}
2145+
21352146
void AcpSessionView::acceptCommandCompletion()
21362147
{
21372148
if (!m_commandPopup || !m_commandPopup->isVisible()) return;

src/widgets/AcpSessionView.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ private slots:
210210
void resizeCommandPopup();
211211
void filterCommandPopup();
212212
void acceptCommandCompletion();
213+
void appendCommandItem(const AcpProtocol::AcpCommandInfo &cmd);
213214

214215
AcpSessionModel *m_model = nullptr; // non-owning
215216
AcpConnection *m_connection = nullptr; // non-owning

0 commit comments

Comments
 (0)