aboutsummaryrefslogtreecommitdiff
path: root/src/nix/repl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix/repl.cc')
-rw-r--r--src/nix/repl.cc107
1 files changed, 76 insertions, 31 deletions
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 77898c632..ff8477865 100644
--- a/src/nix/repl.cc
+++ b/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;