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
|
- VFS: Failed file mapping should return NULL on POSIX
|
||||||
Misc:
|
Misc:
|
||||||
- Core: Suspend runloop when a core crashes
|
- Core: Suspend runloop when a core crashes
|
||||||
|
- Debugger: Save and restore CLI history
|
||||||
- GB Video: Add default SGB border
|
- GB Video: Add default SGB border
|
||||||
- GBA: Automatically skip BIOS if ROM has invalid logo
|
- GBA: Automatically skip BIOS if ROM has invalid logo
|
||||||
- GBA DMA: Enhanced logging (closes mgba.io/i/2454)
|
- 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include "cli-el-backend.h"
|
#include "cli-el-backend.h"
|
||||||
|
|
||||||
|
#include <mgba/core/config.h>
|
||||||
#include <mgba/core/version.h>
|
#include <mgba/core/version.h>
|
||||||
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
@ -60,12 +62,47 @@ void _CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) {
|
||||||
HistEvent ev;
|
HistEvent ev;
|
||||||
history(elbe->histate, &ev, H_SETSIZE, 200);
|
history(elbe->histate, &ev, H_SETSIZE, 200);
|
||||||
el_set(elbe->elstate, EL_HIST, history, elbe->histate);
|
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;
|
_activeDebugger = be->p;
|
||||||
signal(SIGINT, _breakIntoDefault);
|
signal(SIGINT, _breakIntoDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
|
void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
|
||||||
struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) 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);
|
history_end(elbe->histate);
|
||||||
el_end(elbe->elstate);
|
el_end(elbe->elstate);
|
||||||
free(elbe);
|
free(elbe);
|
||||||
|
|
|
@ -26,6 +26,8 @@ DebuggerConsole::DebuggerConsole(DebuggerConsoleController* controller, QWidget*
|
||||||
connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log);
|
connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log);
|
||||||
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::attach);
|
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::attach);
|
||||||
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::breakInto);
|
connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::breakInto);
|
||||||
|
|
||||||
|
controller->historyLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerConsole::log(const QString& line) {
|
void DebuggerConsole::log(const QString& line) {
|
||||||
|
@ -41,7 +43,6 @@ void DebuggerConsole::postLine() {
|
||||||
if (line.isEmpty()) {
|
if (line.isEmpty()) {
|
||||||
m_consoleController->enterLine(QString("\n"));
|
m_consoleController->enterLine(QString("\n"));
|
||||||
} else {
|
} else {
|
||||||
m_history.append(line);
|
|
||||||
m_historyOffset = 0;
|
m_historyOffset = 0;
|
||||||
log(QString("> %1\n").arg(line));
|
log(QString("> %1\n").arg(line));
|
||||||
m_consoleController->enterLine(line);
|
m_consoleController->enterLine(line);
|
||||||
|
@ -52,7 +53,8 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
|
||||||
if (event->type() != QEvent::KeyPress) {
|
if (event->type() != QEvent::KeyPress) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_history.isEmpty()) {
|
QStringList history = m_consoleController->history();
|
||||||
|
if (history.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||||
|
@ -64,7 +66,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
|
||||||
--m_historyOffset;
|
--m_historyOffset;
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Up:
|
case Qt::Key_Up:
|
||||||
if (m_historyOffset >= m_history.size()) {
|
if (m_historyOffset >= history.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
++m_historyOffset;
|
++m_historyOffset;
|
||||||
|
@ -73,7 +75,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
|
||||||
m_historyOffset = 0;
|
m_historyOffset = 0;
|
||||||
break;
|
break;
|
||||||
case Qt::Key_Home:
|
case Qt::Key_Home:
|
||||||
m_historyOffset = m_history.size();
|
m_historyOffset = history.size();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -81,7 +83,7 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
|
||||||
if (m_historyOffset == 0) {
|
if (m_historyOffset == 0) {
|
||||||
m_ui.prompt->clear();
|
m_ui.prompt->clear();
|
||||||
} else {
|
} else {
|
||||||
m_ui.prompt->setText(m_history[m_history.size() - m_historyOffset]);
|
m_ui.prompt->setText(history[history.size() - m_historyOffset]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::DebuggerConsole m_ui;
|
Ui::DebuggerConsole m_ui;
|
||||||
QStringList m_history;
|
|
||||||
int m_historyOffset;
|
int m_historyOffset;
|
||||||
|
|
||||||
DebuggerConsoleController* m_consoleController;
|
DebuggerConsoleController* m_consoleController;
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include "DebuggerConsoleController.h"
|
#include "DebuggerConsoleController.h"
|
||||||
|
|
||||||
|
#include "ConfigController.h"
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
|
#include "LogController.h"
|
||||||
|
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
@ -50,12 +52,12 @@ void DebuggerConsoleController::detach() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DebuggerController::detach();
|
DebuggerController::detach();
|
||||||
|
historySave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerConsoleController::attachInternal() {
|
void DebuggerConsoleController::attachInternal() {
|
||||||
CoreController::Interrupter interrupter(m_gameController);
|
CoreController::Interrupter interrupter(m_gameController);
|
||||||
QMutexLocker lock(&m_mutex);
|
QMutexLocker lock(&m_mutex);
|
||||||
m_history.clear();
|
|
||||||
mCore* core = m_gameController->thread()->core;
|
mCore* core = m_gameController->thread()->core;
|
||||||
CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d);
|
CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d);
|
||||||
CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core));
|
CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core));
|
||||||
|
@ -129,3 +131,37 @@ void DebuggerConsoleController::historyAppend(struct CLIDebuggerBackend* be, con
|
||||||
QMutexLocker lock(&self->m_mutex);
|
QMutexLocker lock(&self->m_mutex);
|
||||||
self->m_history.append(QString::fromUtf8(line));
|
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:
|
public:
|
||||||
DebuggerConsoleController(QObject* parent = nullptr);
|
DebuggerConsoleController(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
QStringList history() const { return m_history; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void log(const QString&);
|
void log(const QString&);
|
||||||
void lineAppend(const QString&);
|
void lineAppend(const QString&);
|
||||||
|
@ -30,6 +32,8 @@ signals:
|
||||||
public slots:
|
public slots:
|
||||||
void enterLine(const QString&);
|
void enterLine(const QString&);
|
||||||
virtual void detach() override;
|
virtual void detach() override;
|
||||||
|
void historyLoad();
|
||||||
|
void historySave();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void attachInternal() override;
|
virtual void attachInternal() override;
|
||||||
|
|
Loading…
Reference in New Issue