mirror of https://github.com/mgba-emu/mgba.git
Debugger: Save and restore CLI history
This commit is contained in:
parent
a966511e1e
commit
4ae540b387
1
CHANGES
1
CHANGES
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ protected:
|
|||
|
||||
private:
|
||||
Ui::DebuggerConsole m_ui;
|
||||
QStringList m_history;
|
||||
int m_historyOffset;
|
||||
|
||||
DebuggerConsoleController* m_consoleController;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue