From 7a85980445a411be0b4f8be43637e3ce0d1c5924 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 3 Feb 2023 22:42:36 -0500 Subject: [PATCH] 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. --- src/libcmd/command.cc | 17 +---- src/libcmd/command.hh | 8 --- src/libcmd/editor-for.cc | 20 ++++++ src/libcmd/editor-for.hh | 11 +++ src/libcmd/local.mk | 2 +- src/libcmd/repl.cc | 146 ++------------------------------------- src/libcmd/repl.hh | 83 ++++++++++++++++++++++ src/nix/edit.cc | 1 + src/nix/repl.cc | 95 +++++++++++++++++++++++++ 9 files changed, 220 insertions(+), 163 deletions(-) create mode 100644 src/libcmd/editor-for.cc create mode 100644 src/libcmd/editor-for.hh create mode 100644 src/libcmd/repl.hh create mode 100644 src/nix/repl.cc diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 0740ea96077a..de80a9958d8a 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -4,6 +4,7 @@ #include "derivations.hh" #include "nixexpr.hh" #include "profiles.hh" +#include "repl.hh" #include @@ -121,7 +122,7 @@ ref EvalCommand::getEvalState() ; if (startReplOnEvalErrors) { - evalState->debugRepl = &runRepl; + evalState->debugRepl = &NixRepl::runSimple; }; } return ref(evalState); @@ -208,20 +209,6 @@ void StorePathCommand::run(ref store, std::vector && storePath run(store, *storePaths.begin()); } -Strings editorFor(const Path & file, uint32_t line) -{ - auto editor = getEnv("EDITOR").value_or("cat"); - auto args = tokenizeString(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() { addFlag({ diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 3b4b40981def..e9087f1b87a2 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -227,10 +227,6 @@ static RegisterCommand registerCommand2(std::vector && name) return RegisterCommand(std::move(name), [](){ return make_ref(); }); } -/* Helper function to generate args that invoke $EDITOR on - filename:lineno. */ -Strings editorFor(const Path & file, uint32_t line); - struct MixProfile : virtual StoreCommand { std::optional profile; @@ -280,8 +276,4 @@ void printClosureDiff( const StorePath & afterPath, std::string_view indent); - -void runRepl( - ref evalState, - const ValMap & extraEnv); } diff --git a/src/libcmd/editor-for.cc b/src/libcmd/editor-for.cc new file mode 100644 index 000000000000..f674f32bd30f --- /dev/null +++ b/src/libcmd/editor-for.cc @@ -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(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; +} + +} diff --git a/src/libcmd/editor-for.hh b/src/libcmd/editor-for.hh new file mode 100644 index 000000000000..8fbd08792a9d --- /dev/null +++ b/src/libcmd/editor-for.hh @@ -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); + +} diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index 152bc388dacf..541a7d2bac71 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -6,7 +6,7 @@ libcmd_DIR := $(d) 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 diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 4158439b6524..39053c6fcd36 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -19,6 +19,8 @@ extern "C" { } #endif +#include "repl.hh" + #include "ansicolor.hh" #include "shared.hh" #include "eval.hh" @@ -31,7 +33,9 @@ extern "C" { #include "get-drvs.hh" #include "derivations.hh" #include "globals.hh" -#include "command.hh" +#include "flake/flake.hh" +#include "flake/lockfile.hh" +#include "editor-for.hh" #include "finally.hh" #include "markdown.hh" #include "local-fs-store.hh" @@ -44,55 +48,6 @@ extern "C" { namespace nix { -struct NixRepl - #if HAVE_BOEHMGC - : gc - #endif -{ - std::string curDir; - ref state; - Bindings * autoArgs; - - size_t debugTraceIndex; - - Strings loadedFiles; - typedef std::vector> AnnotatedValues; - std::function getValues; - - const static int envSize = 32768; - std::shared_ptr staticEnv; - Env * env; - int displ; - StringSet varNames; - - const Path historyFile; - - NixRepl(const Strings & searchPath, nix::ref store,ref state, - std::function getValues); - ~NixRepl(); - void mainLoop(); - StringSet completePrefix(const std::string & prefix); - bool getLine(std::string & input, const std::string & prompt); - StorePath getDerivationPath(Value & v); - bool processLine(std::string line); - - void loadFile(const Path & path); - void loadFlake(const std::string & flakeRef); - void initEnv(); - void loadFiles(); - void reloadFiles(); - void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol name, Value & v); - Expr * parseString(std::string s); - void evalString(std::string s, Value & v); - void loadDebugTraceEnv(DebugTrace & dt); - - typedef std::set ValuesSeen; - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); - std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); -}; - - std::string removeWhitespace(std::string s) { s = chomp(s); @@ -1029,8 +984,8 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -void runRepl( - refevalState, +void NixRepl::runSimple( + ref evalState, const ValMap & extraEnv) { auto getValues = [&]()->NixRepl::AnnotatedValues{ @@ -1054,91 +1009,4 @@ void runRepl( 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 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) 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( - searchPath, - openStore(), - state, - getValues - ); - repl->autoArgs = getAutoArgs(*repl->state); - repl->initEnv(); - repl->mainLoop(); - } -}; - -static auto rCmdRepl = registerCommand("repl"); - } diff --git a/src/libcmd/repl.hh b/src/libcmd/repl.hh new file mode 100644 index 000000000000..51b2e9c204a6 --- /dev/null +++ b/src/libcmd/repl.hh @@ -0,0 +1,83 @@ +#pragma once + +#include "eval.hh" + +#if HAVE_BOEHMGC +#define GC_INCLUDE_NEW +#include +#endif + +namespace nix { + +class NixRepl + #if HAVE_BOEHMGC + : public gc + #endif +{ + std::string curDir; + +public: + + ref state; + Bindings * autoArgs; + +private: + + size_t debugTraceIndex; + + Strings loadedFiles; + +public: + + typedef std::vector> AnnotatedValues; + +private: + + std::function getValues; + + const static int envSize = 32768; + std::shared_ptr staticEnv; + Env * env; + int displ; + StringSet varNames; + + const Path historyFile; + +public: + + NixRepl(const Strings & searchPath, nix::ref store, ref state, + std::function getValues); + ~NixRepl(); + + static void runSimple( + ref evalState, + const ValMap & extraEnv); + + void initEnv(); + + void mainLoop(); + + StringSet completePrefix(const std::string & prefix); + +private: + + bool getLine(std::string & input, const std::string & prompt); + StorePath getDerivationPath(Value & v); + bool processLine(std::string line); + + void loadFile(const Path & path); + void loadFlake(const std::string & flakeRef); + void loadFiles(); + void reloadFiles(); + void addAttrsToScope(Value & attrs); + void addVarToScope(const Symbol name, Value & v); + Expr * parseString(std::string s); + void evalString(std::string s, Value & v); + void loadDebugTraceEnv(DebugTrace & dt); + + typedef std::set ValuesSeen; + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); +}; + +} diff --git a/src/nix/edit.cc b/src/nix/edit.cc index 76a134b1f67c..dfe75fbdf92d 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -3,6 +3,7 @@ #include "eval.hh" #include "attr-path.hh" #include "progress-bar.hh" +#include "editor-for.hh" #include diff --git a/src/nix/repl.cc b/src/nix/repl.cc new file mode 100644 index 000000000000..872f5144bb62 --- /dev/null +++ b/src/nix/repl.cc @@ -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 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) 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( + searchPath, + openStore(), + state, + getValues + ); + repl->autoArgs = getAutoArgs(*repl->state); + repl->initEnv(); + repl->mainLoop(); + } +}; + +static auto rCmdRepl = registerCommand("repl"); + +}