Merge branch 'feature/editline-pr' of https://github.com/dtzWill/nix
This commit is contained in:
commit
6c6bbeb439
13 changed files with 107 additions and 4648 deletions
107
src/nix/repl.cc
107
src/nix/repl.cc
|
|
@ -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,71 @@ 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;
|
||||
} else if (possible.size() > 1) {
|
||||
auto checkAllHaveSameAt = [&](size_t pos) {
|
||||
auto &first = *possible.begin();
|
||||
for (auto &p : possible) {
|
||||
if (p.size() <= pos || p[pos] != first[pos])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
size_t start = strlen(s);
|
||||
size_t len = 0;
|
||||
while (checkAllHaveSameAt(start + len)) ++len;
|
||||
if (len > 0) {
|
||||
*match = 1;
|
||||
auto *res = strdup(std::string(*possible.begin(), start, len).c_str());
|
||||
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 +199,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 +234,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 +244,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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue