-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Nix repl flakes #6233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nix repl flakes #6233
Changes from 15 commits
06d57ce
81567a0
5640b52
1ca3f60
9f8c118
7534798
e1f308a
f21dec5
7d7e002
db613a8
542e36c
82c4af4
9381504
0053dab
7a04fb1
8c3939a
ffd41d1
dae4a8a
51268ce
f801d70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -132,6 +132,8 @@ struct Installable | |||||
| const std::vector<std::shared_ptr<Installable>> & installables); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
and there are probably more places that can use the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I started to make this change, but the compiler was not happy with how I was doing it... we can leave this to another PR? or during hacking session? |
||||||
| }; | ||||||
|
|
||||||
| typedef std::vector<std::shared_ptr<Installable>> Installables; | ||||||
|
tomberek marked this conversation as resolved.
|
||||||
|
|
||||||
| struct InstallableValue : Installable | ||||||
| { | ||||||
| ref<EvalState> state; | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ enum struct ExperimentalFeature | |
| RecursiveNix, | ||
| NoUrlLiterals, | ||
| FetchClosure, | ||
| ReplFlake, | ||
| }; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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" | ||
|
|
@@ -48,10 +49,12 @@ struct NixRepl | |
| #endif | ||
| { | ||
| std::string curDir; | ||
| std::unique_ptr<EvalState> state; | ||
| ref<EvalState> state; | ||
| Bindings * autoArgs; | ||
|
|
||
| Strings loadedFiles; | ||
| typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues; | ||
| std::function<AnnotatedValues()> getValues; | ||
|
|
||
| const static int envSize = 32768; | ||
| StaticEnv staticEnv; | ||
|
|
@@ -61,13 +64,15 @@ struct NixRepl | |
|
|
||
| const Path historyFile; | ||
|
|
||
| NixRepl(const Strings & searchPath, nix::ref<Store> store); | ||
| NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state, | ||
| std::function<AnnotatedValues()> getValues); | ||
| ~NixRepl(); | ||
| void mainLoop(const std::vector<std::string> & 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 loadFile(const Path & path); | ||
| void loadFlake(const std::string & flakeRef); | ||
| void initEnv(); | ||
|
|
@@ -92,8 +97,10 @@ std::string removeWhitespace(std::string s) | |
| } | ||
|
|
||
|
|
||
| NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store) | ||
| : state(std::make_unique<EvalState>(searchPath, store)) | ||
| NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state, | ||
| std::function<NixRepl::AnnotatedValues()> getValues) | ||
| : state(state) | ||
| , getValues(getValues) | ||
| , staticEnv(false, &state->staticBaseEnv) | ||
| , historyFile(getDataDir() + "/nix/repl-history") | ||
| { | ||
|
|
@@ -198,16 +205,12 @@ namespace { | |
| } | ||
| } | ||
|
|
||
| void NixRepl::mainLoop(const std::vector<std::string> & 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,7 +633,6 @@ bool NixRepl::processLine(std::string line) | |
| return true; | ||
| } | ||
|
|
||
|
|
||
| void NixRepl::loadFile(const Path & path) | ||
| { | ||
| loadedFiles.remove(path); | ||
|
|
@@ -684,13 +686,15 @@ 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); | ||
| } | ||
|
|
||
| for (auto & [i, what] : getValues()) { | ||
| notice("Loading installable '%1%'...", what); | ||
| addAttrsToScope(*i); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this effectively merges the attributes of multiple installables? I don't like that "loadables" are loaded into the global scope anyway. It makes discovering which attributes exist harder than it should. Perhaps flakes and installables could be put in a binding that's derived from the installable name? Also interesting
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only problem with this is that flakes don't have an obvious name, so it's not entirely straightforward what the top-level attribute name (e.g.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. I pulled Maybe the attribute name should be provided by the user. or Adding a bare flake or installable to the top-level scope seems ok-ish as long as there's only one. Or maybe it should default to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do have the previous behavior of multiple I wouldn't mind if it just made an array called |
||
| } | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -886,17 +890,32 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m | |
| return str; | ||
| } | ||
|
|
||
| struct CmdRepl : StoreCommand, MixEvalArgs | ||
| struct CmdRepl : InstallablesCommand | ||
| { | ||
| CmdRepl(){ | ||
| evalSettings.pureEval = false; | ||
| } | ||
| void prepare() | ||
| { | ||
| 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; | ||
|
|
||
| CmdRepl() | ||
| Strings getDefaultFlakeAttrPaths() override | ||
| { | ||
| expectArgs({ | ||
| .label = "files", | ||
| .handler = {&files}, | ||
| .completer = completePath | ||
| }); | ||
| return {""}; | ||
| } | ||
| virtual bool useDefaultInstallables() override | ||
| { | ||
| return file.has_value() or expr.has_value(); | ||
| } | ||
|
|
||
| std::string description() override | ||
|
|
@@ -913,10 +932,36 @@ struct CmdRepl : StoreCommand, MixEvalArgs | |
|
|
||
| void run(ref<Store> store) override | ||
| { | ||
| evalSettings.pureEval = false; | ||
| auto repl = std::make_unique<NixRepl>(searchPath, openStore()); | ||
| 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->mainLoop(files); | ||
| repl->mainLoop(); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.