Split out CmdRepl
and editorFor
The REPL itself and the `nix repl` CLI are conceptually different things, and thus deserve to be in different files.
This commit is contained in:
parent
57a2e46ee0
commit
1bd03ad100
|
@ -4,6 +4,7 @@
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "nixexpr.hh"
|
#include "nixexpr.hh"
|
||||||
#include "profiles.hh"
|
#include "profiles.hh"
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ ref<EvalState> EvalCommand::getEvalState()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (startReplOnEvalErrors) {
|
if (startReplOnEvalErrors) {
|
||||||
evalState->debugRepl = &runRepl;
|
evalState->debugRepl = &AbstractNixRepl::runSimple;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return ref<EvalState>(evalState);
|
return ref<EvalState>(evalState);
|
||||||
|
@ -218,20 +219,6 @@ void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePath
|
||||||
run(store, *storePaths.begin());
|
run(store, *storePaths.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
Strings editorFor(const Path & file, uint32_t line)
|
|
||||||
{
|
|
||||||
auto editor = getEnv("EDITOR").value_or("cat");
|
|
||||||
auto args = tokenizeString<Strings>(editor);
|
|
||||||
if (line > 0 && (
|
|
||||||
editor.find("emacs") != std::string::npos ||
|
|
||||||
editor.find("nano") != std::string::npos ||
|
|
||||||
editor.find("vim") != std::string::npos ||
|
|
||||||
editor.find("kak") != std::string::npos))
|
|
||||||
args.push_back(fmt("+%d", line));
|
|
||||||
args.push_back(file);
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
MixProfile::MixProfile()
|
MixProfile::MixProfile()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
|
|
|
@ -231,10 +231,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
|
||||||
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function to generate args that invoke $EDITOR on
|
|
||||||
filename:lineno. */
|
|
||||||
Strings editorFor(const Path & file, uint32_t line);
|
|
||||||
|
|
||||||
struct MixProfile : virtual StoreCommand
|
struct MixProfile : virtual StoreCommand
|
||||||
{
|
{
|
||||||
std::optional<Path> profile;
|
std::optional<Path> profile;
|
||||||
|
@ -284,8 +280,4 @@ void printClosureDiff(
|
||||||
const StorePath & afterPath,
|
const StorePath & afterPath,
|
||||||
std::string_view indent);
|
std::string_view indent);
|
||||||
|
|
||||||
|
|
||||||
void runRepl(
|
|
||||||
ref<EvalState> evalState,
|
|
||||||
const ValMap & extraEnv);
|
|
||||||
}
|
}
|
||||||
|
|
20
src/libcmd/editor-for.cc
Normal file
20
src/libcmd/editor-for.cc
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "util.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
Strings editorFor(const Path & file, uint32_t line)
|
||||||
|
{
|
||||||
|
auto editor = getEnv("EDITOR").value_or("cat");
|
||||||
|
auto args = tokenizeString<Strings>(editor);
|
||||||
|
if (line > 0 && (
|
||||||
|
editor.find("emacs") != std::string::npos ||
|
||||||
|
editor.find("nano") != std::string::npos ||
|
||||||
|
editor.find("vim") != std::string::npos ||
|
||||||
|
editor.find("kak") != std::string::npos))
|
||||||
|
args.push_back(fmt("+%d", line));
|
||||||
|
args.push_back(file);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/libcmd/editor-for.hh
Normal file
11
src/libcmd/editor-for.hh
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/* Helper function to generate args that invoke $EDITOR on
|
||||||
|
filename:lineno. */
|
||||||
|
Strings editorFor(const Path & file, uint32_t line);
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ libcmd_DIR := $(d)
|
||||||
|
|
||||||
libcmd_SOURCES := $(wildcard $(d)/*.cc)
|
libcmd_SOURCES := $(wildcard $(d)/*.cc)
|
||||||
|
|
||||||
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix
|
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers
|
||||||
|
|
||||||
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
|
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ extern "C" {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
#include "ansicolor.hh"
|
#include "ansicolor.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
|
@ -31,7 +33,9 @@ extern "C" {
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
#include "derivations.hh"
|
#include "derivations.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "command.hh"
|
#include "flake/flake.hh"
|
||||||
|
#include "flake/lockfile.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
#include "finally.hh"
|
#include "finally.hh"
|
||||||
#include "markdown.hh"
|
#include "markdown.hh"
|
||||||
#include "local-fs-store.hh"
|
#include "local-fs-store.hh"
|
||||||
|
@ -45,18 +49,16 @@ extern "C" {
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct NixRepl
|
struct NixRepl
|
||||||
|
: AbstractNixRepl,
|
||||||
#if HAVE_BOEHMGC
|
#if HAVE_BOEHMGC
|
||||||
: gc
|
gc
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
std::string curDir;
|
std::string curDir;
|
||||||
ref<EvalState> state;
|
|
||||||
Bindings * autoArgs;
|
|
||||||
|
|
||||||
size_t debugTraceIndex;
|
size_t debugTraceIndex;
|
||||||
|
|
||||||
Strings loadedFiles;
|
Strings loadedFiles;
|
||||||
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
|
||||||
std::function<AnnotatedValues()> getValues;
|
std::function<AnnotatedValues()> getValues;
|
||||||
|
|
||||||
const static int envSize = 32768;
|
const static int envSize = 32768;
|
||||||
|
@ -69,8 +71,11 @@ struct NixRepl
|
||||||
|
|
||||||
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
|
||||||
std::function<AnnotatedValues()> getValues);
|
std::function<AnnotatedValues()> getValues);
|
||||||
~NixRepl();
|
virtual ~NixRepl();
|
||||||
void mainLoop();
|
|
||||||
|
void mainLoop() override;
|
||||||
|
void initEnv() override;
|
||||||
|
|
||||||
StringSet completePrefix(const std::string & prefix);
|
StringSet completePrefix(const std::string & prefix);
|
||||||
bool getLine(std::string & input, const std::string & prompt);
|
bool getLine(std::string & input, const std::string & prompt);
|
||||||
StorePath getDerivationPath(Value & v);
|
StorePath getDerivationPath(Value & v);
|
||||||
|
@ -78,7 +83,6 @@ struct NixRepl
|
||||||
|
|
||||||
void loadFile(const Path & path);
|
void loadFile(const Path & path);
|
||||||
void loadFlake(const std::string & flakeRef);
|
void loadFlake(const std::string & flakeRef);
|
||||||
void initEnv();
|
|
||||||
void loadFiles();
|
void loadFiles();
|
||||||
void reloadFiles();
|
void reloadFiles();
|
||||||
void addAttrsToScope(Value & attrs);
|
void addAttrsToScope(Value & attrs);
|
||||||
|
@ -92,7 +96,6 @@ struct NixRepl
|
||||||
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
|
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
std::string removeWhitespace(std::string s)
|
std::string removeWhitespace(std::string s)
|
||||||
{
|
{
|
||||||
s = chomp(s);
|
s = chomp(s);
|
||||||
|
@ -104,7 +107,7 @@ std::string removeWhitespace(std::string s)
|
||||||
|
|
||||||
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
std::function<NixRepl::AnnotatedValues()> getValues)
|
std::function<NixRepl::AnnotatedValues()> getValues)
|
||||||
: state(state)
|
: AbstractNixRepl(state)
|
||||||
, debugTraceIndex(0)
|
, debugTraceIndex(0)
|
||||||
, getValues(getValues)
|
, getValues(getValues)
|
||||||
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
|
||||||
|
@ -1029,8 +1032,22 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void runRepl(
|
|
||||||
ref<EvalState>evalState,
|
std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
|
||||||
|
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
|
std::function<AnnotatedValues()> getValues)
|
||||||
|
{
|
||||||
|
return std::make_unique<NixRepl>(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
state,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AbstractNixRepl::runSimple(
|
||||||
|
ref<EvalState> evalState,
|
||||||
const ValMap & extraEnv)
|
const ValMap & extraEnv)
|
||||||
{
|
{
|
||||||
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
||||||
|
@ -1054,91 +1071,4 @@ void runRepl(
|
||||||
repl->mainLoop();
|
repl->mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmdRepl : InstallablesCommand
|
|
||||||
{
|
|
||||||
CmdRepl() {
|
|
||||||
evalSettings.pureEval = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prepare() override
|
|
||||||
{
|
|
||||||
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
|
||||||
warn("future versions of Nix will require using `--file` to load a file");
|
|
||||||
if (this->_installables.size() > 1)
|
|
||||||
warn("more than one input file is not currently supported");
|
|
||||||
auto filePath = this->_installables[0].data();
|
|
||||||
file = std::optional(filePath);
|
|
||||||
_installables.front() = _installables.back();
|
|
||||||
_installables.pop_back();
|
|
||||||
}
|
|
||||||
installables = InstallablesCommand::load();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> files;
|
|
||||||
|
|
||||||
Strings getDefaultFlakeAttrPaths() override
|
|
||||||
{
|
|
||||||
return {""};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool useDefaultInstallables() override
|
|
||||||
{
|
|
||||||
return file.has_value() or expr.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool forceImpureByDefault() override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string description() override
|
|
||||||
{
|
|
||||||
return "start an interactive environment for evaluating Nix expressions";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string doc() override
|
|
||||||
{
|
|
||||||
return
|
|
||||||
#include "repl.md"
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run(ref<Store> store) override
|
|
||||||
{
|
|
||||||
auto state = getEvalState();
|
|
||||||
auto getValues = [&]()->NixRepl::AnnotatedValues{
|
|
||||||
auto installables = load();
|
|
||||||
NixRepl::AnnotatedValues values;
|
|
||||||
for (auto & installable: installables){
|
|
||||||
auto what = installable->what();
|
|
||||||
if (file){
|
|
||||||
auto [val, pos] = installable->toValue(*state);
|
|
||||||
auto what = installable->what();
|
|
||||||
state->forceValue(*val, pos);
|
|
||||||
auto autoArgs = getAutoArgs(*state);
|
|
||||||
auto valPost = state->allocValue();
|
|
||||||
state->autoCallFunction(*autoArgs, *val, *valPost);
|
|
||||||
state->forceValue(*valPost, pos);
|
|
||||||
values.push_back( {valPost, what });
|
|
||||||
} else {
|
|
||||||
auto [val, pos] = installable->toValue(*state);
|
|
||||||
values.push_back( {val, what} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
};
|
|
||||||
auto repl = std::make_unique<NixRepl>(
|
|
||||||
searchPath,
|
|
||||||
openStore(),
|
|
||||||
state,
|
|
||||||
getValues
|
|
||||||
);
|
|
||||||
repl->autoArgs = getAutoArgs(*repl->state);
|
|
||||||
repl->initEnv();
|
|
||||||
repl->mainLoop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static auto rCmdRepl = registerCommand<CmdRepl>("repl");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
39
src/libcmd/repl.hh
Normal file
39
src/libcmd/repl.hh
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "eval.hh"
|
||||||
|
|
||||||
|
#if HAVE_BOEHMGC
|
||||||
|
#define GC_INCLUDE_NEW
|
||||||
|
#include <gc/gc_cpp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct AbstractNixRepl
|
||||||
|
{
|
||||||
|
ref<EvalState> state;
|
||||||
|
Bindings * autoArgs;
|
||||||
|
|
||||||
|
AbstractNixRepl(ref<EvalState> state)
|
||||||
|
: state(state)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual ~AbstractNixRepl()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
|
||||||
|
|
||||||
|
static std::unique_ptr<AbstractNixRepl> create(
|
||||||
|
const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
|
||||||
|
std::function<AnnotatedValues()> getValues);
|
||||||
|
|
||||||
|
static void runSimple(
|
||||||
|
ref<EvalState> evalState,
|
||||||
|
const ValMap & extraEnv);
|
||||||
|
|
||||||
|
virtual void initEnv() = 0;
|
||||||
|
|
||||||
|
virtual void mainLoop() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
|
#include "editor-for.hh"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
95
src/nix/repl.cc
Normal file
95
src/nix/repl.cc
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "command.hh"
|
||||||
|
#include "repl.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct CmdRepl : InstallablesCommand
|
||||||
|
{
|
||||||
|
CmdRepl() {
|
||||||
|
evalSettings.pureEval = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare() override
|
||||||
|
{
|
||||||
|
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
|
||||||
|
warn("future versions of Nix will require using `--file` to load a file");
|
||||||
|
if (this->_installables.size() > 1)
|
||||||
|
warn("more than one input file is not currently supported");
|
||||||
|
auto filePath = this->_installables[0].data();
|
||||||
|
file = std::optional(filePath);
|
||||||
|
_installables.front() = _installables.back();
|
||||||
|
_installables.pop_back();
|
||||||
|
}
|
||||||
|
installables = InstallablesCommand::load();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
Strings getDefaultFlakeAttrPaths() override
|
||||||
|
{
|
||||||
|
return {""};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool useDefaultInstallables() override
|
||||||
|
{
|
||||||
|
return file.has_value() or expr.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool forceImpureByDefault() override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return "start an interactive environment for evaluating Nix expressions";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string doc() override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
#include "repl.md"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(ref<Store> store) override
|
||||||
|
{
|
||||||
|
auto state = getEvalState();
|
||||||
|
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
|
||||||
|
auto installables = load();
|
||||||
|
AbstractNixRepl::AnnotatedValues values;
|
||||||
|
for (auto & installable: installables){
|
||||||
|
auto what = installable->what();
|
||||||
|
if (file){
|
||||||
|
auto [val, pos] = installable->toValue(*state);
|
||||||
|
auto what = installable->what();
|
||||||
|
state->forceValue(*val, pos);
|
||||||
|
auto autoArgs = getAutoArgs(*state);
|
||||||
|
auto valPost = state->allocValue();
|
||||||
|
state->autoCallFunction(*autoArgs, *val, *valPost);
|
||||||
|
state->forceValue(*valPost, pos);
|
||||||
|
values.push_back( {valPost, what });
|
||||||
|
} else {
|
||||||
|
auto [val, pos] = installable->toValue(*state);
|
||||||
|
values.push_back( {val, what} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
};
|
||||||
|
auto repl = AbstractNixRepl::create(
|
||||||
|
searchPath,
|
||||||
|
openStore(),
|
||||||
|
state,
|
||||||
|
getValues
|
||||||
|
);
|
||||||
|
repl->autoArgs = getAutoArgs(*repl->state);
|
||||||
|
repl->initEnv();
|
||||||
|
repl->mainLoop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto rCmdRepl = registerCommand<CmdRepl>("repl");
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue