Skip to content

Commit

Permalink
Split out CmdRepl and editorFor
Browse files Browse the repository at this point in the history
The REPL itself and the `nix repl` CLI are conceptually different
things, and thus deserve to be in different files.
  • Loading branch information
Ericson2314 committed Feb 20, 2023
1 parent 57a2e46 commit 1bd03ad
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 123 deletions.
17 changes: 2 additions & 15 deletions src/libcmd/command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "derivations.hh"
#include "nixexpr.hh"
#include "profiles.hh"
#include "repl.hh"

#include <nlohmann/json.hpp>

Expand Down Expand Up @@ -121,7 +122,7 @@ ref<EvalState> EvalCommand::getEvalState()
;

if (startReplOnEvalErrors) {
evalState->debugRepl = &runRepl;
evalState->debugRepl = &AbstractNixRepl::runSimple;
};
}
return ref<EvalState>(evalState);
Expand Down Expand Up @@ -218,20 +219,6 @@ void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePath
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()
{
addFlag({
Expand Down
8 changes: 0 additions & 8 deletions src/libcmd/command.hh
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
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
{
std::optional<Path> profile;
Expand Down Expand Up @@ -284,8 +280,4 @@ void printClosureDiff(
const StorePath & afterPath,
std::string_view indent);


void runRepl(
ref<EvalState> evalState,
const ValMap & extraEnv);
}
20 changes: 20 additions & 0 deletions src/libcmd/editor-for.cc
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/libcmd/editor-for.hh
Original file line number Diff line number Diff line change
@@ -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);

}
2 changes: 1 addition & 1 deletion src/libcmd/local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
128 changes: 29 additions & 99 deletions src/libcmd/repl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ extern "C" {
}
#endif

#include "repl.hh"

#include "ansicolor.hh"
#include "shared.hh"
#include "eval.hh"
Expand All @@ -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"
Expand All @@ -45,18 +49,16 @@ extern "C" {
namespace nix {

struct NixRepl
: AbstractNixRepl,
#if HAVE_BOEHMGC
: gc
gc
#endif
{
std::string curDir;
ref<EvalState> state;
Bindings * autoArgs;

size_t debugTraceIndex;

Strings loadedFiles;
typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
std::function<AnnotatedValues()> getValues;

const static int envSize = 32768;
Expand All @@ -69,16 +71,18 @@ struct NixRepl

NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
std::function<AnnotatedValues()> getValues);
~NixRepl();
void mainLoop();
virtual ~NixRepl();

void mainLoop() override;
void initEnv() override;

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);
Expand All @@ -92,7 +96,6 @@ struct NixRepl
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
};


std::string removeWhitespace(std::string s)
{
s = chomp(s);
Expand All @@ -104,7 +107,7 @@ std::string removeWhitespace(std::string s)

NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
std::function<NixRepl::AnnotatedValues()> getValues)
: state(state)
: AbstractNixRepl(state)
, debugTraceIndex(0)
, getValues(getValues)
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
Expand Down Expand Up @@ -1029,8 +1032,22 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
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)
{
auto getValues = [&]()->NixRepl::AnnotatedValues{
Expand All @@ -1054,91 +1071,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<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 changes: 39 additions & 0 deletions src/libcmd/repl.hh
Original file line number Diff line number Diff line change
@@ -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;
};

}
1 change: 1 addition & 0 deletions src/nix/edit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "eval.hh"
#include "attr-path.hh"
#include "progress-bar.hh"
#include "editor-for.hh"

#include <unistd.h>

Expand Down
Loading

0 comments on commit 1bd03ad

Please sign in to comment.