Replace readline by linenoise
Using linenoise avoids a license compatibility issue (#1356), is a lot smaller and doesn't pull in ncurses.
This commit is contained in:
parent
82a9c93c7f
commit
c5f23f10a8
|
@ -196,14 +196,6 @@ if test "$gc" = yes; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Check for readline, needed by "nix repl".
|
|
||||||
AX_LIB_READLINE
|
|
||||||
if test "$ax_cv_lib_readline" != "no"; then
|
|
||||||
have_readline=1
|
|
||||||
fi
|
|
||||||
AC_SUBST(HAVE_READLINE, [$have_readline])
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
|
AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
|
||||||
[do not initialise DB etc. in `make install']),
|
[do not initialise DB etc. in `make install']),
|
||||||
init_state=$enableval, init_state=yes)
|
init_state=$enableval, init_state=yes)
|
||||||
|
|
|
@ -261,6 +261,12 @@ xlink:href="http://nixos.org/">NixOS homepage</link>.</para>
|
||||||
xlink:href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU
|
xlink:href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">GNU
|
||||||
LGPLv2.1 or (at your option) any later version</link>.</para>
|
LGPLv2.1 or (at your option) any later version</link>.</para>
|
||||||
|
|
||||||
|
<para>Nix uses the <link
|
||||||
|
xlink:href="https://github.com/antirez/linenoise">linenoise
|
||||||
|
library</link>, which has the following license:</para>
|
||||||
|
|
||||||
|
<programlisting><xi:include href="../../../src/linenoise/LICENSE" parse="text" /></programlisting>
|
||||||
|
|
||||||
</simplesect>
|
</simplesect>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,9 @@ Requires: curl
|
||||||
Requires: bzip2
|
Requires: bzip2
|
||||||
Requires: gzip
|
Requires: gzip
|
||||||
Requires: xz
|
Requires: xz
|
||||||
Requires: readline
|
|
||||||
BuildRequires: bzip2-devel
|
BuildRequires: bzip2-devel
|
||||||
BuildRequires: sqlite-devel
|
BuildRequires: sqlite-devel
|
||||||
BuildRequires: libcurl-devel
|
BuildRequires: libcurl-devel
|
||||||
BuildRequires: readline-devel
|
|
||||||
|
|
||||||
# Hack to make that shitty RPM scanning hack shut up.
|
# Hack to make that shitty RPM scanning hack shut up.
|
||||||
Provides: perl(Nix::SSH)
|
Provides: perl(Nix::SSH)
|
||||||
|
|
22
release.nix
22
release.nix
|
@ -73,7 +73,7 @@ let
|
||||||
buildInputs =
|
buildInputs =
|
||||||
[ curl
|
[ curl
|
||||||
bzip2 xz brotli
|
bzip2 xz brotli
|
||||||
openssl pkgconfig sqlite boehmgc readline
|
openssl pkgconfig sqlite boehmgc
|
||||||
|
|
||||||
]
|
]
|
||||||
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
++ lib.optional (stdenv.isLinux || stdenv.isDarwin) libsodium
|
||||||
|
@ -198,15 +198,15 @@ let
|
||||||
rpm_fedora25x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora25x86_64) [ "libsodium-devel" ];
|
rpm_fedora25x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora25x86_64) [ "libsodium-devel" ];
|
||||||
|
|
||||||
|
|
||||||
deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ] [ "libsodium13" "libreadline6" ];
|
deb_debian8i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.debian8i386) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||||
deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ] [ "libsodium13" "libreadline6" ];
|
deb_debian8x86_64 = makeDeb_x86_64 (diskImageFunsFun: diskImageFunsFun.debian8x86_64) [ "libsodium-dev" ] [ "libsodium13" ];
|
||||||
|
|
||||||
deb_ubuntu1410i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1410i386) [] [ "libreadline6" ];
|
deb_ubuntu1410i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1410i386) [] [];
|
||||||
deb_ubuntu1410x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1410x86_64) [] [ "libreadline6" ];
|
deb_ubuntu1410x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1410x86_64) [] [];
|
||||||
deb_ubuntu1604i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1604i386) [ "libsodium-dev" ] [ "libsodium18" "libreadline6" ];
|
deb_ubuntu1604i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1604i386) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||||
deb_ubuntu1604x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1604x86_64) [ "libsodium-dev" ] [ "libsodium18" "libreadline6" ];
|
deb_ubuntu1604x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1604x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||||
deb_ubuntu1610i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1610i386) [ "libsodium-dev" ] [ "libsodium18" "libreadline7" ];
|
deb_ubuntu1610i386 = makeDeb_i686 (diskImageFuns: diskImageFuns.ubuntu1610i386) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||||
deb_ubuntu1610x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1610x86_64) [ "libsodium-dev" ] [ "libsodium18" "libreadline7" ];
|
deb_ubuntu1610x86_64 = makeDeb_x86_64 (diskImageFuns: diskImageFuns.ubuntu1610x86_64) [ "libsodium-dev" ] [ "libsodium18" ];
|
||||||
|
|
||||||
|
|
||||||
# System tests.
|
# System tests.
|
||||||
|
@ -299,7 +299,7 @@ let
|
||||||
src = jobs.tarball;
|
src = jobs.tarball;
|
||||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||||
{ extraPackages =
|
{ extraPackages =
|
||||||
[ "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "libcurl-devel" "openssl-devel" "xz-devel" "readline-devel" ]
|
[ "sqlite" "sqlite-devel" "bzip2-devel" "emacs" "libcurl-devel" "openssl-devel" "xz-devel" ]
|
||||||
++ extraPackages; };
|
++ extraPackages; };
|
||||||
memSize = 1024;
|
memSize = 1024;
|
||||||
meta.schedulingPriority = 50;
|
meta.schedulingPriority = 50;
|
||||||
|
@ -321,7 +321,7 @@ let
|
||||||
src = jobs.tarball;
|
src = jobs.tarball;
|
||||||
diskImage = (diskImageFun vmTools.diskImageFuns)
|
diskImage = (diskImageFun vmTools.diskImageFuns)
|
||||||
{ extraPackages =
|
{ extraPackages =
|
||||||
[ "libsqlite3-dev" "libbz2-dev" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" "libreadline-dev" ]
|
[ "libsqlite3-dev" "libbz2-dev" "libcurl-dev" "libcurl3-nss" "libssl-dev" "liblzma-dev" ]
|
||||||
++ extraPackages; };
|
++ extraPackages; };
|
||||||
memSize = 1024;
|
memSize = 1024;
|
||||||
meta.schedulingPriority = 50;
|
meta.schedulingPriority = 50;
|
||||||
|
|
|
@ -16,7 +16,6 @@ with import <nixpkgs> {};
|
||||||
customMemoryManagement = false;
|
customMemoryManagement = false;
|
||||||
})
|
})
|
||||||
autoreconfHook
|
autoreconfHook
|
||||||
readline
|
|
||||||
|
|
||||||
# For nix-perl
|
# For nix-perl
|
||||||
perl
|
perl
|
||||||
|
|
25
src/linenoise/LICENSE
Normal file
25
src/linenoise/LICENSE
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1199
src/linenoise/linenoise.c
Normal file
1199
src/linenoise/linenoise.c
Normal file
File diff suppressed because it is too large
Load diff
73
src/linenoise/linenoise.h
Normal file
73
src/linenoise/linenoise.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/* linenoise.h -- VERSION 1.0
|
||||||
|
*
|
||||||
|
* Guerrilla line editing library against the idea that a line editing lib
|
||||||
|
* needs to be 20,000 lines of C code.
|
||||||
|
*
|
||||||
|
* See linenoise.c for more information.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
* Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINENOISE_H
|
||||||
|
#define __LINENOISE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct linenoiseCompletions {
|
||||||
|
size_t len;
|
||||||
|
char **cvec;
|
||||||
|
} linenoiseCompletions;
|
||||||
|
|
||||||
|
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||||
|
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
|
||||||
|
typedef void(linenoiseFreeHintsCallback)(void *);
|
||||||
|
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||||
|
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
|
||||||
|
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
|
||||||
|
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
|
||||||
|
|
||||||
|
char *linenoise(const char *prompt);
|
||||||
|
void linenoiseFree(void *ptr);
|
||||||
|
int linenoiseHistoryAdd(const char *line);
|
||||||
|
int linenoiseHistorySetMaxLen(int len);
|
||||||
|
int linenoiseHistorySave(const char *filename);
|
||||||
|
int linenoiseHistoryLoad(const char *filename);
|
||||||
|
void linenoiseClearScreen(void);
|
||||||
|
void linenoiseSetMultiLine(int ml);
|
||||||
|
void linenoisePrintKeyCodes(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LINENOISE_H */
|
|
@ -2,12 +2,8 @@ programs += nix
|
||||||
|
|
||||||
nix_DIR := $(d)
|
nix_DIR := $(d)
|
||||||
|
|
||||||
nix_SOURCES := $(wildcard $(d)/*.cc)
|
nix_SOURCES := $(wildcard $(d)/*.cc) src/linenoise/linenoise.c
|
||||||
|
|
||||||
nix_LIBS = libexpr libmain libstore libutil libformat
|
nix_LIBS = libexpr libmain libstore libutil libformat
|
||||||
|
|
||||||
ifeq ($(HAVE_READLINE), 1)
|
|
||||||
nix_LDFLAGS += -lreadline
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(eval $(call install-symlink, nix, $(bindir)/nix-hash))
|
$(eval $(call install-symlink, nix, $(bindir)/nix-hash))
|
||||||
|
|
171
src/nix/repl.cc
171
src/nix/repl.cc
|
@ -1,13 +1,8 @@
|
||||||
#if HAVE_LIBREADLINE
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
|
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
|
@ -18,6 +13,9 @@
|
||||||
#include "affinity.hh"
|
#include "affinity.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "finally.hh"
|
||||||
|
|
||||||
|
#include "src/linenoise/linenoise.h"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -44,14 +42,11 @@ struct NixRepl
|
||||||
|
|
||||||
const Path historyFile;
|
const Path historyFile;
|
||||||
|
|
||||||
StringSet completions;
|
|
||||||
StringSet::iterator curCompletion;
|
|
||||||
|
|
||||||
NixRepl(const Strings & searchPath, nix::ref<Store> store);
|
NixRepl(const Strings & searchPath, nix::ref<Store> store);
|
||||||
~NixRepl();
|
~NixRepl();
|
||||||
void mainLoop(const Strings & files);
|
void mainLoop(const Strings & files);
|
||||||
void completePrefix(string prefix);
|
StringSet completePrefix(string prefix);
|
||||||
bool getLine(string & input, const char * prompt);
|
bool getLine(string & input, const std::string &prompt);
|
||||||
Path getDerivationPath(Value & v);
|
Path getDerivationPath(Value & v);
|
||||||
bool processLine(string line);
|
bool processLine(string line);
|
||||||
void loadFile(const Path & path);
|
void loadFile(const Path & path);
|
||||||
|
@ -122,7 +117,17 @@ NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store)
|
||||||
|
|
||||||
NixRepl::~NixRepl()
|
NixRepl::~NixRepl()
|
||||||
{
|
{
|
||||||
write_history(historyFile.c_str());
|
linenoiseHistorySave(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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,22 +142,20 @@ void NixRepl::mainLoop(const Strings & files)
|
||||||
reloadFiles();
|
reloadFiles();
|
||||||
if (!loadedFiles.empty()) std::cout << std::endl;
|
if (!loadedFiles.empty()) std::cout << std::endl;
|
||||||
|
|
||||||
// Allow nix-repl specific settings in .inputrc
|
|
||||||
rl_readline_name = "nix-repl";
|
|
||||||
using_history();
|
|
||||||
createDirs(dirOf(historyFile));
|
createDirs(dirOf(historyFile));
|
||||||
read_history(historyFile.c_str());
|
linenoiseHistorySetMaxLen(1000);
|
||||||
|
linenoiseHistoryLoad(historyFile.c_str());
|
||||||
|
|
||||||
string input;
|
curRepl = this;
|
||||||
|
linenoiseSetCompletionCallback(completionCallback);
|
||||||
|
|
||||||
|
std::string input;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// When continuing input from previous lines, don't print a prompt, just align to the same
|
// When continuing input from previous lines, don't print a prompt, just align to the same
|
||||||
// number of chars as the prompt.
|
// number of chars as the prompt.
|
||||||
const char * prompt = input.empty() ? "nix-repl> " : " ";
|
if (!getLine(input, input.empty() ? "nix-repl> " : " "))
|
||||||
if (!getLine(input, prompt)) {
|
|
||||||
std::cout << std::endl;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!removeWhitespace(input).empty() && !processLine(input)) return;
|
if (!removeWhitespace(input).empty() && !processLine(input)) return;
|
||||||
|
@ -170,103 +173,57 @@ void NixRepl::mainLoop(const Strings & files)
|
||||||
printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
|
printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
|
||||||
}
|
}
|
||||||
|
|
||||||
// We handled the current input fully, so we should clear it and read brand new input.
|
// We handled the current input fully, so we should clear it
|
||||||
|
// and read brand new input.
|
||||||
|
linenoiseHistoryAdd(input.c_str());
|
||||||
input.clear();
|
input.clear();
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Apparently, the only way to get readline() to return on Ctrl-C
|
bool NixRepl::getLine(string & input, const std::string &prompt)
|
||||||
(SIGINT) is to use siglongjmp(). That's fucked up... */
|
|
||||||
static sigjmp_buf sigintJmpBuf;
|
|
||||||
|
|
||||||
|
|
||||||
static void sigintHandler(int signo)
|
|
||||||
{
|
{
|
||||||
siglongjmp(sigintJmpBuf, 1);
|
char * s = linenoise(prompt.c_str());
|
||||||
}
|
Finally doFree([&]() { linenoiseFree(s); });
|
||||||
|
if (!s) return false;
|
||||||
|
input += s;
|
||||||
/* 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 & input, const char * prompt)
|
|
||||||
{
|
|
||||||
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");
|
|
||||||
|
|
||||||
static sigset_t savedSignalMask, set;
|
|
||||||
sigemptyset(&set);
|
|
||||||
sigaddset(&set, SIGINT);
|
|
||||||
|
|
||||||
if (sigprocmask(SIG_UNBLOCK, &set, &savedSignalMask))
|
|
||||||
throw SysError("unblocking SIGINT");
|
|
||||||
|
|
||||||
if (sigsetjmp(sigintJmpBuf, 1)) {
|
|
||||||
input.clear();
|
|
||||||
} else {
|
|
||||||
curRepl = this;
|
|
||||||
rl_completion_entry_function = completerThunk;
|
|
||||||
|
|
||||||
char * s = readline(prompt);
|
|
||||||
if (!s) return false;
|
|
||||||
input.append(s);
|
|
||||||
input.push_back('\n');
|
|
||||||
if (!removeWhitespace(s).empty()) {
|
|
||||||
add_history(s);
|
|
||||||
append_history(1, 0);
|
|
||||||
}
|
|
||||||
free(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_isInterrupted = 0;
|
|
||||||
|
|
||||||
if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
|
|
||||||
throw SysError("restoring signals");
|
|
||||||
|
|
||||||
if (sigaction(SIGINT, &old, 0))
|
|
||||||
throw SysError("restoring handler for SIGINT");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NixRepl::completePrefix(string prefix)
|
StringSet NixRepl::completePrefix(string prefix)
|
||||||
{
|
{
|
||||||
completions.clear();
|
StringSet completions;
|
||||||
|
|
||||||
size_t dot = prefix.rfind('.');
|
size_t start = prefix.find_last_of(" \n\r\t(){}[]");
|
||||||
|
std::string prev, cur;
|
||||||
|
if (start == std::string::npos) {
|
||||||
|
prev = "";
|
||||||
|
cur = prefix;
|
||||||
|
} else {
|
||||||
|
prev = std::string(prefix, 0, start + 1);
|
||||||
|
cur = std::string(prefix, start + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (dot == string::npos) {
|
size_t slash, dot;
|
||||||
|
|
||||||
|
if ((slash = cur.rfind('/')) != string::npos) {
|
||||||
|
try {
|
||||||
|
auto dir = std::string(cur, 0, slash);
|
||||||
|
auto prefix2 = std::string(cur, slash + 1);
|
||||||
|
for (auto & entry : readDirectory(dir == "" ? "/" : dir)) {
|
||||||
|
if (entry.name[0] != '.' && hasPrefix(entry.name, prefix2))
|
||||||
|
completions.insert(prev + dir + "/" + entry.name);
|
||||||
|
}
|
||||||
|
} catch (Error &) {
|
||||||
|
}
|
||||||
|
} else if ((dot = cur.rfind('.')) == string::npos) {
|
||||||
/* This is a variable name; look it up in the current scope. */
|
/* This is a variable name; look it up in the current scope. */
|
||||||
StringSet::iterator i = varNames.lower_bound(prefix);
|
StringSet::iterator i = varNames.lower_bound(cur);
|
||||||
while (i != varNames.end()) {
|
while (i != varNames.end()) {
|
||||||
if (string(*i, 0, prefix.size()) != prefix) break;
|
if (string(*i, 0, cur.size()) != cur) break;
|
||||||
completions.insert(*i);
|
completions.insert(prev + *i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -274,8 +231,8 @@ void NixRepl::completePrefix(string prefix)
|
||||||
/* This is an expression that should evaluate to an
|
/* This is an expression that should evaluate to an
|
||||||
attribute set. Evaluate it to get the names of the
|
attribute set. Evaluate it to get the names of the
|
||||||
attributes. */
|
attributes. */
|
||||||
string expr(prefix, 0, dot);
|
string expr(cur, 0, dot);
|
||||||
string prefix2 = string(prefix, dot + 1);
|
string cur2 = string(cur, dot + 1);
|
||||||
|
|
||||||
Expr * e = parseString(expr);
|
Expr * e = parseString(expr);
|
||||||
Value v;
|
Value v;
|
||||||
|
@ -284,8 +241,8 @@ void NixRepl::completePrefix(string prefix)
|
||||||
|
|
||||||
for (auto & i : *v.attrs) {
|
for (auto & i : *v.attrs) {
|
||||||
string name = i.name;
|
string name = i.name;
|
||||||
if (string(name, 0, prefix2.size()) != prefix2) continue;
|
if (string(name, 0, cur2.size()) != cur2) continue;
|
||||||
completions.insert(expr + "." + name);
|
completions.insert(prev + expr + "." + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ParseError & e) {
|
} catch (ParseError & e) {
|
||||||
|
@ -296,6 +253,8 @@ void NixRepl::completePrefix(string prefix)
|
||||||
// Quietly ignore undefined variable errors.
|
// Quietly ignore undefined variable errors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return completions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -728,5 +687,3 @@ struct CmdRepl : StoreCommand
|
||||||
static RegisterCommand r1(make_ref<CmdRepl>());
|
static RegisterCommand r1(make_ref<CmdRepl>());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue