Skip to content

Commit 86f3570

Browse files
committed
Add equate autocomplete to disassembly view's goto dialog
1 parent 32f6f59 commit 86f3570

File tree

5 files changed

+78
-6
lines changed

5 files changed

+78
-6
lines changed

gui/qt/debugger.cpp

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <QtWidgets/QToolTip>
2828
#include <QtCore/QFileInfo>
29+
#include <QtCore/QStringList>
2930
#include <QtCore/QRegularExpression>
3031
#include <QtWidgets/QMessageBox>
3132
#include <QtWidgets/QInputDialog>
@@ -40,6 +41,7 @@
4041
#include <QtGui/QWindow>
4142
#include <QtGui/QScreen>
4243
#include <algorithm>
44+
#include <ranges>
4345

4446
#ifdef _MSC_VER
4547
#include <direct.h>
@@ -184,6 +186,7 @@ void MainWindow::debugImportFile(const QString &file) {
184186

185187
disasm.map.clear();
186188
disasm.reverse.clear();
189+
markDisasmGotoCompletionsDirty();
187190
for (QString &equFile : m_equateFiles) {
188191
equatesAddFile(equFile);
189192
}
@@ -1820,6 +1823,7 @@ void MainWindow::updateLabels() {
18201823
void MainWindow::equatesRefresh() {
18211824
disasm.map.clear();
18221825
disasm.reverse.clear();
1826+
markDisasmGotoCompletionsDirty();
18231827
for (QString &file : m_equateFiles) {
18241828
equatesAddFile(file);
18251829
}
@@ -1917,11 +1921,14 @@ void MainWindow::equatesAddEquate(const QString &name, uint32_t address) {
19171921
if (!equatesAddEquateInternal(name, address)) {
19181922
return;
19191923
}
1924+
markDisasmGotoCompletionsDirty();
19201925
uint8_t *ptr = static_cast<uint8_t *>(phys_mem_ptr(address - 4, 9));
19211926
if (ptr && ptr[4] == 0xC3 && (ptr[0] == 0xC3 || ptr[8] == 0xC3)) { // jump table?
19221927
uint32_t address2 = ptr[5] | ptr[6] << 8 | ptr[7] << 16;
19231928
if (phys_mem_ptr(address2, 1)) {
1924-
equatesAddEquateInternal(QStringLiteral("_") + name, address2);
1929+
if (equatesAddEquateInternal(QStringLiteral("_") + name, address2)) {
1930+
markDisasmGotoCompletionsDirty();
1931+
}
19251932
}
19261933
}
19271934
}
@@ -2081,14 +2088,15 @@ void MainWindow::gotoPressed() {
20812088
m_gotoAddr = m_disasm->getSelectedAddr();
20822089
}
20832090

2084-
GotoDialog dlg(m_gotoAddr, m_disasmGotoHistory, this);
2091+
GotoDialog dlg(m_gotoAddr, m_disasmGotoHistory, disasmGotoCompletions(), this);
20852092
if (dlg.exec() == QDialog::Accepted) {
20862093
QString typed = dlg.text().trimmed();
20872094
bool ok = false;
20882095
QString resolved = resolveAddressOrEquate(typed, &ok);
20892096
if (ok) {
20902097
m_gotoAddr = typed;
2091-
disasmUpdateAddr(hex2int(resolved), false);
2098+
// changes are routed through here to make sure history is updated for fwd and back
2099+
gotoDisasmAddr(static_cast<uint32_t>(hex2int(resolved)));
20922100

20932101
auto &hist = m_disasmGotoHistory;
20942102
std::erase_if(hist, [&](const QString &s){ return s.compare(typed, Qt::CaseInsensitive) == 0; });
@@ -2159,6 +2167,44 @@ QAction *MainWindow::gotoMemAction(QMenu *menu, bool vat) const {
21592167
return gotoMem;
21602168
}
21612169

2170+
const QStringList &MainWindow::disasmGotoCompletions() {
2171+
if (!m_disasmGotoCompletionsDirty) {
2172+
return m_disasmGotoCompletions;
2173+
}
2174+
2175+
m_disasmGotoCompletionsDirty = false;
2176+
2177+
QStringList completions;
2178+
static constexpr std::array kRegisterAliases {
2179+
"AF", "HL", "DE", "BC", "IX", "IY",
2180+
"AF'", "HL'", "DE'", "BC'", "SPL", "SPS", "PC"
2181+
};
2182+
2183+
completions.reserve(static_cast<int>(disasm.reverse.size() + kRegisterAliases.size()));
2184+
2185+
for (const auto &name : disasm.reverse | std::views::keys) {
2186+
completions.append(QString::fromStdString(name));
2187+
}
2188+
2189+
for (const char *alias : kRegisterAliases) {
2190+
const QLatin1String aliasStr(alias);
2191+
if (!completions.contains(aliasStr)) {
2192+
completions.append(QString::fromLatin1(alias));
2193+
}
2194+
}
2195+
2196+
std::ranges::sort(completions, [](const QString &lhs, const QString &rhs) {
2197+
return lhs.localeAwareCompare(rhs) < 0;
2198+
});
2199+
2200+
m_disasmGotoCompletions = std::move(completions);
2201+
return m_disasmGotoCompletions;
2202+
}
2203+
2204+
void MainWindow::markDisasmGotoCompletionsDirty() {
2205+
m_disasmGotoCompletionsDirty = true;
2206+
}
2207+
21622208
void MainWindow::handleCtrlClickText(QPlainTextEdit *edit) {
21632209
if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) {
21642210
bool ok = true;

gui/qt/gotodialog.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#include "gotodialog.h"
22

33
#include <QtWidgets/QComboBox>
4+
#include <QtWidgets/QCompleter>
45
#include <QtWidgets/QDialogButtonBox>
56
#include <QtWidgets/QLabel>
67
#include <QtWidgets/QVBoxLayout>
78
#include <QtWidgets/QSizePolicy>
9+
#include <QtWidgets/QLineEdit>
10+
#include <QtCore/Qt>
811

912
GotoDialog::GotoDialog(const QString &seed,
1013
const std::vector<QString> &history,
14+
const QStringList &completions,
1115
QWidget *parent)
1216
: QDialog(parent) {
1317
setWindowTitle(tr("Goto"));
@@ -18,6 +22,19 @@ GotoDialog::GotoDialog(const QString &seed,
1822

1923
m_combo = new QComboBox(this); // NOLINT: Qt parent-ownership handles deletion
2024
m_combo->setEditable(true);
25+
m_combo->setInsertPolicy(QComboBox::NoInsert);
26+
27+
if (!completions.isEmpty()) {
28+
auto *completer = new QCompleter(completions, m_combo); // NOLINT: Qt parent-ownership handles deletion
29+
completer->setCaseSensitivity(Qt::CaseInsensitive);
30+
completer->setFilterMode(Qt::MatchContains);
31+
completer->setCompletionMode(QCompleter::PopupCompletion);
32+
if (auto *lineEdit = m_combo->lineEdit()) {
33+
lineEdit->setCompleter(completer);
34+
} else {
35+
m_combo->setCompleter(completer);
36+
}
37+
}
2138

2239
for (const QString &h : history) {
2340
m_combo->addItem(h);

gui/qt/gotodialog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <QtWidgets/QDialog>
55
#include <QtCore/QString>
6+
#include <QtCore/QStringList>
67
#include <vector>
78

89
QT_BEGIN_NAMESPACE
@@ -14,6 +15,7 @@ class GotoDialog : public QDialog {
1415
public:
1516
explicit GotoDialog(const QString &seed,
1617
const std::vector<QString> &history,
18+
const QStringList &completions = {},
1719
QWidget *parent = nullptr);
1820

1921
[[nodiscard]] QString text() const;

gui/qt/mainwindow.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <QtWidgets/QTableWidgetItem>
2424
#include <QtWidgets/QPlainTextEdit>
2525
#include <QtWidgets/QFileDialog>
26+
#include <QtCore/QStringList>
2627
#include <QtCore/QSettings>
2728
#include <QtCore/QThread>
2829
#include <QtCore/QTimer>
@@ -366,6 +367,8 @@ private slots:
366367
void gotoMemAddr(uint32_t addr);
367368
HexWidget *gotoMemAddrNoRaise(uint32_t addr);
368369
QAction *gotoMemAction(QMenu *menu, bool vat = false) const;
370+
const QStringList &disasmGotoCompletions();
371+
void markDisasmGotoCompletionsDirty();
369372

370373
void handleCtrlClickText(QPlainTextEdit *edit);
371374
void handleCtrlClickLine(QLineEdit *edit);
@@ -736,6 +739,9 @@ private slots:
736739

737740
std::vector<QString> m_memGotoHistory;
738741

742+
QStringList m_disasmGotoCompletions;
743+
bool m_disasmGotoCompletionsDirty = true;
744+
739745
QString m_pathConfig;
740746
QMenu *m_menuDocks;
741747
QMenu *m_menuDebug;

gui/qt/memorywidget.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <QtGui/QClipboard>
1212
#include <QtCore/QFileInfo>
1313
#include <QtCore/QRegularExpression>
14+
#include <QtCore/QStringList>
1415
#include <QtWidgets/QMessageBox>
1516
#include <QtWidgets/QInputDialog>
1617
#include <algorithm>
@@ -107,7 +108,7 @@ void MainWindow::memUpdateEdit(HexWidget *edit, bool force) {
107108
}
108109

109110
void MainWindow::flashGotoPressed() {
110-
if (GotoDialog dlg(m_flashGotoAddr, m_memGotoHistory, this); dlg.exec() == QDialog::Accepted) {
111+
if (GotoDialog dlg(m_flashGotoAddr, m_memGotoHistory, QStringList(), this); dlg.exec() == QDialog::Accepted) {
111112
const QString typed = dlg.text().trimmed();
112113
bool ok = false;
113114
const QString resolved = resolveAddressOrEquate(typed, &ok);
@@ -127,7 +128,7 @@ void MainWindow::flashGotoPressed() {
127128
}
128129

129130
void MainWindow::ramGotoPressed() {
130-
GotoDialog dlg(m_RamGotoAddr, m_memGotoHistory, this);
131+
GotoDialog dlg(m_RamGotoAddr, m_memGotoHistory, QStringList(), this);
131132
if (dlg.exec() == QDialog::Accepted) {
132133
const QString typed = dlg.text().trimmed();
133134
bool ok = false;
@@ -216,7 +217,7 @@ void MainWindow::memGotoEdit(HexWidget *edit) {
216217
return;
217218
}
218219

219-
GotoDialog dlg(m_memGotoAddr, m_memGotoHistory, this);
220+
GotoDialog dlg(m_memGotoAddr, m_memGotoHistory, QStringList(), this);
220221
if (dlg.exec() == QDialog::Accepted) {
221222
QString typed = dlg.text().trimmed();
222223
bool ok = false;

0 commit comments

Comments
 (0)