Add optional readline support to the text debugger console.

Make text/graphical console selectable with an option to configure.

svn-id: r42787
This commit is contained in:
Willem Jan Palenstijn 2009-07-25 23:36:24 +00:00
parent 037c02a1f7
commit 45cde5f642
3 changed files with 142 additions and 24 deletions

View file

@ -27,10 +27,14 @@
#include "common/system.h"
#include "gui/debugger.h"
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
#include "gui/console.h"
#elif defined(USE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#endif
namespace GUI {
Debugger::Debugger() {
@ -39,7 +43,7 @@ Debugger::Debugger() {
_isAttached = false;
_errStr = NULL;
_firstTime = true;
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
_debuggerDialog = new GUI::ConsoleDialog(1.0f, 0.67f);
_debuggerDialog->setInputCallback(debuggerInputCallback, this);
_debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this);
@ -57,7 +61,7 @@ Debugger::Debugger() {
}
Debugger::~Debugger() {
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
delete _debuggerDialog;
#endif
}
@ -69,7 +73,7 @@ int Debugger::DebugPrintf(const char *format, ...) {
va_start(argptr, format);
int count;
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
count = _debuggerDialog->vprintf(format, argptr);
#else
count = ::vprintf(format, argptr);
@ -116,9 +120,21 @@ void Debugger::onFrame() {
}
}
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
static Debugger* g_readline_debugger;
char * readline_completionFunction (const char *text, int state)
{
return g_readline_debugger->readlineComplete(text, state);
}
#endif
// Main Debugger Loop
void Debugger::enter() {
#if USE_CONSOLE
// TODO: Having three I/O methods #ifdef-ed in this file is not the
// cleanest approach to this...
#ifndef USE_TEXT_CONSOLE
if (_firstTime) {
DebugPrintf("Debugger started, type 'exit' to return to the game.\n");
DebugPrintf("Type 'help' to see a little list of commands and variables.\n");
@ -133,18 +149,28 @@ void Debugger::enter() {
_debuggerDialog->runModal();
#else
// TODO: compared to the console input, this here is very bare bone.
// For example, no support for tab completion and no history. At least
// we should re-add (optional) support for the readline library.
// Or maybe instead of choosing between a console dialog and stdio,
// we should move that choice into the ConsoleDialog class - that is,
// the console dialog code could be #ifdef'ed to not print to the dialog
// but rather to stdio. This way, we could also reuse the command history
// and tab completion of the console. It would still require a lot of
// work, but at least no dependency on a 3rd party library...
printf("Debugger entered, please switch to this console for input.\n");
#ifdef USE_READLINE
// TODO: add support for saving/loading history?
g_readline_debugger = this;
rl_completion_entry_function = &readline_completionFunction;
char *line_read = 0;
do {
free(line_read);
line_read = readline("debug> ");
if (line_read && line_read[0])
add_history(line_read);
} while (line_read && parseCommand(line_read));
free(line_read);
line_read = 0;
#else
int i;
char buf[256];
@ -160,6 +186,7 @@ void Debugger::enter() {
if (i == 0)
continue;
} while (parseCommand(buf));
#endif
#endif
}
@ -330,6 +357,30 @@ bool Debugger::tabComplete(const char *input, Common::String &completion) const
return true;
}
#if defined(USE_TEXT_CONSOLE) && defined(USE_READLINE)
char* Debugger::readlineComplete(const char *input, int state)
{
static CommandsMap::const_iterator iter;
// We assume that _cmds isn't changed between calls to readlineComplete,
// unless state is 0.
if (state == 0) {
iter = _cmds.begin();
} else {
++iter;
}
for (; iter != _cmds.end(); ++iter) {
if (iter->_key.hasPrefix(input)) {
char *ret = (char *)malloc(iter->_key.size() + 1);
strcpy(ret, iter->_key.c_str());
return ret;
}
}
return 0;
}
#endif
// Variable registration function
void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) {
// TODO: Filter out duplicates
@ -361,9 +412,13 @@ bool Debugger::Cmd_Exit(int argc, const char **argv) {
// Print a list of all registered commands (and variables, if any),
// nicely word-wrapped.
bool Debugger::Cmd_Help(int argc, const char **argv) {
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
const int charsPerLine = _debuggerDialog->getCharsPerLine();
#elif defined(USE_READLINE)
int charsPerLine, rows;
rl_get_screen_size(&rows, &charsPerLine);
#else
// Can we do better?
const int charsPerLine = 80;
#endif
int width, size;
@ -460,7 +515,7 @@ bool Debugger::Cmd_DebugFlagDisable(int argc, const char **argv) {
}
// Console handler
#if USE_CONSOLE
#ifndef USE_TEXT_CONSOLE
bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) {
Debugger *debugger = (Debugger *)refCon;