diff --git a/src/libcmd/repl-interacter.cc b/src/libcmd/repl-interacter.cc index 3e34ecdb6ad..570201285af 100644 --- a/src/libcmd/repl-interacter.cc +++ b/src/libcmd/repl-interacter.cc @@ -1,4 +1,6 @@ #include +#include +#include #ifdef USE_READLINE #include @@ -183,4 +185,24 @@ ReadlineLikeInteracter::~ReadlineLikeInteracter() write_history(historyFile.c_str()); } +AutomationInteracter::Guard AutomationInteracter::init(detail::ReplCompleterMixin *) +{ + return Guard([] {}); +} + +// ASCII ENQ character +constexpr const char * automationPrompt = "\x05"; + +bool AutomationInteracter::getLine(std::string & input, ReplPromptType promptType) +{ + std::cout << std::unitbuf; + std::cout << automationPrompt; + if (!std::getline(std::cin, input)) { + // reset failure bits on EOF + std::cin.clear(); + return false; + } + return true; +} + }; diff --git a/src/libcmd/repl-interacter.hh b/src/libcmd/repl-interacter.hh index cc70efd0729..c31b1a1e669 100644 --- a/src/libcmd/repl-interacter.hh +++ b/src/libcmd/repl-interacter.hh @@ -45,4 +45,13 @@ public: virtual ~ReadlineLikeInteracter() override; }; +class AutomationInteracter : public virtual ReplInteracter +{ +public: + AutomationInteracter() = default; + virtual Guard init(detail::ReplCompleterMixin * repl) override; + virtual bool getLine(std::string & input, ReplPromptType promptType) override; + virtual ~AutomationInteracter() override = default; +}; + }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 229d77767c3..be45d693c9a 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -122,6 +122,12 @@ std::string removeWhitespace(std::string s) return s; } +static box_ptr makeInteractor() { + if (experimentalFeatureSettings.isEnabled(Xp::ReplAutomation)) + return make_box_ptr(); + else + return make_box_ptr(getDataDir() + "/nix/repl-history"); +} NixRepl::NixRepl(const SearchPath & searchPath, nix::ref store, ref state, std::function getValues) @@ -129,7 +135,7 @@ NixRepl::NixRepl(const SearchPath & searchPath, nix::ref store, refstaticBaseEnv.get())) - , interacter(make_box_ptr(getDataDir() + "/nix/repl-history")) + , interacter(makeInteractor()) { } diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 9b46fc5b00a..9e030280712 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -22,7 +22,7 @@ struct ExperimentalFeatureDetails * feature, we either have no issue at all if few features are not added * at the end of the list, or a proper merge conflict if they are. */ -constexpr size_t numXpFeatures = 1 + static_cast(Xp::VerifiedFetches); +constexpr size_t numXpFeatures = 1 + static_cast(Xp::ReplAutomation); constexpr std::array xpFeatureDetails = {{ { @@ -275,6 +275,13 @@ constexpr std::array xpFeatureDetails Enables verification of git commit signatures through the [`fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit) built-in. )", }, + { + .tag = Xp::ReplAutomation, + .name = "repl-automation", + .description = R"( + Makes the repl not use readline/editline, print ENQ (U+0005) when ready for a command, and take commands followed by newline. + )", + }, }}; static_assert( diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index eae4fa9b856..f3f7e4ace65 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -36,6 +36,7 @@ enum struct ExperimentalFeature ConfigurableImpureEnv, MountedSSHStore, VerifiedFetches, + ReplAutomation, }; /**