Add basic variable name completion

This commit is contained in:
Eelco Dolstra 2013-09-06 19:51:59 +02:00
parent cf4c29d90a
commit 0abdf4beaa

View file

@ -29,9 +29,15 @@ struct NixRepl
StaticEnv staticEnv; StaticEnv staticEnv;
Env * env; Env * env;
int displ; int displ;
StringSet varNames;
StringSet completions;
StringSet::iterator curCompletion;
NixRepl(); NixRepl();
void mainLoop(const Strings & args); void mainLoop(const Strings & args);
void completePrefix(string prefix);
bool getLine(string & line);
void processLine(string line); void processLine(string line);
void loadFile(const Path & path); void loadFile(const Path & path);
void addAttrsToScope(Value & attrs); void addAttrsToScope(Value & attrs);
@ -47,48 +53,6 @@ void printHelp()
} }
/* Apparently, the only way to get readline() to return on Ctrl-C
(SIGINT) is to use siglongjmp(). That's fucked up... */
static sigjmp_buf sigintJmpBuf;
static void sigintHandler(int signo)
{
siglongjmp(sigintJmpBuf, 1);
}
bool getLine(string & line)
{
struct sigaction act, old;
act.sa_handler = sigintHandler;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGINT, &act, &old))
throw SysError("installing handler for SIGINT");
if (sigsetjmp(sigintJmpBuf, 1))
line = "";
else {
char * s = readline("nix-repl> ");
if (!s) return false;
line = chomp(string(s));
free(s);
if (line != "") {
add_history(line.c_str());
append_history(1, 0);
}
}
_isInterrupted = 0;
if (sigaction(SIGINT, &old, 0))
throw SysError("restoring handler for SIGINT");
return true;
}
string removeWhitespace(string s) string removeWhitespace(string s)
{ {
s = chomp(s); s = chomp(s);
@ -143,6 +107,86 @@ void NixRepl::mainLoop(const Strings & args)
} }
/* Apparently, the only way to get readline() to return on Ctrl-C
(SIGINT) is to use siglongjmp(). That's fucked up... */
static sigjmp_buf sigintJmpBuf;
static void sigintHandler(int signo)
{
siglongjmp(sigintJmpBuf, 1);
}
/* Oh, if only g++ had nested functions... */
NixRepl * curRepl;
char * completerThunk(const char * s, int state)
{
string prefix(s);
/* If the prefix has a slash in it, use readline's builtin filename
completer. */
if (prefix.find('/') != string::npos)
return rl_filename_completion_function(s, state);
/* Otherwise, return all symbols that start with the prefix. */
if (state == 0) {
curRepl->completePrefix(s);
curRepl->curCompletion = curRepl->completions.begin();
}
if (curRepl->curCompletion == curRepl->completions.end()) return 0;
return strdup((curRepl->curCompletion++)->c_str());
}
bool NixRepl::getLine(string & line)
{
struct sigaction act, old;
act.sa_handler = sigintHandler;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGINT, &act, &old))
throw SysError("installing handler for SIGINT");
if (sigsetjmp(sigintJmpBuf, 1))
line = "";
else {
curRepl = this;
rl_completion_entry_function = completerThunk;
char * s = readline("nix-repl> ");
if (!s) return false;
line = chomp(string(s));
free(s);
if (line != "") {
add_history(line.c_str());
append_history(1, 0);
}
}
_isInterrupted = 0;
if (sigaction(SIGINT, &old, 0))
throw SysError("restoring handler for SIGINT");
return true;
}
void NixRepl::completePrefix(string prefix)
{
completions.clear();
StringSet::iterator i = varNames.lower_bound(prefix);
while (i != varNames.end()) {
if (string(*i, 0, prefix.size()) != prefix) break;
completions.insert(*i);
i++;
}
}
void NixRepl::processLine(string line) void NixRepl::processLine(string line)
{ {
if (line == "") return; if (line == "") return;
@ -227,6 +271,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v)
{ {
staticEnv.vars[name] = displ; staticEnv.vars[name] = displ;
env->values[displ++] = v; env->values[displ++] = v;
varNames.insert((string) name);
} }