editline: wip

This commit is contained in:
Will Dietz 2018-10-29 08:44:58 -05:00
parent f90a67e24d
commit 3d974d31fa
13 changed files with 89 additions and 4648 deletions

View file

@ -1,8 +1,12 @@
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <setjmp.h>
#include <editline.h>
#include "shared.hh"
#include "eval.hh"
#include "eval-inline.hh"
@ -15,8 +19,6 @@
#include "command.hh"
#include "finally.hh"
#include "src/linenoise/linenoise.h"
namespace nix {
#define ESC_RED "\033[31m"
@ -118,17 +120,53 @@ NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store)
NixRepl::~NixRepl()
{
linenoiseHistorySave(historyFile.c_str());
write_history(historyFile.c_str());
}
static NixRepl * curRepl; // ugly
static void completionCallback(const char * s, linenoiseCompletions *lc)
{
/* Otherwise, return all symbols that start with the prefix. */
for (auto & c : curRepl->completePrefix(s))
linenoiseAddCompletion(lc, c.c_str());
static char * completionCallback(char * s, int *match) {
auto possible = curRepl->completePrefix(s);
if (possible.size() == 1) {
*match = 1;
auto *res = strdup(possible.begin()->c_str() + strlen(s));
if (!res) throw Error("allocation failure");
return res;
}
*match = 0;
return nullptr;
}
static int listPossibleCallback(char *s, char ***avp) {
auto possible = curRepl->completePrefix(s);
if (possible.size() > (INT_MAX / sizeof(char*)))
throw Error("too many completions");
int ac = 0;
char **vp = nullptr;
auto check = [&](auto *p) {
if (!p) {
if (vp) {
while (--ac >= 0)
free(vp[ac]);
free(vp);
}
throw Error("allocation failure");
}
return p;
};
vp = check((char **)malloc(possible.size() * sizeof(char*)));
for (auto & p : possible)
vp[ac++] = check(strdup(p.c_str()));
*avp = vp;
return ac;
}
@ -143,12 +181,16 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
reloadFiles();
if (!loadedFiles.empty()) std::cout << std::endl;
// Allow nix-repl specific settings in .inputrc
rl_readline_name = "nix-repl";
createDirs(dirOf(historyFile));
linenoiseHistorySetMaxLen(1000);
linenoiseHistoryLoad(historyFile.c_str());
el_hist_size = 1000;
read_history(historyFile.c_str());
// rl_initialize();
// linenoiseSetCompletionCallback(completionCallback);
curRepl = this;
linenoiseSetCompletionCallback(completionCallback);
rl_set_complete_func(completionCallback);
rl_set_list_possib_func(listPossibleCallback);
std::string input;
@ -174,12 +216,6 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
}
if (input.size() > 0) {
// Remove trailing newline before adding to history
input.erase(input.size() - 1);
linenoiseHistoryAdd(input.c_str());
}
// We handled the current input fully, so we should clear it
// and read brand new input.
input.clear();
@ -190,19 +226,10 @@ void NixRepl::mainLoop(const std::vector<std::string> & files)
bool NixRepl::getLine(string & input, const std::string &prompt)
{
char * s = linenoise(prompt.c_str());
char * s = readline(prompt.c_str());
Finally doFree([&]() { free(s); });
if (!s) {
switch (auto type = linenoiseKeyType()) {
case 1: // ctrl-C
input = "";
return true;
case 2: // ctrl-D
return false;
default:
throw Error(format("Unexpected linenoise keytype: %1%") % type);
}
}
if (!s)
return false;
input += s;
input += '\n';
return true;