mirror of https://github.com/stella-emu/stella.git
Tab completion in the PromptWidget is now working again. As well,
the completion now includes functions (built-in and user-defined). Cleaned up some more of the debugger documentation, mostly related to tab completion. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1992 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
72b2ddd89b
commit
964415508d
|
@ -53,7 +53,7 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
|
||||||
<li><strike>Symbolic names in disassembly.</strike> <b>Note:</b> Disabled until a future release</li>
|
<li><strike>Symbolic names in disassembly.</strike> <b>Note:</b> Disabled until a future release</li>
|
||||||
|
|
||||||
<li>Symbolic names accepted as input.</li>
|
<li>Symbolic names accepted as input.</li>
|
||||||
<li>Tab completion for commands and symbol names.</li>
|
<li>Tab completion for commands, symbol names and functions.</li>
|
||||||
<li>Graphical editor for RIOT and extended RAM. Acts a lot like a spreadsheet.
|
<li>Graphical editor for RIOT and extended RAM. Acts a lot like a spreadsheet.
|
||||||
Input in hex, with displays for label/decimal/binary for
|
Input in hex, with displays for label/decimal/binary for
|
||||||
currently-selected location.</li>
|
currently-selected location.</li>
|
||||||
|
@ -186,7 +186,7 @@ Bash-style commands are also supported:</p>
|
||||||
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
|
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
|
||||||
|
|
||||||
<p>To see the available commands, enter "help". Bash-style tab completion is
|
<p>To see the available commands, enter "help". Bash-style tab completion is
|
||||||
supported for commands and labels (see below).</p>
|
supported for commands, labels and functions (see below).</p>
|
||||||
|
|
||||||
<p>For now, there are some functions that only exist in the prompt. We
|
<p>For now, there are some functions that only exist in the prompt. We
|
||||||
intend to add GUI equivalents for all (or almost all?) of the prompt
|
intend to add GUI equivalents for all (or almost all?) of the prompt
|
||||||
|
@ -196,7 +196,7 @@ debugger without typing (or without typing much, anyway).</p>
|
||||||
|
|
||||||
<h4>Tab completion</h4>
|
<h4>Tab completion</h4>
|
||||||
|
|
||||||
<p>While entering a command or label, you can type a partial name and
|
<p>While entering a command, label or function, you can type a partial name and
|
||||||
press the Tab key to attempt to auto-complete it. If you've ever used
|
press the Tab key to attempt to auto-complete it. If you've ever used
|
||||||
"bash", this will be immediately familiar. If not, try it: load up
|
"bash", this will be immediately familiar. If not, try it: load up
|
||||||
a ROM, go to the debugger, type "print w" (but don't press Enter),
|
a ROM, go to the debugger, type "print w" (but don't press Enter),
|
||||||
|
@ -206,9 +206,9 @@ completions (try with "v" instead of "w"), you'll see a list of them,
|
||||||
and your partial name will be completed as far as possible.</p>
|
and your partial name will be completed as far as possible.</p>
|
||||||
|
|
||||||
<p>Tab completion works on all labels: built-in, loaded from a symbol file,
|
<p>Tab completion works on all labels: built-in, loaded from a symbol file,
|
||||||
or set during debugging with the "define" command. However, it does not
|
or set during debugging with the "define" command. It also works with
|
||||||
yet work on functions defined with the "function" command, nor does it
|
built-in functions and those defined with the "function" command,
|
||||||
work on filenames.</p>
|
but it doesn't (yet) work on filenames.</p>
|
||||||
|
|
||||||
<h4>Expressions</h4>
|
<h4>Expressions</h4>
|
||||||
|
|
||||||
|
|
|
@ -463,48 +463,27 @@ string CartDebug::loadSymbolFile(const string& f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int CartDebug::countCompletions(const char *in)
|
void CartDebug::getCompletions(const char* in, StringList& completions) const
|
||||||
{
|
{
|
||||||
/* FIXME
|
// First scan system equates
|
||||||
myCompletions = myCompPrefix = "";
|
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||||
return countCompletions(in, mySystemAddresses) +
|
if(BSPF_strncasecmp(ourTIAMnemonicR[addr], in, strlen(in)) == 0)
|
||||||
countCompletions(in, myUserAddresses);
|
completions.push_back(ourTIAMnemonicR[addr]);
|
||||||
*/
|
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||||
return 0;
|
if(BSPF_strncasecmp(ourTIAMnemonicW[addr], in, strlen(in)) == 0)
|
||||||
}
|
completions.push_back(ourTIAMnemonicW[addr]);
|
||||||
|
for(uInt16 addr = 0; addr <= 0x297-0x280; ++addr)
|
||||||
|
if(BSPF_strncasecmp(ourIOMnemonic[addr], in, strlen(in)) == 0)
|
||||||
|
completions.push_back(ourIOMnemonic[addr]);
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Now scan user-defined labels
|
||||||
int CartDebug::countCompletions(const char *in, LabelToAddr& addresses)
|
LabelToAddr::const_iterator iter;
|
||||||
{
|
for(iter = myUserAddresses.begin(); iter != myUserAddresses.end(); ++iter)
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
LabelToAddr::iterator iter;
|
|
||||||
for(iter = addresses.begin(); iter != addresses.end(); iter++)
|
|
||||||
{
|
{
|
||||||
const char *l = iter->first.c_str();
|
const char* l = iter->first.c_str();
|
||||||
|
|
||||||
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
|
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
|
||||||
{
|
completions.push_back(l);
|
||||||
if(myCompPrefix == "")
|
|
||||||
myCompPrefix += l;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int nonMatch = 0;
|
|
||||||
const char *c = myCompPrefix.c_str();
|
|
||||||
while(*c != '\0' && tolower(*c) == tolower(l[nonMatch]))
|
|
||||||
{
|
|
||||||
c++;
|
|
||||||
nonMatch++;
|
|
||||||
}
|
|
||||||
myCompPrefix.erase(nonMatch, myCompPrefix.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count++) myCompletions += " ";
|
|
||||||
myCompletions += l;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -26,6 +26,7 @@ class System;
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Array.hxx"
|
#include "Array.hxx"
|
||||||
#include "Cart.hxx"
|
#include "Cart.hxx"
|
||||||
|
#include "StringList.hxx"
|
||||||
#include "DebuggerSystem.hxx"
|
#include "DebuggerSystem.hxx"
|
||||||
|
|
||||||
// pointer types for CartDebug instance methods
|
// pointer types for CartDebug instance methods
|
||||||
|
@ -150,7 +151,6 @@ class CartDebug : public DebuggerSystem
|
||||||
*/
|
*/
|
||||||
string getCartType();
|
string getCartType();
|
||||||
|
|
||||||
////////////////////////////////////////
|
|
||||||
/**
|
/**
|
||||||
Add a label and associated address.
|
Add a label and associated address.
|
||||||
Labels that reference either TIA or RIOT spaces will not be processed.
|
Labels that reference either TIA or RIOT spaces will not be processed.
|
||||||
|
@ -183,11 +183,9 @@ class CartDebug : public DebuggerSystem
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Methods used by the command parser for tab-completion
|
Methods used by the command parser for tab-completion
|
||||||
|
In this case, return completions from the equate list(s)
|
||||||
*/
|
*/
|
||||||
int countCompletions(const char *in);
|
void getCompletions(const char* in, StringList& list) const;
|
||||||
const string& getCompletions() const { return myCompletions; }
|
|
||||||
const string& getCompletionPrefix() const { return myCompPrefix; }
|
|
||||||
////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef map<uInt16, string> AddrToLabel;
|
typedef map<uInt16, string> AddrToLabel;
|
||||||
|
@ -210,9 +208,6 @@ class CartDebug : public DebuggerSystem
|
||||||
string extractLabel(char *c) const;
|
string extractLabel(char *c) const;
|
||||||
int extractValue(char *c) const;
|
int extractValue(char *c) const;
|
||||||
|
|
||||||
// Count completions for the given mapping
|
|
||||||
int countCompletions(const char *in, LabelToAddr& addresses);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CartState myState;
|
CartState myState;
|
||||||
CartState myOldState;
|
CartState myOldState;
|
||||||
|
@ -242,9 +237,8 @@ class CartDebug : public DebuggerSystem
|
||||||
// handled differently
|
// handled differently
|
||||||
LabelToAddr mySystemAddresses;
|
LabelToAddr mySystemAddresses;
|
||||||
|
|
||||||
string myCompletions;
|
// Holds address at which the most recent read from a write port
|
||||||
string myCompPrefix;
|
// occurred
|
||||||
|
|
||||||
uInt16 myRWPortAddress;
|
uInt16 myRWPortAddress;
|
||||||
|
|
||||||
/// Table of instruction mnemonics
|
/// Table of instruction mnemonics
|
||||||
|
|
|
@ -234,86 +234,6 @@ void Debugger::quit()
|
||||||
myOSystem->eventHandler().leaveDebugMode();
|
myOSystem->eventHandler().leaveDebugMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // FIXME - remove this
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Debugger::loadListFile(string f)
|
|
||||||
{
|
|
||||||
char buffer[255];
|
|
||||||
|
|
||||||
if(f == "")
|
|
||||||
{
|
|
||||||
f = myOSystem->romFile();
|
|
||||||
|
|
||||||
string::size_type pos;
|
|
||||||
if( (pos = f.find_last_of('.')) != string::npos )
|
|
||||||
f.replace(pos, f.size(), ".lst");
|
|
||||||
else
|
|
||||||
f += ".lst";
|
|
||||||
}
|
|
||||||
|
|
||||||
ifstream in(f.c_str());
|
|
||||||
if(!in.is_open())
|
|
||||||
return "Unable to read listing from " + f;
|
|
||||||
|
|
||||||
sourceLines.clear();
|
|
||||||
int count = 0;
|
|
||||||
while( !in.eof() )
|
|
||||||
{
|
|
||||||
if(!in.getline(buffer, 255))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(strlen(buffer) >= 14 &&
|
|
||||||
buffer[0] == ' ' &&
|
|
||||||
buffer[7] == ' ' &&
|
|
||||||
buffer[8] == ' ' &&
|
|
||||||
isxdigit(buffer[9]) &&
|
|
||||||
isxdigit(buffer[12]) &&
|
|
||||||
BSPF_isblank(buffer[13]))
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
char addr[5];
|
|
||||||
for(int i=0; i<4; i++)
|
|
||||||
addr[i] = buffer[9+i];
|
|
||||||
|
|
||||||
for(char *c = buffer; *c != '\0'; c++)
|
|
||||||
if(*c == '\t') *c = ' ';
|
|
||||||
|
|
||||||
addr[4] = '\0';
|
|
||||||
string a = addr;
|
|
||||||
string b = buffer;
|
|
||||||
sourceLines.insert(make_pair(a, b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
|
|
||||||
return valueToString(count) + " lines loaded from " + f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string Debugger::getSourceLines(int addr) const
|
|
||||||
{
|
|
||||||
if(sourceLines.size() == 0)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
string ret;
|
|
||||||
string want = to_hex_16(addr);
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
pair<ListIter, ListIter> lines = sourceLines.equal_range(want);
|
|
||||||
for(ListIter i = lines.first; i != lines.second; i++)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
ret += i->second;
|
|
||||||
ret += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found)
|
|
||||||
return ret;
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::autoExec()
|
void Debugger::autoExec()
|
||||||
{
|
{
|
||||||
|
@ -831,6 +751,28 @@ const string Debugger::builtinHelp() const
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Debugger::getCompletions(const char* in, StringList& list) const
|
||||||
|
{
|
||||||
|
// First check built-in functions
|
||||||
|
FunctionMap::const_iterator iter1;
|
||||||
|
for(iter1 = functions.begin(); iter1 != functions.end(); ++iter1)
|
||||||
|
{
|
||||||
|
const char* l = iter1->first.c_str();
|
||||||
|
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
|
||||||
|
list.push_back(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now consider user-defined functions
|
||||||
|
FunctionDefMap::const_iterator iter2;
|
||||||
|
for(iter2 = functionDefs.begin(); iter2 != functionDefs.end(); ++iter2)
|
||||||
|
{
|
||||||
|
const char* l = iter2->first.c_str();
|
||||||
|
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
|
||||||
|
list.push_back(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool Debugger::saveROM(const string& filename) const
|
bool Debugger::saveROM(const string& filename) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -129,6 +129,12 @@ class Debugger : public DialogContainer
|
||||||
const FunctionDefMap getFunctionDefMap() const;
|
const FunctionDefMap getFunctionDefMap() const;
|
||||||
const string builtinHelp() const;
|
const string builtinHelp() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Methods used by the command parser for tab-completion
|
||||||
|
In this case, return completions from the function list
|
||||||
|
*/
|
||||||
|
void getCompletions(const char* in, StringList& list) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The debugger subsystem responsible for all CPU state
|
The debugger subsystem responsible for all CPU state
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -157,50 +157,17 @@ string DebuggerParser::exec(const string& file, bool verbose)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// completion-related stuff:
|
// Completion-related stuff:
|
||||||
int DebuggerParser::countCompletions(const char *in)
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void DebuggerParser::getCompletions(const char* in, StringList& completions) const
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
completions = compPrefix = "";
|
|
||||||
|
|
||||||
// cerr << "Attempting to complete \"" << in << "\"" << endl;
|
// cerr << "Attempting to complete \"" << in << "\"" << endl;
|
||||||
for(int i = 0; i < kNumCommands; ++i)
|
for(int i = 0; i < kNumCommands; ++i)
|
||||||
{
|
{
|
||||||
const char *l = commands[i].cmdString.c_str();
|
const char* l = commands[i].cmdString.c_str();
|
||||||
|
if(BSPF_strncasecmp(l, in, strlen(in)) == 0)
|
||||||
if(BSPF_strncasecmp(l, in, strlen(in)) == 0) {
|
completions.push_back(l);
|
||||||
if(compPrefix == "")
|
|
||||||
compPrefix += l;
|
|
||||||
else {
|
|
||||||
int nonMatch = 0;
|
|
||||||
const char *c = compPrefix.c_str();
|
|
||||||
while(*c != '\0' && tolower(*c) == tolower(l[nonMatch])) {
|
|
||||||
c++;
|
|
||||||
nonMatch++;
|
|
||||||
}
|
|
||||||
compPrefix.erase(nonMatch, compPrefix.length());
|
|
||||||
// cerr << "compPrefix==" << compPrefix << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count++) completions += " ";
|
|
||||||
completions += l;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cerr << "Found " << count << " label(s):" << endl << completions << endl;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
const char *DebuggerParser::getCompletions()
|
|
||||||
{
|
|
||||||
return completions.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
const char *DebuggerParser::getCompletionPrefix()
|
|
||||||
{
|
|
||||||
return compPrefix.c_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -48,9 +48,7 @@ class DebuggerParser
|
||||||
|
|
||||||
/** Given a substring, determine matching substrings from the list
|
/** Given a substring, determine matching substrings from the list
|
||||||
of available commands. Used in the debugger prompt for tab-completion */
|
of available commands. Used in the debugger prompt for tab-completion */
|
||||||
int countCompletions(const char *in);
|
void getCompletions(const char* in, StringList& list) const;
|
||||||
const char *getCompletions();
|
|
||||||
const char *getCompletionPrefix();
|
|
||||||
|
|
||||||
/** Evaluate the given expression using operators, current base, etc */
|
/** Evaluate the given expression using operators, current base, etc */
|
||||||
int decipher_arg(const string &str);
|
int decipher_arg(const string &str);
|
||||||
|
@ -131,10 +129,6 @@ class DebuggerParser
|
||||||
BaseFormat defaultBase;
|
BaseFormat defaultBase;
|
||||||
StringList watches;
|
StringList watches;
|
||||||
|
|
||||||
// Used in 'tab-completion', holds list of commands related to a substring
|
|
||||||
string completions;
|
|
||||||
string compPrefix;
|
|
||||||
|
|
||||||
// List of available command methods
|
// List of available command methods
|
||||||
void executeA();
|
void executeA();
|
||||||
void executeBank();
|
void executeBank();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "Debugger.hxx"
|
#include "Debugger.hxx"
|
||||||
#include "DebuggerDialog.hxx"
|
#include "DebuggerDialog.hxx"
|
||||||
#include "DebuggerParser.hxx"
|
#include "DebuggerParser.hxx"
|
||||||
|
#include "StringList.hxx"
|
||||||
|
|
||||||
#include "PromptWidget.hxx"
|
#include "PromptWidget.hxx"
|
||||||
#include "CartDebug.hxx"
|
#include "CartDebug.hxx"
|
||||||
|
@ -220,7 +221,7 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
||||||
int lastDelimPos = -1;
|
int lastDelimPos = -1;
|
||||||
char delimiter = '\0';
|
char delimiter = '\0';
|
||||||
|
|
||||||
char *str = new char[len + 1];
|
char str[len + 1];
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
str[i] = buffer(_promptStartPos + i) & 0x7f;
|
str[i] = buffer(_promptStartPos + i) & 0x7f;
|
||||||
|
@ -232,46 +233,50 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
||||||
}
|
}
|
||||||
str[len] = '\0';
|
str[len] = '\0';
|
||||||
|
|
||||||
const char *completionList;
|
StringList list;
|
||||||
const char *prefix;
|
string completionList;
|
||||||
int possibilities;
|
string prefix;
|
||||||
|
|
||||||
if(lastDelimPos < 0)
|
if(lastDelimPos < 0)
|
||||||
{
|
{
|
||||||
// no delimiters, do command completion:
|
// no delimiters, do command completion:
|
||||||
DebuggerParser& parser = instance().debugger().parser();
|
const DebuggerParser& parser = instance().debugger().parser();
|
||||||
possibilities = parser.countCompletions(str);
|
parser.getCompletions(str, list);
|
||||||
|
|
||||||
if(possibilities < 1) {
|
if(list.size() < 1)
|
||||||
delete[] str;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
completionList = parser.getCompletions();
|
// TODO: sort completions (add sort method to StringList)
|
||||||
prefix = parser.getCompletionPrefix();
|
completionList = list[0];
|
||||||
|
for(uInt32 i = 1; i < list.size(); ++i)
|
||||||
|
completionList += " " + list[i];
|
||||||
|
prefix = getCompletionPrefix(list, str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we got a delimiter, so this must be a label:
|
// we got a delimiter, so this must be a label or a function
|
||||||
CartDebug& cart = instance().debugger().cartDebug();
|
const Debugger& dbg = instance().debugger();
|
||||||
possibilities = cart.countCompletions(str + lastDelimPos + 1);
|
|
||||||
|
|
||||||
if(possibilities < 1) {
|
dbg.cartDebug().getCompletions(str + lastDelimPos + 1, list);
|
||||||
delete[] str;
|
dbg.getCompletions(str + lastDelimPos + 1, list);
|
||||||
|
|
||||||
|
if(list.size() < 1)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - perhaps use strings instead of char pointers
|
// TODO: sort completions (add sort method to StringList)
|
||||||
completionList = cart.getCompletions().c_str();
|
completionList = list[0];
|
||||||
prefix = cart.getCompletionPrefix().c_str();
|
for(uInt32 i = 1; i < list.size(); ++i)
|
||||||
|
completionList += " " + list[i];
|
||||||
|
prefix = getCompletionPrefix(list, str + lastDelimPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(possibilities == 1)
|
if(list.size() == 1)
|
||||||
{
|
{
|
||||||
// add to buffer as though user typed it (plus a space)
|
// add to buffer as though user typed it (plus a space)
|
||||||
_currentPos = _promptStartPos + lastDelimPos + 1;
|
_currentPos = _promptStartPos + lastDelimPos + 1;
|
||||||
while(*completionList != '\0')
|
const char* clptr = completionList.c_str();
|
||||||
putcharIntern(*completionList++);
|
while(*clptr != '\0')
|
||||||
|
putcharIntern(*clptr++);
|
||||||
|
|
||||||
putcharIntern(' ');
|
putcharIntern(' ');
|
||||||
_promptEndPos = _currentPos;
|
_promptEndPos = _currentPos;
|
||||||
|
@ -298,7 +303,6 @@ bool PromptWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
||||||
print(prefix);
|
print(prefix);
|
||||||
_promptEndPos = _currentPos;
|
_promptEndPos = _currentPos;
|
||||||
}
|
}
|
||||||
delete[] str;
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -883,3 +887,30 @@ bool PromptWidget::saveBuffer(string& filename)
|
||||||
out.close();
|
out.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string PromptWidget::getCompletionPrefix(const StringList& completions, string prefix)
|
||||||
|
{
|
||||||
|
// Search for prefix in every string, progressively growing it
|
||||||
|
// Once a mismatch is found or length is past one of the strings, we're done
|
||||||
|
// We *could* use the longest common string algorithm, but for the lengths
|
||||||
|
// of the strings we're dealing with, it's probably not worth it
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
for(uInt32 i = 0; i < completions.size(); ++i)
|
||||||
|
{
|
||||||
|
const string& s = completions[i];
|
||||||
|
if(s.length() < prefix.length())
|
||||||
|
return prefix; // current prefix is the best we're going to get
|
||||||
|
else if(s.compare(0, prefix.length(), prefix) != 0)
|
||||||
|
{
|
||||||
|
prefix.erase(prefix.length()-1);
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(completions[0].length() > prefix.length())
|
||||||
|
prefix = completions[0].substr(0, prefix.length() + 1);
|
||||||
|
else
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -79,6 +79,10 @@ class PromptWidget : public Widget, public CommandSender
|
||||||
|
|
||||||
void loadConfig();
|
void loadConfig();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Get the longest prefix (initially 's') that is in every string in the list
|
||||||
|
string getCompletionPrefix(const StringList& completions, string s);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
kBufferSize = 32768,
|
kBufferSize = 32768,
|
||||||
|
|
Loading…
Reference in New Issue