diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 078e2a2ce..65626e33f 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -132,6 +132,7 @@ struct InstallableCommand : virtual Args, SourceExprCommand InstallableCommand(bool supportReadOnlyMode = false); void prepare() override; + std::shared_ptr load(); std::optional getFlakeRefForCompletion() override { diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 635ce19b6..7d2ff0f68 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -1054,10 +1054,13 @@ InstallableCommand::InstallableCommand(bool supportReadOnlyMode) }} }); } +std::shared_ptr InstallableCommand::load() { + return parseInstallable(getStore(), _installable); +} void InstallableCommand::prepare() { - installable = parseInstallable(getStore(), _installable); + installable = load(); } } diff --git a/src/nix/repl.cc b/src/nix/repl.cc index d20eb0929..df921ef06 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -22,6 +22,7 @@ extern "C" { #include "ansicolor.hh" #include "shared.hh" #include "eval.hh" +#include "eval-cache.hh" #include "eval-inline.hh" #include "attr-path.hh" #include "store-api.hh" @@ -42,16 +43,20 @@ extern "C" { namespace nix { +typedef std::vector> Installables; + struct NixRepl #if HAVE_BOEHMGC : gc #endif { std::string curDir; - std::unique_ptr state; + ref state; Bindings * autoArgs; Strings loadedFiles; + typedef std::vector> AnnotatedValues; + std::function getValues; const static int envSize = 32768; StaticEnv staticEnv; @@ -61,13 +66,16 @@ struct NixRepl const Path historyFile; - NixRepl(const Strings & searchPath, nix::ref store); + NixRepl(const Strings & searchPath, nix::ref store,ref state, + std::function getValues); ~NixRepl(); - void mainLoop(const std::vector & files); + 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 loadInstallable(Installable & installable); void loadFile(const Path & path); void loadFlake(const std::string & flakeRef); void initEnv(); @@ -92,8 +100,10 @@ std::string removeWhitespace(std::string s) } -NixRepl::NixRepl(const Strings & searchPath, nix::ref store) - : state(std::make_unique(searchPath, store)) +NixRepl::NixRepl(const Strings & searchPath, nix::ref store,ref state, + std::function getValues) + : state(state) + , getValues(getValues) , staticEnv(false, &state->staticBaseEnv) , historyFile(getDataDir() + "/nix/repl-history") { @@ -198,16 +208,12 @@ namespace { } } -void NixRepl::mainLoop(const std::vector & files) +void NixRepl::mainLoop() { std::string error = ANSI_RED "error:" ANSI_NORMAL " "; notice("Welcome to Nix " + nixVersion + ". Type :? for help.\n"); - for (auto & i : files) - loadedFiles.push_back(i); - reloadFiles(); - if (!loadedFiles.empty()) notice(""); // Allow nix-repl specific settings in .inputrc rl_readline_name = "nix-repl"; @@ -630,6 +636,11 @@ bool NixRepl::processLine(std::string line) return true; } +void NixRepl::loadInstallable(Installable & installable) +{ + auto [val, pos] = installable.toValue(*state); + addAttrsToScope(*val); +} void NixRepl::loadFile(const Path & path) { @@ -646,11 +657,11 @@ void NixRepl::loadFlake(const std::string & flakeRefS) if (flakeRefS.empty()) throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); - auto [flakeRef, fragment] = parseFlakeRefWithFragment(flakeRefS, absPath("."), true); + auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true); if (evalSettings.pureEval && !flakeRef.input.isLocked()) throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS); - auto v = state->allocValue(); + Value v; flake::callFlake(*state, flake::lockFlake(*state, flakeRef, @@ -659,17 +670,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS) .useRegistries = !evalSettings.pureEval, .allowMutable = !evalSettings.pureEval, }), - *v); - - auto f = v->attrs->get(state->symbols.create(fragment)); - - if (f == 0) { - warn("no attribute %s, nothing loaded", fragment); - return; - }; - - fragment != "" ? addAttrsToScope(*f->value) : addAttrsToScope(*v); - + v); + addAttrsToScope(v); } @@ -693,15 +695,14 @@ void NixRepl::reloadFiles() Strings old = loadedFiles; loadedFiles.clear(); - bool first = true; for (auto & i : old) { - if (!first) notice(""); - first = false; notice("Loading '%1%'...", i); + loadFile(i); + } - settings.isExperimentalFeatureEnabled(Xp::Flakes) - ? loadFlake(i) - : loadFile(i); + for (auto & [i,what] : getValues()) { + notice("Loading Installable '%1%'...", what); + addAttrsToScope(*i); } } @@ -898,17 +899,20 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -struct CmdRepl : StoreCommand, MixEvalArgs +struct CmdRepl : InstallableCommand { std::vector files; + Strings getDefaultFlakeAttrPathPrefixes() + override { + return {}; + } + Strings getDefaultFlakeAttrPaths() + override { + return {""}; + } CmdRepl() { - expectArgs({ - .label = "files", - .handler = {&files}, - .completer = completePath - }); } std::string description() override @@ -925,10 +929,19 @@ struct CmdRepl : StoreCommand, MixEvalArgs void run(ref store) override { + evalSettings.pureEval = false; - auto repl = std::make_unique(searchPath, openStore()); + auto state = getEvalState(); + auto repl = std::make_unique(searchPath, openStore(),state + ,[&]()->NixRepl::AnnotatedValues{ + auto installable = load(); + auto [val, pos] = installable->toValue(*state); + auto what = installable->what(); + return { {val,what} }; + } + ); repl->autoArgs = getAutoArgs(*repl->state); - repl->mainLoop(files); + repl->mainLoop(); } };