Debugger: Save and restore CLI history

This commit is contained in:
Vicki Pfau 2022-02-20 03:49:59 -08:00
parent a966511e1e
commit 4ae540b387
6 changed files with 86 additions and 7 deletions

View File

@ -44,6 +44,7 @@ Other fixes:
- VFS: Failed file mapping should return NULL on POSIX
Misc:
- Core: Suspend runloop when a core crashes
- Debugger: Save and restore CLI history
- GB Video: Add default SGB border
- GBA: Automatically skip BIOS if ROM has invalid logo
- GBA DMA: Enhanced logging (closes mgba.io/i/2454)

View File

@ -5,7 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cli-el-backend.h"
#include <mgba/core/config.h>
#include <mgba/core/version.h>
#include <mgba-util/vfs.h>
#include <signal.h>
@ -60,12 +62,47 @@ void _CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) {
HistEvent ev;
history(elbe->histate, &ev, H_SETSIZE, 200);
el_set(elbe->elstate, EL_HIST, history, elbe->histate);
char path[PATH_MAX + 1];
mCoreConfigDirectory(path, PATH_MAX);
if (path[0]) {
strncat(path, PATH_SEP, PATH_MAX);
strncat(path, "cli_history.log", PATH_MAX);
struct VFile* vf = VFileOpen(path, O_RDONLY);
if (vf) {
char line[512];
while (vf->readline(vf, line, sizeof(line)) > 0) {
history(elbe->histate, &ev, H_ENTER, line);
}
vf->close(vf);
}
}
_activeDebugger = be->p;
signal(SIGINT, _breakIntoDefault);
}
void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be;
char path[PATH_MAX + 1];
mCoreConfigDirectory(path, PATH_MAX);
if (path[0]) {
strncat(path, PATH_SEP, PATH_MAX);
strncat(path, "cli_history.log", PATH_MAX);
struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
if (vf) {
HistEvent ev = {0};
if (history(elbe->histate, &ev, H_FIRST) >= 0) {
do {
if (!ev.str || ev.str[0] == '\n') {
continue;
}
vf->write(vf, ev.str, strlen(ev.str));
} while (history(elbe->histate, &ev, H_NEXT) >= 0);
}
vf->close(vf);
}
}
history_end(elbe->histate);
el_end(elbe->elstate);
free(elbe);

View File

@ -26,6 +26,8 @@ DebuggerConsole::DebuggerConsole(DebuggerConsoleController* controller, QWidget*
connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log);
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::attach);
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::breakInto);
controller->historyLoad();
}
void DebuggerConsole::log(const QString& line) {
@ -41,7 +43,6 @@ void DebuggerConsole::postLine() {
if (line.isEmpty()) {
m_consoleController->enterLine(QString("\n"));
} else {
m_history.append(line);
m_historyOffset = 0;
log(QString("> %1\n").arg(line));
m_consoleController->enterLine(line);
@ -52,7 +53,8 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
if (event->type() != QEvent::KeyPress) {
return false;
}
if (m_history.isEmpty()) {
QStringList history = m_consoleController->history();
if (history.isEmpty()) {
return false;
}
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
@ -64,7 +66,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
--m_historyOffset;
break;
case Qt::Key_Up:
if (m_historyOffset >= m_history.size()) {
if (m_historyOffset >= history.size()) {
return false;
}
++m_historyOffset;
@ -73,7 +75,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
m_historyOffset = 0;
break;
case Qt::Key_Home:
m_historyOffset = m_history.size();
m_historyOffset = history.size();
break;
default:
return false;
@ -81,7 +83,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
if (m_historyOffset == 0) {
m_ui.prompt->clear();
} else {
m_ui.prompt->setText(m_history[m_history.size() - m_historyOffset]);
m_ui.prompt->setText(history[history.size() - m_historyOffset]);
}
return true;
}

View File

@ -26,7 +26,6 @@ protected:
private:
Ui::DebuggerConsole m_ui;
QStringList m_history;
int m_historyOffset;
DebuggerConsoleController* m_consoleController;

View File

@ -5,7 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DebuggerConsoleController.h"
#include "ConfigController.h"
#include "CoreController.h"
#include "LogController.h"
#include <QMutexLocker>
#include <QThread>
@ -50,12 +52,12 @@ void DebuggerConsoleController::detach() {
}
}
DebuggerController::detach();
historySave();
}
void DebuggerConsoleController::attachInternal() {
CoreController::Interrupter interrupter(m_gameController);
QMutexLocker lock(&m_mutex);
m_history.clear();
mCore* core = m_gameController->thread()->core;
CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d);
CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core));
@ -129,3 +131,37 @@ void DebuggerConsoleController::historyAppend(struct CLIDebuggerBackend* be, con
QMutexLocker lock(&self->m_mutex);
self->m_history.append(QString::fromUtf8(line));
}
void DebuggerConsoleController::historyLoad() {
QFile log(ConfigController::configDir() + "/cli_history.log");
QStringList history;
if (!log.open(QIODevice::ReadOnly | QIODevice::Text)) {
return;
}
while (true) {
QByteArray line = log.readLine();
if (line.isEmpty()) {
break;
}
if (line.endsWith("\r\n")) {
line.chop(2);
} else if (line.endsWith("\n")) {
line.chop(1);
}
history.append(QString::fromUtf8(line));
}
QMutexLocker lock(&m_mutex);
m_history = history;
}
void DebuggerConsoleController::historySave() {
QFile log(ConfigController::configDir() + "/cli_history.log");
if (!log.open(QIODevice::WriteOnly | QIODevice::Text)) {
LOG(QT, WARN) << tr("Could not open CLI history for writing");
return;
}
for (const QString& line : m_history) {
log.write(line.toUtf8());
log.write("\n");
}
}

View File

@ -23,6 +23,8 @@ Q_OBJECT
public:
DebuggerConsoleController(QObject* parent = nullptr);
QStringList history() const { return m_history; }
signals:
void log(const QString&);
void lineAppend(const QString&);
@ -30,6 +32,8 @@ signals:
public slots:
void enterLine(const QString&);
virtual void detach() override;
void historyLoad();
void historySave();
protected:
virtual void attachInternal() override;